Simulating IsSynchronizedWithCurrentItem in Silverlight (part 1)

.NET, Blend, Silverlight, Technical stuff, Work, WPF
See comments

This is part 1 of a two posts series about the property IsSynchronizedWithCurrentItem. In this post, we will see what it does in Windows Presentation Foundation. In the next post, we will see that this property is missing in Silverlight, and propose a way to simulate it.

One of the features I really like in Windows Presentation Foundation is the ability to set a flag on various list controls (such as ListBox, ComboBox, etc…) deriving from the Selector class. This flag is named IsSynchronizedWithCurrentItem. It indicates to the framework that when the selected item in a collection changes, all the Selector controls that use this collection as their ItemsSource must be notified. This is very handy to keep a user interface in synch without writing code.

This feature in WPF is made possible by the presence of a class named CollectionViewSource. In fact, when you bind a Selector control to an ObservableCollection, behind the scene, a CollectionViewSource is created. This object enables interesting scenarios, such as filtering or sorting the items without touching the original collection, or (yes) detecting which item is currently selected.

Using IsSynchronizedWithCurrentItem in WPF

In WPF, you can also have an very interesting, and not very well known syntax in XAML bindings: You can bind a property to the selected item of a given collection. To see this in action, download this sample, unzip and open it in Visual Studio. Let’s review this sample together.

  • The ViewModel folder contains data classes that are especially prepared to be data bound to. This is done by letting them implement the interface INotifyPropertyChanged. This pattern is named Model-View-ViewModel (or MVVM) and is gaining a lot of popularity nowadays in WPF and Silverlight. For more info about MVVM, read a great introductory  article by my friend and programmer extraordinaire Josh Smith.
  • It must be noted that the MainViewModel class constructor builds 10 DataItem instances and adds them in the collection (called DataItems). Normally, we would only do this during design time, to give the designer data to design against. In this simple sample, there is no “real service” providing data, so this is the only data we’ll work with.
  • Also worth noting: The collection named DataItems is deriving from ObservableCollection<DataItem>. This class doesn’t provide any additional feature. This is something we do sometimes when we want to use a generic class in XAML, because XAML doesn’t support generics (Not yet at least. The next version of XAML will have built in support for generics). In this particular case, we use a new class named DataItems because its implementation will be slightly different in Silverlight, and we want to hide this from the ViewModel class. More about this later.
  • The class Window.xaml.cs, called the “code behind”, doesn’t contain any code, apart from the generated call to “InitializeComponent” (this is the method that parses the XAML code and creates the UI elements). This is one advantage of the MVVM pattern: No code behind (or only minimal), which improves the testability and the maintainability of the application, as well as its portability (like we will see when we convert the application to Silverlight).
  • The User Interface is implemented in Window.xaml. It is very basic: A Grid with two columns. The left column has a ListBox. The right column has a StackPanel containing a ComboBox, a TextBox and a CheckBox.

The interesting thing is that the DataContext of the Window is set to an instance of the MainViewModel. This is achieved by the following code:

<Window.Resources>
  <vm:MainViewModel x:Key="MainViewModel"
                    d:IsDataSource="True" />
</Window.Resources>

<Window.DataContext>
  <Binding Source="{StaticResource MainViewModel}" />
</Window.DataContext>

This XAML snippet places an instance of the MainViewModel class in the Window’s resources. Then, it binds the Window’s DataContext property to that resource. The MainViewModel class will be instantiated when the XAML parser executes the binding. This way to create the ViewModel is very nice, because it will also be executed in Expression Blend. Remember the 10 DataItem we added to the collection in the MainViewModel constructor? Blend will display them, and allow the designer to create a DataTemplate, which is also placed in the Window’s resources.

image

Main window in Expression Blend. Notice that the 10 “design time items” are available.

Setting up the Selector controls

The Selector controls in the Window (a ListBox and a ComboBox) all use the same collection. They also both use the property IsSynchronizedWithCurrentItem. The ListBox sets this property to true, no matter what.

<ListBox ItemTemplate="{StaticResource DataTemplate1}"
         ItemsSource="{Binding Items}"
         IsSynchronizedWithCurrentItem="True" />

The ComboBox binds the property to a boolean property in the ViewModel:

<ComboBox IsSynchronizedWithCurrentItem="{Binding PropertyOn}"
          ItemTemplate="{StaticResource DataTemplate1}"
          ItemsSource="{Binding Items}" />

This ViewModel property is controlled by the CheckBox. So when the CheckBox is checked, the ComboBox’ selected item is kept in sync with the ListBox. If the CheckBox is unchecked, the ComboBox will be allowed to display a different selected item than the ListBox.

<CheckBox Content="Switch property on/off on combo"
          IsChecked="{Binding PropertyOn, Mode=TwoWay}"
          Margin="0,10,0,0" />

Using the selected item on the collection in a binding

As we mentioned before, a special syntax in XAML allows to bind to the selected item in the collection in an implicit manner. This is displayed in the TextBox:

<TextBox Text="{Binding Items/TestName, Mode=TwoWay}"
         Height="30"
         Margin="0,10,0,0" />

The syntax “Items/TestName” means “In the Items collection (in the explicit DataContext), use the selected item (this is what the “/” means). In this selected item, bind to the property TestName.” Since this is a TwoWay binding, if the user modifies the value, the new value will automatically appear in the ListBox and in the ComboBox.

This syntax is very handy when you want to keep a user interface in synchronization without using code behind. The simple example can easily be expanded to display other properties of the DataItem and make it really easy to implement a List-Details view.

Unfortunately, this convenient property does not exist in Silverlight 2. In the next post, we will see how we can use an attached behavior to simulate the property and make the syntax as close to the WPF one as possible.

Running the code

If you run the application, you will see that the item selcted in the ListBox, in the ComboBox and the item displayed by the TextBox are kept in sync. If you edit the name in the TextBox, the result is reflected in the Selector controls immediately – through the magic of data binding. If you change the selection in the ComboBox, the selected item in the ListBox also changes.

If however you uncheck the CheckBox, the property IsSynchronizedWithCurrentItem is set to false on the ComboBox. Changes in the ListBox are not reflected and the SelectedItem is not set. Of course, if you edit the name of the SelectedItem, the edited name will also be visible in the ComboBox (IsSynchronizedWithCurrentItem  only affects the SelectedItem). Checking the CheckBox again will synchronize the Selector controls again.

image

image

And this for Rob

Hey Rob, I set the Title on my window ;)

Previous entry | Next blog entry

Comments for Simulating IsSynchronizedWithCurrentItem in Silverlight (part 1)