WPF – refresh SelectedItem in itemscontrol using MVVM

29 בMay 2013

תגובה אחת

the objective – you got items control – more specific you have got comboBox, and for each item in the collection the meaning is to Invoke some Command Action , now where is the problem ? when you select any item from the source , and at runtime like to invoke the same specific function e.g. the same selected item, the Control by default, doesnt refresh the and raise the selection change Event and when you depend on this change , your action just not showing up, and it is very simple why.. because the SelectedItem State just stay the same item and using MVVM it remaining the ViewModel side in darkness. yes you can probably solve it using codeBehind, but in several cases <depend on your code complex and what the SelectedItem-selection Change acting for > but its ugly.. and as we says its surly unsafe because you can clear the selected item before the BL part use it at all .

better solution could be using WPF Trigger and command Action with command Parameter the commanchingd parameter will be the ItemsControl itself , than in your viewModel side when finished the action than refresh the Combobox/ListBox.

Many WPF developers have found themselves against MVVM architecture in case like this. in basic it sound simple , but now its not about MVVM its about WPF controls behaviors.

The point is the MVVM make the challenge more fun.

For testing things lets start with next code:

   1: <StackPanel>

   2:     <ComboBox SelectedIndex="0" ItemsSource="{Binding Commands}" SelectedItem="{Binding SelectedColor}" />

   3:     <Label Name="label1"  Content="testcommand" Background="{Binding ColorTest}"  />

   4:     <Button Content="ColorTester" Height="23"   Name="button1" Width="75" Click="button1_Click" />

   5: </StackPanel>  

   6:  

1. Label for shoing selected color

2. comboBox for switching selected Color

3. button in position of interrupter player.

The application purpose is to switch the label color from green to red as the selected value of comboBox.

That Xaml conceted to the follow ViewModel Code:

   1: private List<string> commands;

   2: public List<string> Commands

   3: {

   4:     get { return commands; }

   5:     set

   6:     {

   7:         commands = value;

   8:         PropertyChanged(this, new PropertyChangedEventArgs("Commands"));

   9:     }

  10: }

  11:  

  12: private string selectedColor;

  13: public string SelectedColor

  14: {

  15:     get { return selectedColor; }

  16:     set

  17:     {

  18:         selectedColor = value;

  19:         PropertyChanged(this, new PropertyChangedEventArgs("SelectedColorcommand"));

  20:         switch (value)

  21:         {

  22:             case ("green"):

  23:                 {

  24:                     ColorTest = new SolidColorBrush(Colors.Green);

  25:                     break;

  26:                 }

  27:             case ("red"):

  28:                 {

  29:                     ColorTest = new SolidColorBrush(Colors.Red);

  30:                     break;

  31:                 }

  32:             default:

  33:                 break;

  34:         }

  35:     }

  36: }

  37:  

  38: private SolidColorBrush colorTest;

  39: public SolidColorBrush ColorTest

  40: {

  41:     get { return colorTest; }

  42:     set

  43:     {

  44:         colorTest = value;

  45:         PropertyChanged(this, new PropertyChangedEventArgs("ColorTest"));

  46:     }

  47: }

  48:  

  49: private void button1_Click(object sender, RoutedEventArgs e)

  50: {

  51:     ColorTest = Brushes.Yellow;

  52: }

 

It will be simple the figure it out when the last selection was green, than the interrupter set for something else, and when we get back to the combo and choose for green once again, it will not responds! It will reacting for selecting red! So why ?? well it is simple actually.

Since every items control has internal property called selectedItem, and the selected Item stay as it was because the label got is value from outside, and if we select same as last selected item it not called to observers and raise the SelectionChange Event ,

So, if we understand the problem we probably think about refresh the selected item after every selectionChanged, to do this using MVVM lets try use Triggers Action of System windows Interactivity.

Before we write the ‘Good’ solution lets check the bad one.

We can try this,

SelectionChanged="ComboBox_SelectionChanged"

And than

   1: private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)

   2:        {

   3:            ComboBox com = sender as ComboBox;

   4:            com.SelectedItem = null;

   5:        }

Well , first its breaking the MVVM for my taste, but worse it could be act before the command invokes or better to say you will never know !!

So the better option will be the next.

Add reference to system windows interactivity,

So first change the xaml as follow :

   1: <ComboBox SelectedIndex="0" ItemsSource="{Binding Commands}" SelectedItem="{Binding SelectedColor}"  >

   2:                 <i:Interaction.Triggers>

   3:                     <i:EventTrigger EventName="SelectionChanged" >

   4:                         <i:InvokeCommandAction Command="{Binding RefreshCommand}"   CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ComboBox}}}">

   5:                         </i:InvokeCommandAction>

   6:                     </i:EventTrigger>

   7:                 </i:Interaction.Triggers>

   8:             </ComboBox>

And your c# code will look like that:

   1: public DelegateCommand<object> RefreshCommand { get; set; }

   2:        

   3:        RefreshCommand = new DelegateCommand<object>(OnSelectionChanged);

   4:        

   5:        private void OnSelectionChanged(object sender)

   6:        {

   7:            ComboBox combo = sender as ComboBox;

   8:            if (combo.SelectedItem != null)

   9:            {

  10:                SelectedColor = combo.SelectedItem.ToString();

  11:                combo.SelectedItem = null;

  12:            }

  13:        }

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

Leave a Reply

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

תגובה אחת

  1. NFC30 בMay 2013 ב 2:01

    good article . you the man

    Reply