WPF: Embedding DLR Scripts in XAML (Python, Ruby) - Part 4, A DLR Command

A Visual Studio 2008 Solution with the complete code listing for this series is attached to the final part.

GUIs are all about layout, style and wiring. WPF has the first two in spades; XAML is an excellent language for doing layout and styling of WPF GUI elements. However, sorely lacking in WFP is the ability to route commands and events in dynamically loaded XAML. This makes any attempt to build truly dynamic XAML based GUIs near on impossible as at some point an event is going to need handling or a command issued.

Continuing the series on embedding DLR scripting in XAML, here I demonstrate how to implement a scripted WPF Command, making dynamically loaded XAML one step closer to being a first class citizen in the WPF world.

A WPF Command is a class that implements the ICommand interface. Below is a WPF Command that delegates it's execution to a DLR script. The class uses many of the concepts of that were introduced in Part 2. The parameter passed into the Execute method is passed to the Script and so is available to the script when it executes.

  1. public class ScriptCommand : System.Windows.Input.ICommand
  2. {
  3. public string Script{ get; set; }
  4. public string Language{ get; set; }
  6. public bool CanExecute(object parameter)
  7. {
  8. return true;
  9. }
  11. public event System.EventHandler CanExecuteChanged;
  13. public void Execute(object parameter)
  14. {
  15. Dictionary<string, object> scopeVars = new Dictionary<string, object>();
  16. scopeVars["parameter"] = parameter;
  17. DlrUtils.Execute(Language, Script, scopeVars);
  18. }
  19. }

The CanExecute property and event are essentially unsupported by the above class. At this point I am unsure of the best way to deal with the CanExecuteChanged event - how and when would the script fire it? This limits the usefulness of this class, but it is useful in circumstances when the CanExecute logic is not required.

The following is an example use of the ScriptCommand. A Button is used to increment an integer stored in the Text property of a TextBlock. The increment is performed by a Python script:

  1. <Button Content="Increment" CommandParameter="{Binding ElementName=TheCommandTarget}">
  2. <Button.Command>
  3. <local:ScriptCommand Language="Python">
  4. <local:ScriptCommand.Script>
  5. parameter.Text = str( int(parameter.Text) + 1 )
  6. </local:ScriptCommand.Script>
  7. </local:ScriptCommand>
  8. </Button.Command>
  9. </Button>
  10. <TextBlock Name="TheCommandTarget">0</TextBlock>

The ScriptCommand allows dynamically loaded XAML to include scripts that process commands, making it one step closer to having all the features of its compiled brethren.