Le réseau pour les développeurs >
Forums - Accueil
>
Windows Presentation Foundation (WPF)
>
Using ComboBox with ViewModel Pattern does not work?
Using ComboBox with ViewModel Pattern does not work?
- Hi,
I'm trying to control which ComboBoxItem in a ComboBox is selected by setting the IsSelected property of the underlying data items that ComboBox's ItemsSource points to. In other words, I want the ComboBox to work similar to the TreeView in Josh Smith's excellent example found here: Simplifying the WPF TreeView by Using the ViewModel Pattern
However when I try to do this, the ComboBox fails to show the item that is selected according to the underlying data! But strangely enough, when I drop down the ComboBox, the correct item is pre-selected. So now I wonder why the ComboBox won't show the selected item until the drop down is expanded, and if there is any way to make the ComboBox display the selected item before this?
I have included an example below. In the example the ComboBox is supposed to display a number of items of the Person class. The Person class has an IsSelected property which is supposed to control which Person is selected in the ComboBox. Therefore the ComboBox.ItemsContainerStyle binds the Person's IsSelected property to the corresponding ComboBoxItem's IsSelected property.
I would have expected the Person instance with Name="Mike" to be shown as selected in the ComboBox, but it's not. And that's what I want to fix! Any suggestions are welcome.
See XAML code below:<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" x:Name="Window"> <StackPanel> <ComboBox ItemsSource="{Binding Path=Persons, ElementName=Window}" DisplayMemberPath="Name"> <!-- Bind ComboBoxItem's IsSelected to underlying Person's IsSelected -->
<ComboBox.ItemContainerStyle><Style TargetType="{x:Type ComboBoxItem}"> <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/> </Style> </ComboBox.ItemContainerStyle> </ComboBox> </StackPanel> </Window>
And the code behind:using System.Windows; using System.Collections.ObjectModel; using System.ComponentModel; namespace WpfApplication1 { public partial class Window1 : Window { public ObservableCollection<Person> Persons { get { return (ObservableCollection<Person>)GetValue(PersonsProperty); } set { SetValue(PersonsProperty, value); } } public static readonly DependencyProperty PersonsProperty = DependencyProperty.Register("Persons", typeof(ObservableCollection<Person>), typeof(Window1)); public Window1() { InitializeComponent(); // Create Persons. Pre-select the person named "Mike". Persons = new ObservableCollection<Person>()
{ new Person("John", false), new Person("Mike", true) };} } public class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public string Name { get; set; } private bool isSelected; public bool IsSelected { get { return isSelected; } set { if (value != isSelected) { isSelected = value; OnPropertyChanged("IsSelected"); } } } public Person(string name, bool isSelected) { Name = name; IsSelected = isSelected; } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } } - ModifiéJohn Fredman_ jeudi 4 septembre 2008 14:21Clarification.
- ModifiéJohn Fredman_ jeudi 4 septembre 2008 14:22Misspelled.
- ModifiéJohn Fredman_ jeudi 4 septembre 2008 14:25Misspelled.
- ModifiéJohn Fredman_ jeudi 4 septembre 2008 14:42Fixed formatting.
Réponses
- This is expected, because the ItemContainerStyle will be applied only when the container aka ComboBoxItem is generated which happens when you open the ComboBox dropdown menu, to workaround this issue, you could try define another dependency property called SelectedPerson, and let the ComoBox's SelectedValue property bind to SelectedPerson property as follows:
<StackPanel>
<ComboBox
ItemsSource="{Binding Path=Persons, ElementName=Window}"
SelectedValue="{Binding Path=SelectedPerson, ElementName=Window}"
DisplayMemberPath="Name">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</StackPanel>
public partial class Window1 : Window
{
public ObservableCollection<Person> Persons
{
get { return (ObservableCollection<Person>)GetValue(PersonsProperty); }
set { SetValue(PersonsProperty, value); }
}
public object SelectedPerson
{
get { return (object)GetValue(SelectedPersonProperty); }
set { SetValue(SelectedPersonProperty, value); }
}
public static readonly DependencyProperty SelectedPersonProperty =
DependencyProperty.Register("SelectedPerson", typeof(object), typeof(Window1), new UIPropertyMetadata(null));
public static readonly DependencyProperty PersonsProperty =
DependencyProperty.Register("Persons", typeof(ObservableCollection<Person>), typeof(Window1));
public Window1()
{
InitializeComponent();
// Create Persons. Pre-select the person named "Mike".
Persons = new ObservableCollection<Person>() { new Person("John", false), new Person("Mike", true) };
SelectedPerson = Persons[1];
}
}
Hope this helps
- Marqué comme réponseMarco Zhou mercredi 10 septembre 2008 09:50
- Marqué comme réponseMarco Zhou mercredi 10 septembre 2008 09:49
Toutes les réponses
- This is expected, because the ItemContainerStyle will be applied only when the container aka ComboBoxItem is generated which happens when you open the ComboBox dropdown menu, to workaround this issue, you could try define another dependency property called SelectedPerson, and let the ComoBox's SelectedValue property bind to SelectedPerson property as follows:
<StackPanel>
<ComboBox
ItemsSource="{Binding Path=Persons, ElementName=Window}"
SelectedValue="{Binding Path=SelectedPerson, ElementName=Window}"
DisplayMemberPath="Name">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</StackPanel>
public partial class Window1 : Window
{
public ObservableCollection<Person> Persons
{
get { return (ObservableCollection<Person>)GetValue(PersonsProperty); }
set { SetValue(PersonsProperty, value); }
}
public object SelectedPerson
{
get { return (object)GetValue(SelectedPersonProperty); }
set { SetValue(SelectedPersonProperty, value); }
}
public static readonly DependencyProperty SelectedPersonProperty =
DependencyProperty.Register("SelectedPerson", typeof(object), typeof(Window1), new UIPropertyMetadata(null));
public static readonly DependencyProperty PersonsProperty =
DependencyProperty.Register("Persons", typeof(ObservableCollection<Person>), typeof(Window1));
public Window1()
{
InitializeComponent();
// Create Persons. Pre-select the person named "Mike".
Persons = new ObservableCollection<Person>() { new Person("John", false), new Person("Mike", true) };
SelectedPerson = Persons[1];
}
}
Hope this helps
- Marqué comme réponseMarco Zhou mercredi 10 septembre 2008 09:50
- Marqué comme réponseMarco Zhou mercredi 10 septembre 2008 09:49

