WPF ViewModel First, set Binding from code after loading

20 בMay 2014

2 תגובות

,This is probably not a rare situation

:The Scenario is as following

.1

,we have a View which contain a CollectionView of any type

.2

.the collection’s SelectedItem is bound to some ViewModel Property lets call it MySelectedItem

.3

:the View DataContext get initialized during ViewLoading like

   1: public MyView(MyViewModel viewModel)

   2:         {

   3:             InitializeComponent();

   4:             this.Loaded += (s, e) =>

   5:             {

   6:                 this.DataContext = viewModel;

   7:

   8:             };

   9:         }

Now, this mechanism working using some IOC library, but not sure it is relevant, since we can

:directly invoke the ViewModel like

   1: MyViewModel vm = new MyViewModel();

   2: MyView view = new MyView(vm);

,the MySelectedITem in the ViewModel  sets his value before the View even exit,
meaning

   1: MyViewModel vm = new MyViewModel();

   2: VM. MySelectedITem = MyList.firstOrDefault;

   3: MyView view = new MyView(vm);

.4

now when the UI get rendering the UICollection has no Idea of the SelectedItem bounded Property that already has a value, and even worse he actually overwrite it, since default of

. SelectedItem in Collection (Like ComboBox) is the First

.So clearly we have a corrupted data in our ViewModel

A few solutions can considerate here. Lets try one that is quite dirty but quite brilliant at the

.same time

.1

.in our xaml we not binding the selectedItem Property to nothing

.Only the itemSource has Binding

.2

:we do must add some helper like this EventTrigger

   1: <i:Interaction.Triggers>

   2:                     <i:EventTrigger EventName="Loaded">

   3:                         <i:InvokeCommandAction  Command="{Binding Path=RefreshSelectedComboCommand}"    CommandParameter="{Binding RelativeSource= {RelativeSource Mode=FindAncestor, AncestorType=ComboBox}}"/>

   4:                     </i:EventTrigger>

   5:                 </i:Interaction.Triggers>

This is just a notification of Pre-Loading control when the regular properties has all the Binding

.parameters

.3

:in your viewModel we create an appropriate ICommand

   1: private DelegateCommand<ComboBox> m_refreshSelectedComboCommand;

   2:         public DelegateCommand<ComboBox> RefreshSelectedComboCommand

   3:         {

   4:             get

   5:             {

   6:                 if (m_refreshSelectedComboCommand == null)

   7:                 {

   8:                     m_refreshSelectedComboCommand = new DelegateCommand<ComboBox>(RefreshProperties);

   9:                 }

  10:                 return m_refreshSelectedComboCommand;

  11:

  12:             }

  13:         }

.4

now I know its kind of dirty architecture yet,I do actually has a reference the UIComboBox and

..we can see the light at the end of the tunnel

the Command function can build some custom Binding instance and connect to the relevant

:Property

   1: public void RefreshProperties(ComboBox combo)

   2:       {

   3:           Binding myBinding = new Binding();

   4:           myBinding.Source = this;

   5:           myBinding.Path = new PropertyPath("MySelectedItem");

   6:           myBinding.Mode = BindingMode.TwoWay;

   7:           myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

   8:           BindingOperations.SetBinding(combo, ComboBox.SelectedItemProperty, myBinding);

   9:

  10:           RaisePropertyChanged(() => MySelectedItem);

  11:       }

.And it works

It is recommended to try this solution using Custom Behavior

הוסף תגובה
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

2 תגובות

  1. שחר אלדד21 בMay 2014 ב 12:18

    למה לא להרים RaisePropertyChanged ריק כדי שכל ה- binding יתעדכנו? (ניתן לקרוא לו מיד אחרי שמחברים את ה- viewmodel ל- view ב- Loaded)
    האם הקוד למעלה אומר שה- viewmodel מודע לנושא של Binding שהוא אוביקט של View?

    Reply
    1. Uriel Jacobson
      Uriel Jacobson27 בMay 2014 ב 7:58

      indeed, i said before, it is dirty, and it should be export to some behavior,
      to refresh the view model will not help since the SelecedItem binding set it first so we will need a swap with temporary variable and its also a dirty code

      Reply