none
UpdateSourceTrigger=Explicit not working with Master-Detail Scenario

    שאלה

  •  

    For some reason UpdateSourceTrigger= Explicit does not work when using Master-Detail Scenario.

     

    I have a ListView bound to an observablecollection and a content control as follows

     

    <ListView Name="TenantList" Height="Auto" HorizontalAlignment="Left" VerticalAlignment="Top"

    DataContext="{Binding Source={StaticResource OwnerListData}}" IsSynchronizedWithCurrentItem="True"

    Style="{StaticResource BaseStyle}" ItemsSource="{Binding Path=Tenants}" >

     

    <ContentControl Name="TenantDetails" VerticalAlignment="Top" HorizontalAlignment="Left"

    Grid.Column="1" Grid.Row="7" DataContext="{Binding Source={StaticResource OwnerListData}}"

    Content="{Binding Path=Tenants}"

    ContentTemplate="{StaticResource detailsTenantTemplate}"

    Margin="9,0,0,0"/>

     

    Inside my ContentControl's template I have a Textbox defined as follows

    <TextBox Grid.Column="2" Name="TenantNotesData" Text="{Binding Path=Notes, Mode=TwoWay, UpdateSourceTrigger=Explicit}" AcceptsReturn="True"

    Style="{StaticResource TextStyleInherited}" Height="60"/>

     

    For some reason the Textbox does TwoWay binding as soon as soon as another item in the ListView is selected. I see this happening only when I use Master-Detail Scenario. Am I doing something wrong or is this a limitation?

    יום שני 23 אפריל 2007 16:48

תשובות

  • This is by design.  When you select another item in the ListView, the TextBox gets bound to the new item.  What should happen to the text in the TextBox?  The user entered that text while the old item was displayed, so the text clearly belongs to the old item (not the new one).  Discarding the text would be wrong - it throws away data that the user entered.  Writing that text out to the old item is the only reasonable thing to do.

     

    To put it another way, an app uses the Explicit update mode to let the user type in provisional values and eventually commit them (typically by clicking a "Commit" button that calls the UpdateSource method on the relevant bindings).  Selecting another item is merely another way to commit the changes for the current item.

     

    The XML binding doesn't do this.  That's a bug.

    יום שלישי 24 אפריל 2007 17:18
  • Hello,

     

    Sam and I talked about this, and we understand your scenario and why you would not want the data to be commited when changing selection. We think that the current behavior makes sense when the binding mode is not Explicit, but we will rethink our design for explicit bindings. We especially don't like the fact that XML and objects behave differently today, there is not technical reason why this should happen. Unfortunately it's too late to talk about this for the next release, but we'll revisit this topic after that.

     

    I played with your scenario and was able to find a workaround. I started by adding an event that will be raised every time a ListViewItem becomes unselected.

     

    <Style TargetType="{x:Type ListViewItem}">

    <EventSetter Event="Unselected" Handler="SelectedItem" />

    </Style>

     

    Then, in the handler for that event, I grab the instance of the BindingExpression of the ContentControl and update its target. Updating the target (the Text property of the TextBox) with the current value of its source (the selected item of the ListView) will revert whatever the customer typed in the TextBox.

     

    private void SelectedItem(object sender, RoutedEventArgs args)

    {

    ContentPresenter cp = (ContentPresenter)(VisualTreeHelper.GetChild(TenantDetails, 0));

    DataTemplate tenantTemplate = this.Resources["TenantTemplate"] as DataTemplate;

    TextBox tb = tenantTemplate.FindName("tb", cp) as TextBox;

    BindingExpression be = tb.GetBindingExpression(TextBox.TextProperty);

    be.UpdateTarget();

    }

     

    You can find a complete csproj with this code here: http://www.beacosta.com/Forum/MasterDetail.zip.

     

    Let me know if this works for you. This was great feedback, thanks a lot for explaining this scenario to us!

     

    Bea

     

    יום שישי 04 מאי 2007 00:35
    מנחה דיון

כל התגובות

  •  

    Some updates on what I have been trying

     

    I tried the Master-Deatils Scenario with the following

    • ObservableCollection
    • List<T>
    • XML Data

    What I see is that the UpdateSourceTrigger=Explicit does not work for ObservableCollection or when using List<T> but works if I'm using XML Data. In the first two cases editting the textbox updates the Listview as soon as I select another item in the Listview inspite of specifying UpdateSourceTrigger=Explicit.

     

    Please help me understand whats happening here. Thanks

     

     

    יום שני 23 אפריל 2007 18:33

  • I tried couple of things more, still it does not work. Could somebody atleast tell me if this is a known limitation or if it is something that I'm doing wrong. It would be greatly helpful if somebody could provide me this information. If this is a known limitation, I do not want to spend more time but figure out a work around. Any help here would be appreciated. Thanks.
    יום שלישי 24 אפריל 2007 12:11
  • This is by design.  When you select another item in the ListView, the TextBox gets bound to the new item.  What should happen to the text in the TextBox?  The user entered that text while the old item was displayed, so the text clearly belongs to the old item (not the new one).  Discarding the text would be wrong - it throws away data that the user entered.  Writing that text out to the old item is the only reasonable thing to do.

     

    To put it another way, an app uses the Explicit update mode to let the user type in provisional values and eventually commit them (typically by clicking a "Commit" button that calls the UpdateSource method on the relevant bindings).  Selecting another item is merely another way to commit the changes for the current item.

     

    The XML binding doesn't do this.  That's a bug.

    יום שלישי 24 אפריל 2007 17:18
  •  

    Thank you so much Sam for your answer .. I spend quite a few days trying to understand this behavior and also did a lot of searches in google and several blogs and forum but did not find anything ..  I'm just curios but is there any documentation on this behavior?

     

    I still do not understand why this has been designed the way it is today... there could be scenarios where you type something in the details but do not want to commit. For example if I have a list of Tenants in my ListView and the DetailsView has the details of the selected Tenant, I may start editting the selected Tenant's details and then realise that I do not want to make this changes .. in this case I have no way to cancel out ... does that mean I'll have to type back the old values? .. or does that mean I have to implement a cancel button in my details view? There could also be cases where someone types a character in one of the fields in the detailsView without realising and as he goes to the next item in the ListBox, he may not even have realised the data has been changed until he gets some error or exception .. Could you please explain?

    יום שלישי 24 אפריל 2007 18:23
  • Hello,

     

    Sam and I talked about this, and we understand your scenario and why you would not want the data to be commited when changing selection. We think that the current behavior makes sense when the binding mode is not Explicit, but we will rethink our design for explicit bindings. We especially don't like the fact that XML and objects behave differently today, there is not technical reason why this should happen. Unfortunately it's too late to talk about this for the next release, but we'll revisit this topic after that.

     

    I played with your scenario and was able to find a workaround. I started by adding an event that will be raised every time a ListViewItem becomes unselected.

     

    <Style TargetType="{x:Type ListViewItem}">

    <EventSetter Event="Unselected" Handler="SelectedItem" />

    </Style>

     

    Then, in the handler for that event, I grab the instance of the BindingExpression of the ContentControl and update its target. Updating the target (the Text property of the TextBox) with the current value of its source (the selected item of the ListView) will revert whatever the customer typed in the TextBox.

     

    private void SelectedItem(object sender, RoutedEventArgs args)

    {

    ContentPresenter cp = (ContentPresenter)(VisualTreeHelper.GetChild(TenantDetails, 0));

    DataTemplate tenantTemplate = this.Resources["TenantTemplate"] as DataTemplate;

    TextBox tb = tenantTemplate.FindName("tb", cp) as TextBox;

    BindingExpression be = tb.GetBindingExpression(TextBox.TextProperty);

    be.UpdateTarget();

    }

     

    You can find a complete csproj with this code here: http://www.beacosta.com/Forum/MasterDetail.zip.

     

    Let me know if this works for you. This was great feedback, thanks a lot for explaining this scenario to us!

     

    Bea

     

    יום שישי 04 מאי 2007 00:35
    מנחה דיון
  •  

    Thank you Bea for your response. I agree with you on the current behavior when the binding mode is not Explicit and also that objects and XML does not have to behave differently. But I do feel that this needs to change when mode is Explicit especially because of the following reasons

    • The behavior of UpdateSourceTrigger=Explcit remains consistent throughout the framework in every scenario, thus making it very intuitive
    • When  you specify Explicit, YOU want the control on when the update should happen, not the databinding engine.

    Regarding the work around you sent me, I was aware of it and it works just fine. Thank you once again for your response and it feels good to know that posts in this forum are taken seriously and feedbacks are very much valued.

     

    - Rajani Nair

    יום שישי 04 מאי 2007 12:53
  • Hi Rajani,

     

    I'm not sure how clear I was, but that was precisely my point. I think that our design needs to change for Explicit bindings, for the reasons you mentioned. I already opened a bug about that internally, so this will not be forgotten.

     

    Thanks again for the great feedback!

     

    Bea

    יום שישי 04 מאי 2007 18:50
    מנחה דיון
  • Bea

    I'm running into the same issue. Although I can run your demo app to see that your workaround works, I have a problem to transfer this to my solution:

    I am using a ressource dictionary. and when I enter the style into that, I have to set a X:class name. Doing this, my whole app breaks.

    So I tried to add the handler by code,but I only can refer to the listview, not the listviewitem. Maybe you can show how to deifne this (ossibly in vb?)

    Regards
    Klaus
    יום חמישי 08 מאי 2008 21:32