What is the easiest way to handle SelectedItem event with MVVM?

17,752

Solution 1

You should be able to bind a property in you ViewModel to the SelectedItem property of the combobox. If you set this up as two way binding you will be notified when the SelectedItem is changed because it will trigger the set method on the property.

ViewModel:

public ObservableCollection Customers
{
   get { return _customers; }
   set
   {
       if (_customers != value)
       {
           _customers = value;
           OnPropertyChanged("Customers");
       }
   }
}

public Customer SelectedCustomer
{
   get { return _selectedCustomer; }
   set
   {
       if (_selectedCustomer != value)
       {
           _selectedCustomer= value;
           LastName= value.LastName;
           OnPropertyChanged("SelectedCustomer");
       }
   }
}

public Customer LastName
{
   get { return _lastName; }
   set
   {
       if (_lastName!= value)
       {
           _lastName= value;
           OnPropertyChanged("LastName");
       }
   }
}

Xaml:

<DockPanel LastChildFill="False" Margin="10">
    <ComboBox 
        x:Name="CustomerList"
        ItemTemplate="{StaticResource CustomerTemplate}"
        HorizontalAlignment="Left"
        DockPanel.Dock="Top" 
        Width="200"
        SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}"
        ItemsSource="{Binding Customers}"/>

    <TextBlock x:Name="CurrentlySelectedCustomer"
               Text="{Binding LastName}"/>
</DockPanel>

Solution 2

Have a look at this application on www.codeproject.com. Here I use the CollectionView to detect the currently selected item

Update

Using CollectionView to detect current selected item

ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(Customers); 
view.CurrentChanged += delegate 
{ 
    SelectedCustomer= (Customer)view.CurrentItem; 
};

Just remember to also set IsSynchronizedWithCurrentItem="True"

Share:
17,752
Angry Dan
Author by

Angry Dan

web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info

Updated on June 11, 2022

Comments

  • Angry Dan
    Angry Dan almost 2 years

    In the code below, when user selects Customer in the combobox, the customer's name is displayed in a textbox. I fill the Combox box with an ObservableCollection property on my ViewModel but how do I handle the SelectedItem event in my ViewModel?

    It's easy to implement this with code-behind as shown below, but how do I do this with the MVVM pattern?

    I currently have DelegateCommand and AttachedBehaviors in my basic MVVM template that I can use, but I can't figure out how to get them to fire when "combobox selects a new item".

    View:

    <Window.Resources>
        <DataTemplate x:Key="CustomerTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding LastName}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    
    <DockPanel LastChildFill="False" Margin="10">
        <ComboBox 
            x:Name="CustomerList"
            ItemTemplate="{StaticResource CustomerTemplate}"
            HorizontalAlignment="Left"
            DockPanel.Dock="Top" 
            Width="200"
            SelectionChanged="CustomerSelected"
            ItemsSource="{Binding Customers}"/>
    
        <TextBlock x:Name="CurrentlySelectedCustomer"/>
    </DockPanel>
    

    Code Behind:

    private void CustomerSelected(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        Customer customer = (Customer)CustomerList.SelectedItem;
        CurrentlySelectedCustomer.Text = String.Format("{0} {1}", customer.FirstName, customer.LastName);
    }
    
  • Angry Dan
    Angry Dan almost 15 years
    exactly what I was looking for, didn't know it was so simple, thanks
  • rudigrobler
    rudigrobler almost 15 years
    Just remember that this puts a dependency between your V/VM... If you test this code without the view, the CurrentlySelectedCustomer will never update! If you use the CollectionView... It will work even if your view do not bind back to the VM!
  • Martin Harris
    Martin Harris almost 15 years
    In general I agree there are advantages to a CollectionView (although there are some provisos when you want to bind the same list to multiple selectors), but I don't think your comment is correct. There is no more dependency in my version than yours, for example if I wanted to write a test to check that the LastName property updates correctly I don't need a view, I can just set the SelectedCustomer property through the test code.
  • rudigrobler
    rudigrobler almost 15 years
    Agreed... both will definetly work! The only other problem I can see is that if you want to use a deffirent view... you have to remeber to bind back to the selected item! My approach has a simillar problem because in my view you have to remeber to set the IsSyncronizedWithCurrent to true! I definetely like your sulotion and in some cases it will definetely work I just don't like to be dependent on the view... Using the CV is just a little more de-coupled!
  • HolySamosa
    HolySamosa about 11 years
    +1 for mentioning the need for IsSynchronizedWithCurrentItem="True". After an hour of trying to figure out why CurrendChanged was never being fired in my code you have saved the day.