Triggering Commands from the ViewModel in WPF with MVVM - wpf

I have created a few Custom Controls (NOT UserControls) with bind-able "ClearCommand" ICommand dependency properties. This property will do exactly what it sounds: it will clear all the values from the control (textboxes, etc). I also bind (some) of those same properties to the VM I describe below.
Now I'm stuck trying to trigger the ClearCommand in those controls in the following MVVM scenario:
I've added a few such controls into my View. The View also includes a "Save" button that binds to my ViewModel's SaveCommand DelegateCommand property.
What I need to happen is that, upon a successful save, the VM should trigger the ClearCommand on those controls found in the View.
UPDATE
I've added code examples below. I have a few controls that resemble the ExampleCustomControl. Also, just to note, I am open to restructuring some of this if it's completely off.
Example Control snippet:
public class ExampleCustomControl : Control {
public string SearchTextBox { get; set; }
public IEnumerable<CustomObject> ResultList { get; set; }
public ExampleCustomControl() {
ClearCommand = new DelegateCommand(Clear);
}
/// <summary>
/// Dependency Property for Datagrid ItemSource.
/// </summary>
public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem",
typeof(CustomObject), typeof(ExampleCustomControl), new PropertyMetadata(default(CustomObject)));
public CustomObject SelectedItem {
get { return (CustomObject)GetValue(SelectedCustomObjectProperty); }
set { SetValue(SelectedCustomObjectProperty, value); }
}
public static DependencyProperty ClearCommandProperty = DependencyProperty.Register("ClearCommand", typeof(ICommand),
typeof(ExampleCustomControl), new PropertyMetadata(default(ICommand)));
/// <summary>
/// Dependency Property for resetting the control
/// </summary>
[Description("The command that clears the control"), Category("Common Properties")]
public ICommand ClearCommand {
get { return (ICommand)GetValue(ClearCommandProperty); }
set { SetValue(ClearCommandProperty, value); }
}
public void Clear(object o) {
SearchTextBox = string.Empty;
SelectedItem = null;
ResultList = null;
}
}
Example View snippet:
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<control:ExampleCustomControl Grid.Row="0"
SelectedItem="{Binding Selection, UpdateSourceTrigger=PropertyChanged}" />
<Button Grid.Row="1" x:Name="ResetButton" Command="{Binding SaveCommand}">
Save
</Button>
</Grid>
Example ViewModel:
public class TestViewModel : WorkspaceTask {
public TestViewModel() {
View = new TestView { Model = this };
SaveCommand = new DelegateCommand(Save);
}
private CustomObject _selection;
public CustomObject Selection {
get { return _selection; }
set {
_selection = value;
OnPropertyChanged("Selection");
}
}
public DelegateCommand SaveCommand { get; private set; }
private void Save(object o) {
// perform save
// clear controls
}
}

As others have said the VM shouldn't know about the view directly in MVVM so it doesn't make sense really that the VM triggers something on your custom control to clear everything.
I would have set the DataContext of the custom control to an object that has all the properties you want to clear, which are all each bound (two-way) to your textboxes etc. Then in the Save() method you can set a new object (which the custom control DataContext is bound to) and all the properties will be cleared for you (assuming you have implemented INotifyPropertyChanged on the object).
UPDATED:
As per my comment, see an example of the workaround for your current setup (untested btw):
public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem",
typeof(CustomObject), typeof(ExampleCustomControl), new PropertyMetadata(default(CustomObject), OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
var cont = source as ExampleCustomControl;
//do all the clearing of txtboxes etc here....
cont.SearchTextBox = string.Empty;
}
But I would still try and move all this into the VM. i.e. have a clear command, like you do with the save command and bind the textbox text etc to a property in the VM and when the command is called it clears everything, which you can then easily call from the Save method in the VM too. But obviously I have no idea what you are trying to achieve in the long run or how selectedItem and the textboxes etc are related, so depends (as always) i guess.

It sounds like you are thinking about this the wrong way. In MVVM the ViewModel should never know anything about the custom controls (hence you are having a problem with this Clear functionality).
Your requirements are a bit vague, but have you considered:
1) If the properties are bound from the VM, can't the Control detect when these are changed?
2) If you really need to call Clear from the XAML layer and want to keep it pure MVVM, then consider something like the Expression Blend SDK's CallMethodAction.

As a followup to my comment. I suspect your command is targeting the View and clearing the TextBoxes directly. Instead, have your command target the ViewModel and clear the properties the View is bound to. Then you can have the command be a property on the ViewModel and call it whenever needed.

Related

How to use IObservable<T> as a source for a WPF source binding to a ListBox?

So this is what I am currently doing:
I have a WPF ListBox that is currently data bounded to and populated by a
public ObservableCollection<string> SourceBinding
{
get;
set;
}
This WPF bounded source has an OnCollectionChanged event handler that does the following whenever a new item is added;
ObservableCollection<string> source = new ObservableCollection<String>();
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
NotifyPropertyChanged("NotifyPropertyChanged")
}
I am also subscribed to an IObservable<string> stream that is handling each tick via the TickHHandler event handler;
Stream.Subscribe(TickHandler);
TickHandler is currently doigng this:
private void TestSubscription( string item)
{
sourceBinding.Add(item)
}
Here, for each output tick event from the Rx stream, the ObservableCollection is updated and the WPF GUI is notified of the changes that need to be made.
What I would like to do however, is bind the ListBox directly to my IObservable<string> stream preferably inside xaml.
I am assuming that I'd somehow have to use Behaviors to expose a custom IObservableItemsSource property to bind the IObservable<string> source for consumption. I imagine it would look something like this in the end:
IObservableItemsSource ="{Binding IObservableSource}"
I know how to implement Behavior, but I have no idea how to start creating an IObservable<string> property for use in xaml, or if this is even possible!
Am I way off the mark? Can someone explain what the best way to implement this should be?
Thanks.
The Observable Collection implement INotifyCollectionChanged which will alert the xaml that it needs to update the view. So if you just add to the collection as you are doing it should update the UI automatically as long as you are binding it correctly to the ViewModel.
This is the view
<ListBox ItemsSource="{Binding Collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is the code behind
public class ViewModel
{
public ObservableCollection<string> Collection { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
vm.Collection = new ObservableCollection<string>();
this.DataContext = vm;
vm.Collection.Add("Item");
vm.Collection.Add("Item");
vm.Collection.Add("Item");
vm.Collection.Add("Item");
vm.Collection.Add("Item");
}
Note that as long as you are doing your processing in the UI thread you this will work. If you are doing it in a background thread you will need to dispatch and add to the observable collection in the UI thread.

Confused in DataContext in WPF

I am beginner to WPF and MVMM architecture. VI came across many links which explains about DataContext dependence property in WPF MVMM architecture,
i.e.
view.DataContext = new ViewModels.MainViewModel();
but they always made me confused. Although I have some basic idea about this DataContext like it is used to represent who's object we need in xaml file, but when blogs talks about tree structure inheritance of dataContext I gets confused. Can any one please help me with some very simple and clear example showing how this hierarchy of DataContext works?
Thanks in advanced.
The DataContext property specifies the default source for Data Binding. Consider the following example:
<TextBox Text="{Binding MyProperty}" />
What this Binding says: take the value of MyProperty from whatever object is inside the DataContext, convert it to a string and put it in the TextBox. So if we would set the DataContext of the TextBox to be an object of the following class:
public class Example {
int MyProperty { get { return 3; } }
}
Then, the Text of the TextBox would be set to 3.
What does it mean that the values Inherit? Consider a slightly more complex example:
<Window Name="MainWindow">
<StackPanel>
<TextBox Text="{Binding MyProperty}" />
...etc
If we would have 10 or more TextBox elements on our screen, it would be a lot of senseless work to assign the DataContext to each and every TextBox. To relieve this issue, the implementors of WPF decided that setting the DataContext on the MainWindow in our case would also apply it to everything inside that Window (all children, all nested elements) until the DataContext property is overwritten (i.e. we set the DataContext of the TextBox, then the TextBox and all its children would also receive this DataContext).
If you want to see this behavior in action, the same applies to the FontSize property, try setting the FontSize of your Window to 48 and see what happens to all the text in there!
The Datacontext property is the default source of all the binding of a View.
In MVVM, the Datacontext is used to link a ViewModel to a View.
As the Datacontext property is a dependence property, if you don't define it in a control, it will inherit from his father, etc.
Here is an exemple of MVVM implementation :
Parent of all ViewModel class (to implement INotifyPropertyChanged in all ViewModels) :
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Note : INotifyPropertyChanged allow your ViewModel to notify the View of a change (used for bindings).
Let's say I want a MainWindows (View) to be linked to a ViewModel :
public MainWindow()
{
InitializeComponent();
MainViewModel mainViewModel = new MainViewModel(this);
this.DataContext = mainViewModel;
}
With for ViewModel :
class MainViewModel : ViewModelBase
{
#region fields
private MainWindow mainWindow;
private string message = "Hello world !";
#endregion
#region properties
public MainWindow MainWindow
{
get
{
return this.mainWindow;
}
}
public string Message
{
get
{
return message;
}
set
{
this.message = value; OnPropertyChanged("Message");
}
}
// ...
#endregion
public MainViewModel(MainWindow mainWindow)
{
this.mainWindow = mainWindow;
}
}
So now if I want to bind a property of MainViewModel in my View (mainwindow), i just have to have a public property in my ViewModel and to create a binding in my XAML. I won't have to specify the source as the DataContext is the default source.
So MainWindow.xaml I can add :
<TextBox Text="{Binding Message}" />

How can I bind to a non ObservableCollection?

Is there a way to bind directly to a Collection in the model and manually tell WPF that the binding needs refreshing without having to create an ObservableCollection for it in the viewmodel?
<ListBox ItemsSource="{Binding Position.PossibleMoves}">
...
</ListBox>
Position is my model, part of a chess library, and PossibleMoves is a Collection within it. I do not want to implement INotifyProperty changed or put ObservableCollections in a stand alone optimized library.
I want to avoid copying PossibleMoves into an ObservableCollection every time the position is updated. The data binding works on initialization but it would be handy if I could also refresh the binding at will inside the viewmodel.
Calling OnNotifyPropertyChanged("Position.PossibleMoves") from the viewmodel doesn't work because the reference to the collection itself does not change.
You can do this by using an attached behavior to bind a handler to an event that gets triggered in the view model. You can't bind directly to events though so you have to wrap them in a class like so:
public class Refresher
{
public delegate void RefreshDelegate();
public event RefreshDelegate Refresh;
public void DoRefresh()
{
if (this.Refresh != null)
this.Refresh();
}
}
Now add an instance of that to your view model:
public class MyViewModel
{
public IList<string> Items { get; set; }
private Refresher _Refresher = new Refresher();
public Refresher Refresher {get {return this._Refresher;}}
}
Next create an attached behavior that registers a delegate instance with that event and forces the listbox to refresh its binding:
public static class RefreshBehavior
{
public static readonly DependencyProperty RefresherProperty = DependencyProperty.RegisterAttached(
"Refresher",
typeof(Refresher),
typeof(RefreshBehavior),
new PropertyMetadata(null, OnRefresherChange));
public static void SetRefresher(DependencyObject source, Refresher value)
{
source.SetValue(RefresherProperty, value);
}
public static Refresher GetRefresher(DependencyObject source)
{
return (Refresher)source.GetValue(RefresherProperty);
}
private static void OnRefresherChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Refresher.RefreshDelegate handler = () =>
{
var listBox = d as ListBox;
listBox.Items.Refresh();
};
if (e.NewValue != null)
(e.NewValue as Refresher).Refresh += handler;
if (e.OldValue != null)
(e.OldValue as Refresher).Refresh -= handler;
}
}
And finally attach it to your listbox in the xaml:
<ListBox ItemsSource="{Binding Items}"
local:RefreshBehavior.Refresher="{Binding Refresher}"/>
That's it. Call Refresher.DoRefresh() in your view model and it will force a listbox update.
This works but it's really hammering a square peg into a round hole. If I were you I'd do everything I could to try and do proper collection changed notification in your view model. I understand you wanting to keep ObservableCollection out of your model but there are ways to proxy change notification automatically (e.g. Castle DynamicProxy).
You need to NotifyPropertyChange for the PossibleMoves from inside the Position class or make a property that delegates to the Position.PossibleMoves and notify that one.

WPF custom control databinding

I'm new to the development of custom controls in WPF, but I tried to develop a single one to use in a application that I'm developing. This control is an autocomplete textbox. In this control, I have a DependencyProprety that has a list of possible entries so a person can choose from while entering the text
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource",typeof (IList<object>),typeof (AutoCompleteTextBox),new PropertyMetadata(null));
public IList<object> ItemsSource
{
get { return (IList<object>) GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
RaiseOnPropertyChanged("ItemsSource");
}
}
I use this control in a usercontrol and associate this control to a property in the viewmodel
<CustomControls:AutoCompleteTextBox Height="23" Width="200"
VerticalAlignment="Center" Text="{Binding Path=ArticleName, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=Articles,
Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
</CustomControls:AutoCompleteTextBox>
I have a viewmodel that I assign on the usercontrol load to the datacontext of the usercontrol load
protected virtual void Window_Loaded(object sender, RoutedEventArgs e)
{
if (!DesignerProperties.GetIsInDesignMode(this))
{
this.DataContext = viewModel;
SetLabels();
}
}
This viewmodel has the property Articles with values but the ItemsSource property of the control is null when I try to search in the list after the user enter some text.
Is there any special step that I missed when I create the control so use the mvvm pattern.
I hope that the explain the problem in a understandable way. Any help/hints would be welcome.
There are two issues here:
First, you're dependency property is defining the "default" value for this property to be null. You can change that by changing the metadata to specify a new collection:
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource",typeof (IList<object>),typeof (AutoCompleteTextBox),
new PropertyMetadata(new List<object>));
Secondly, when using dependency properties, the setter can't contain any logic. You should keep your property set as:
public IList<object> ItemsSource
{
get { return (IList<object>) GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
This is because the setter doesn't actually get called by the binding system - only when you use code. However, since the class is a DependencyObject and this is a DP, you don't need to raise property changed events.

WPF MVVM : Commands are easy. How to Connect View and ViewModel with RoutedEvent

Suppose I have a view implemented as a DataTempate inside a resource Dictionary.
And I have a corresponding ViewModel.
Binding Commands are easy. But what if my View contains a control such as a ListBox, and I need to Publish an application wide event (Using Prism's Event Aggreagtor) based on the Item being Changed on the List.
if ListBox supports a command I could just bind it to a command in the ViewModel and publish the event. But Listbox doesn't allow such an option.
How do I bridge this?
EDIT:
Many great answers.
Take a look at this link http://blogs.microsoft.co.il/blogs/tomershamam/archive/2009/04/14/wpf-commands-everywhere.aspx
Thanks
Ariel
Instead of trying to bind a command to when the item changes, I looked at the problem another way.
If you bind the selected item of the ListBox to a property in the ViewModel, then when that property is changed you can publish the event. That way the ViewModel remains the source of the event and it is triggered by the item changing, which is what you want.
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
...
public class ViewModel
{
public IEnumerable<Item> Items { get; set; }
private Item selectedItem;
public Item SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem == value)
return;
selectedItem = value;
// Publish event when the selected item changes
}
}
Extend the control to support ICommandSource and decide which action should trigger the command.
I did this with Combo Box and used OnSelectionChanged as the trigger for the command. First I will show in XAML how I bind the command to the extended Control ComboBox which I called CommandComboBox, then I will show the code for CommandComboBox that adds the support for the ICommandSource to ComboBox.
1) Using CommandComboBox in your XAML code:
In your XAML namespace declarations include
xmlns:custom="clr-namespace:WpfCommandControlsLibrary;assembly=WpfCommandControlsLibrary">
Use the CommandComboBox in place of ComboBox and bind the command to it like so: Note that in this example I have a defined a command called SetLanguageCommand im my ViewModel and I am passing the selected value for this ComboBox as the parameter to the command.
<custom:CommandComboBox
x:Name="ux_cbSelectLanguage"
ItemsSource="{Binding Path = ImagesAndCultures}"
ItemTemplate="{DynamicResource LanguageComboBoxTemplate}"
Command="{Binding Path=SetLanguageCommand, Mode=Default}"
CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=SelectedValue, Mode=Default}"
IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Grid.Column="1" Margin="0,0,20,0" Style="{DynamicResource GlassyComboBox}" ScrollViewer.IsDeferredScrollingEnabled="True"
/>
2) The code for CommandComboBox
The code for the file CommandComboBox.cs is included below. I added this file to a Class Library called WpfCommandControlsLibrary and made it a separate project so I could easily add any extend commands to whatever solution needed to use them and so I could easily add additional WPF Controls and extend them to support the ICommandSource inteface.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WpfCommandControlsLibrary
{
/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:WpfCommandControlsLibrary"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:WpfCommandControlsLibrary;assembly=WpfCommandControlsLibrary"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:CustomControl1/>
///
/// </summary>
public class CommandComboBox : ComboBox, ICommandSource
{
public CommandComboBox() : base()
{
}
#region Dependency Properties
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(CommandComboBox),
new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(CommandChanged)));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
// Make CommandTarget a dependency property so it can use databinding.
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register(
"CommandTarget",
typeof(IInputElement),
typeof(CommandComboBox),
new PropertyMetadata((IInputElement)null));
public IInputElement CommandTarget
{
get
{
return (IInputElement)GetValue(CommandTargetProperty);
}
set
{
SetValue(CommandTargetProperty, value);
}
}
// Make CommandParameter a dependency property so it can use databinding.
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(CommandComboBox),
new PropertyMetadata((object)null));
public object CommandParameter
{
get
{
return (object)GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
#endregion
// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandComboBox cb = (CommandComboBox)d;
cb.HookUpCommand((ICommand)e.OldValue, (ICommand)e.NewValue);
}
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
}
// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
}
}
private void CanExecuteChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
}
}
// If Command is defined, selecting a combo box item will invoke the command;
// Otherwise, combo box will behave normally.
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}
// Keep a copy of the handler so it doesn't get garbage collected.
private static EventHandler canExecuteChangedHandler;
}
}
One option is to extend the control in question and add support for the particular command you require. For example, I've modified ListView before to support the ItemActivated event and related command.
Well, nobody answered.
So I've gave up and moved the implementation of the View outside the Dictionary into a regular UserControl, I've injected him a reference to the ViewModel.
Now when the ListBox fire the Event it's calls the ViewModel and from there everything is possible again.
Ariel
A great solution to this type of problem comes from the usage of Attached Properties.
Marlon Grech has taken the usage of Attached Properties to the next level by creating Attached Command Behaviors. Using these it is possible to bind any Command existing in a ViewModel to any Event existing in the view.
This is something I use a lot to deal with similar issues with ListBoxes, where I want them to open, or edit or do some action on a double click.
In this example I'm using an older version of Attached Command Behaviors, but the effect is the same. I have a style that is used for ListBoxItems which I am explicitly keying to.
However, it would be easy enough to create a application or window wide style applying to all ListBoxItems that sets the commands at a much higher level. Then, whenever the event for the ListBoxItem attached to the CommandBehavior.Event property would fire, it instead fires off the attached Command.
<!-- acb is the namespace reference to the Attached Command Behaviors -->
<Style x:Key="Local_OpenListItemCommandStyle">
<Setter Property="acb:CommandBehavior.Event"
Value="MouseDoubleClick" />
<Setter Property="acb:CommandBehavior.Command"
Value="{Binding ElementName=uiMyListBorder, Path=DataContext.OpenListItemCommand}" />
<Setter Property="acb:CommandBehavior.CommandParameter"
Value="{Binding}" />
</Style>
<DataTemplate x:Key="MyView">
<Border x:Name="uiMyListBorder">
<ListBox ItemsSource="{Binding MyItems}"
ItemContainerStyle="{StaticResource local_OpenListItemCommandStyle}" />
</Border>
</DataTemplate>
I have been writing behaviors (attached properties) to do this, and there are still cases where I need them.
For the usual case however, simply binding an event to a command, you can do everything in Xaml if you have Blend SDK 4 installed. Note that you will have to add a reference to System.Windows.Interactivity.dll, and to redistribute this assembly.
Expression Blend SDK for .NET 4
Microsoft SDKs (for future reference)
This example is invoking an ICommand DragEnterCommand on the ViewModel when the DragEnter event of the Grid is fired:
<UserControl xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DragEnter">
<i:InvokeCommandAction Command="{Binding DragEnterCommand}" CommandParameter="{Binding ...}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</UserControl>
Try using Prism 2.
It comes with great extensions to commanding and opens many new posibilites (like commands to being tied to visual tree).

Resources