Saturday, April 11, 2009

Binding a State Change to a Property Change

The video below describes the application in which we applied the approach described in this blog post:



VisualStateManager is a great way to change a lot of properties at once when the state of the model that is bound to the control changes. It allows you to separate design from implementation and gives your designers freedom to build some really interesting visual applications.
The code for forcing a Silverlight control to change state is:

VisualStateManager.GoToState(oControl, "NEWSTATE", true);

So you need to call this code to force a state transition. But what if you want to notify VisualStateManager based on the change of a value in your domain model? You can exploit the IValueConverter interface and the normal binding mechanism to do this.



void OnLoaded(object sender, RoutedEventArgs e)
{
Binding oBinding = new Binding("DisplayState");
oBinding.Converter = StateConverter;
oBinding.ConverterParameter = ValueIcon;
//the control that is the target of the state change
LayoutRoot.SetBinding(FrameworkElement.VisibilityProperty, oBinding);
}


When the control is loaded I use standard binding to associate the VisibilityProperty of the control to the property in my domain model named "DisplayState". The binding instructions include the StateConverter (defined next), and the value of ConverterParameter is the XAML element that is the target of the GoToState Command. As you can see, the StateConverter ignores the conversion completely and always returns 'visible'. However, during the update process, the control passed in the parameter argument is now the target of the GoToState command. Furthermore, the new state is set to the value calculated by the property bound to this StateConverter. Whenever the domain model changes state, the GoToState will be targeted at the associated control and passed the correct value.

public class StateConverter : ValueConverter
{
#region IValueConverter Members

public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Control oControl = parameter as Control;
sState = value.ToString();
VisualStateManager.GoToState(oControl, sState, true);
return Visibility.Visible;
}

#endregion
}


I like to have all my converter classes inherit from a common converter class, mainly because in most cases the conversions do not require a ConvertBack method -- this way I only need to implement the functionality the converter truly requires.

public class ValueConverter : IValueConverter
{
#region IValueConverter Members

public virtual object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}

public virtual object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}

#endregion
}

1 comment:

Kirk Quinbar said...

I like this technique, but i would like to know if its possible to setup this kind of binding on the xaml side instead of codebehind?