Saturday, 25 August 2012

Silverlight datepicker in a MVVM master-detail setup

Working on my pet project where the UI is developed in Silverligth 4 I had a bit of a problem last day. The setup was simple. A master-detail where the master is a listbox and the detail a bunch of textboxes. To maintain the separation of concerns we use the MVVM pattern. Now the problem occured when adding a silverlight datepicker control to the detail control. Nothing special one would think. Here's my simplified xaml.
<Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Width="300" Margin="25">
            <ListBox x:Name="theListBox" ItemsSource="{Binding Dates}" SelectedItem="{Binding SelectedDate,Mode=TwoWay}" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Date}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

            <StackPanel DataContext="{Binding SelectedDate, Mode=TwoWay}">
                <sdk:DatePicker x:Name="theDatePicker" SelectedDate="{Binding Date, Mode=TwoWay}" />                
            </StackPanel>
            
        </StackPanel>
    </Grid>
The master viewmodel contains a list of childviewmodels, called "Dates", and a selected childviewmodel, called "SelectedDate", as you may deduct from the xaml. The childviewmodel contains one property called "Date" which returns a DateTime.

To reproduce the problem, select a date in the listbox. Change the value in the datepicker by typing the new value (not with the calendar control) and now, before triggering a lostfocus event on the datepicker, select another date in the listbox. Much to my surprise I noticed it was not the listbox item first selected but the second one that was changed.

To illustrate to problem more vividly you can have a try on here

The problem seemed to be that the binding operation of the datepicker is only triggering after the selectd item of the listbox is changed when losing focus. Thus updating the newly selected item and not the previous one.

After trying a lot of possible solutions I figured, if silverlight won't do the binding update correctly I guess I had to do it myself. This implied setting the UpdateSourceTrigger from my datepicker and listbox to explicit. So I can decide myself when to trigger the binding operation. Furthermore I had to create a custom datepicker and a custom listbox so that I could attach the appropriate handlers to the events.

You can download the source here.

I find it peculiar that such a simple thing requires that much work. Or perhaps I'm missing something, no actually I hope I'm missing something. I'm calling out to anyone who has a better solution here. I've got it to work but I'm not glad with the imo hacked solution. Luckily the "dirt" stays in the codebehind of the view.

One of the strengths of Silverlight and WPF is the ease to bind your view with your viewmodel. Losing that makes it a much less attractive choice.

No comments:

Post a comment