views:

64

answers:

1

Question: Can anyone please provide a full code example that shows how one does programmatically change the SelectedItem of a data-bound WPF ComboBox without using MyComboBox.SelectedIndex?

Code sample: Here is what I currently have.

XAML:

<Window x:Class="Wpf.ComboBoxDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ComboBox Name="MyComboBox" DisplayMemberPath="LastName" SelectedIndex="0"/>
    </Grid>
</Window>

Code-behind:

using System.Collections.ObjectModel;
using System.Windows;

namespace Wpf.ComboBoxDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            ObservableCollection<Person> myPersonList = new ObservableCollection<Person>();

            Person personJobs = new Person("Steve", "Jobs");
            Person personGates = new Person("Bill", "Gates");

            myPersonList.Add(personJobs);
            myPersonList.Add(personGates);

            MyComboBox.ItemsSource = myPersonList;

            // How do I programmatically select the second Person, i.e. "Gates"?
            // The best pratice must be to somehow to set something like IsCurrentlySelected on the model, so the view update automatically. But how?
            MyComboBox.SelectedIndex = 1; // This works, but is there no way without using the index?

        }

        private class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }

            public Person(string firstName, string lastName)
            {
                FirstName = firstName;
                LastName = lastName;
            }
        }
    }
}

Similar questions: I have of course searched the Internet first, but found nothing that helped me.

  • Changing the SelectedItem of a enum-bound combobox inside ViewModel (MSDN)
  • Programmatically set ComboBox SelectedItem in WPF (3.5sp1) (Stack Overflow)
+1  A: 

At the top of my head (I might be wrong), make the window implement INotifyPropertyChanged and add the event:

namespace Wpf.ComboBoxDemo
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindow()
        {

Then add a property for the currently selected item which notifies on changes:

        private Person _selected;
        public Person MySelected
        {
            get { return _selected; }
            set
            {
                if (value != _selected)
                {
                    _selected = value;            
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this,
                            new PropertyChangedEventArgs("MySelected"));
                    }
                }
            }
        }

Now bind the combobox (the binding could be more advanced here using FindAncestor but sometimes to keep things simple I put the datacontext in code behind):

XAML:

        <ComboBox
            Name="MyComboBox"
            DisplayMemberPath="LastName"
            SelectedItem="{Binding MySelected}" />

Code behind:

    public MainWindow()
    {
        InitializeComponent();
        // ...

        // this will cause the "MySelected" binding to target the correct property on this object
        MyComboBox.DataContext = this;
    }

I think it goes something like that. I cant test it right now but hopefully it will nudge you in the right direction.

Edit: If you want to try the "other way" of binding heres how. Expand the SelectedItem binding to look like this:

        <ComboBox
            Name="MyComboBox"
            DisplayMemberPath="LastName"
            SelectedItem="{Binding MySelected,
                RelativeSource={RelativeSource FindAncestor,
                    AncestorType={x:Type Window}}}" />

You can now skip setting the DataContext in code behind:

    public MainWindow()
    {
        InitializeComponent();
        // ...

        // this will cause the "MySelected" binding to target the correct property on this object
        //MyComboBox.DataContext = this;
    }

This is because that FindAncestor mode makes the ComboBox itself find the object to which property it should bind, rather than you specifically stating.

The current hot topic here at the office is which of these two ways are the best. To me its just more XAML and less code behind (or the other way around), just use the method that places the code where youre comfortable to work. I think there are some scenarios where the latter is preferred (like when you include data binding controls inside other controls), but Im just dabbling so I havent really figured those parts out yet.

mizipzor
@mizipzor: Great nudge, thanks a lot for your help!
Lernkurve
Glad I could help. :) I added the second method of binding, if you want to try it out. That code isnt tested either so I hope I got some luck left.
mizipzor
@mizipzor: Now I am torn between this.DataContext = myPersonlist (which doesn't need the ComboBox to have a name) and your FindAncestor approach which needs no code-behind at all.
Lernkurve