Often times when working in WPF and Silverlight we have to perform some action in code-behind that cannot be uncoupled from the view and put in the view model. For instance, a command may affect multiple properties on a UI control or a property may not support binding. Here is a quick set of steps to make tightly coupled code-behind more MVVM-friendly.
UserControl
Put your UI into a UserControl if it’s not already.
Dependency Property
Define a dependency property in your User Control’s code-behind. The PropertyChangedCallback event of your property should contain the troublesome code that can only be set in code-behind.
private static string DefaultMyDependencyProperty = "";
/// <summary>
/// MyDependencyProperty Dependency Property
/// </summary>
public static readonly DependencyProperty MyDependencyPropertyProperty =
DependencyProperty.Register(
"MyDependencyProperty",
typeof(string),
typeof(MyUserControl),
new PropertyMetadata(DefaultMyDependencyProperty, OnMyDependencyPropertyChanged));
/// <summary>
/// Gets or sets the MyDependencyProperty property.
/// </summary>
public string MyDependencyProperty
{
get { return (string)GetValue(MyDependencyPropertyProperty); }
set { SetValue(MyDependencyPropertyProperty, value); }
}
/// <summary>
/// Handles changes to the MyDependencyProperty property.
/// </summary>
private static void OnMyDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = (MyUserControl)d;
string oldMyDependencyProperty = (string)e.OldValue;
string newMyDependencyProperty = target.MyDependencyProperty;
target.OnMyDependencyPropertyChanged(oldMyDependencyProperty, newMyDependencyProperty);
}
/// <summary>
/// Provides derived classes an opportunity to handle changes
/// to the MyDependencyProperty property.
/// </summary>
protected virtual void OnMyDependencyPropertyChanged(string oldMyDependencyProperty, string newMyDependencyProperty)
{
// write your code-behind logic here
}
Bind in the View
Where you’ve defined the UserControl in your parent Window or Page, now you can bind the dependency property to some property on your view model.
<local:MyUserControl MyDependencyProperty="{Binding MyViewModelProperty, Mode=TwoWay}" />
Now when you set the MyViewModelProperty from your view model, the OnMyDependencyPropertyChanged event (which contains your code-behind logic) gets fired. Now you can trigger code-behind from a command in your view model. For example, you can have a button on your UI that is bound to a command in the view model. The command sets the public property on the view model that’s bound to the new dependency property. This triggers the callback event, and fires the UI code-behind that has access to the UI controls. So why would you do all of this? It only makes sense if you are actually getting and setting useful information in the MyViewModelProperty. If not, then you’ve overcomplicated the button logic, and you should just stick with button click event.
A Sample Scenario
I made a sample using the technique above to illustrate how this helps make FlexGrid filtering more MVVM-friendly. The C1FlexGridFilter class is used to add some filtering features to the C1FlexGrid control. It has a property called FilterDefinition which gets or sets the filter as an XML string. FilterDefinition makes it possible to persist the filter settings between runs of the application; however it’s not a dependency property that can be easily bound to in XAML. By creating my own dependency property on my user control, I’ve now made the filter definition controlled by the view model. You can download the sample below. Download FlexGridFilterMVVM Sample
Hunter Haaf