WPF - MVVM - ComboBox SelectedItem
Solution 1
The category you are setting in this line -
NodeCategory = some_list_of_other_objects.Category;
and one present in your Categories collection(ItemsSource="{Binding Categories}"
) should be referring to same object. If they are not then SelectedItem
won't work.
Solution 1 -
You can also try to use SelectedValuePath
like this -
<ComboBox x:Name="categoryComboBox"
ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding NodeCategory, Mode=TwoWay}" />
and in code you can do something like this -
private string _NodeCategory;
public string NodeCategory
{
get
{
return _NodeCategory;
}
set
{
_NodeCategory = value;
OnPropertyChanged("NodeCategory");
}
}
and set selected item like this -
NodeCategory = some_list_of_other_objects.Category.Name;
and use selected value like this -
Category selectedCategory =
some_list_of_other_objects.FirstOrDefault(cat=> cat.Name == NodeCategory);
or
Category selectedCategory =
Categories.FirstOrDefault(cat=> cat.Name == NodeCategory);
Solution 2 -
Another possible solution can be -
NodeCategory =
Categories.FirstOrDefault(cat=> cat.Name == some_list_of_other_objects.Category.Name);
this way your NodeCategory
property will have the reference of an object in Categories
collection and SelectedItem
will work.
Solution 2
Your XAML needs a couple of modifications but I think the real problem is with the code you have posted which I don't think is telling the full story.
For starters, your combobox ItemSource
is bound to a property called Categories but you do not show how this property is coded or how your NodeCategory
property is initially synced with the item.
Try using the following code and you will see that the selected item is kept in sync as the user changes the value in the combobox.
XAML
<Window x:Class="WpfApplication1.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">
<StackPanel>
<ComboBox x:Name="categoryComboBox"
Grid.Column="1"
Grid.Row="3"
Grid.ColumnSpan="2"
Margin="10"
ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedItem="{Binding NodeCategory}" />
<Label Content="{Binding NodeCategory.Name}" />
</StackPanel>
Code-behind
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<Category> _categories = new ObservableCollection<Category>
{
new Category { Name = "Squares"},
new Category { Name = "Triangles"},
new Category { Name = "Circles"},
};
public MainWindow()
{
InitializeComponent();
NodeCategory = _categories.First();
this.DataContext = this;
}
public IEnumerable<Category> Categories
{
get { return _categories; }
}
private Category _NodeCategory;
public Category NodeCategory
{
get
{
return _NodeCategory;
}
set
{
_NodeCategory = value;
OnPropertyChanged("NodeCategory");
}
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
[Serializable]
public class Category : INotifyPropertyChanged
{
private string _Name;
[XmlAttribute("Name")]
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
}
Solution 3
From my little example:
Note: This is setting just a string (or a category from another list), but the basics should be same here:
Basically this is done:
private void button1_Click(object sender, RoutedEventArgs e)
{
(this.DataContext as ComboBoxSampleViewModel).SelectCategory("Categorie 4");
}
Here is my XAML:
<Grid>
<ComboBox Height="23" HorizontalAlignment="Left" Margin="76,59,0,0"
Name="comboBox1" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding List.Categories}"
DisplayMemberPath="Name"
SelectedValue="{Binding NodeCategory, Mode=TwoWay}" />
<Button Content="Button" Height="27" HorizontalAlignment="Left"
Margin="76,110,0,0" Name="button1" VerticalAlignment="Top"
Width="120" Click="button1_Click" />
</Grid>
and in the ViewModel of the Window
class ComboBoxSampleViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public CategoryList List { get; set; }
public ComboBoxSampleViewModel()
{
this.List = new CategoryList();
NodeCategory = List.Selected;
}
private ComboBoxSampleItemViewModel nodeCategory;
public ComboBoxSampleItemViewModel NodeCategory
{
get
{
return nodeCategory;
}
set
{
nodeCategory = value;
NotifyPropertyChanged("NodeCategory");
}
}
internal void SelectCategory(string p)
{
this.List.SelectByName(p);
this.NodeCategory = this.List.Selected;
}
}
With the help of this little class:
public class CategoryList
{
public ObservableCollection<ComboBoxSampleItemViewModel> Categories { get; set; }
public ComboBoxSampleItemViewModel Selected { get; set; }
public CategoryList()
{
Categories = new ObservableCollection<ComboBoxSampleItemViewModel>();
var cat1 = new ComboBoxSampleItemViewModel() { Name = "Categorie 1" };
var cat2 = new ComboBoxSampleItemViewModel() { Name = "Categorie 2" };
var cat3 = new ComboBoxSampleItemViewModel() { Name = "Categorie 3" };
var cat4 = new ComboBoxSampleItemViewModel() { Name = "Categorie 4" };
Categories.Add(cat1);
Categories.Add(cat2);
Categories.Add(cat3);
Categories.Add(cat4);
this.Selected = cat3;
}
internal void SelectByName(string p)
{
this.Selected = this.Categories.Where(s => s.Name.Equals(p)).FirstOrDefault();
}
}
And this Item ViewModel
public class ComboBoxSampleItemViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
NotifyPropertyChanged("Name");
}
}
}
Related videos on Youtube
Bip
Updated on July 09, 2022Comments
-
Bip almost 2 years
I have
ViewModel
(implementedINotifyPropertyChanged
) in the background and classCategory
which has only one property of typestring
. My ComboBox SelectedItem is bind to an instance of a Category. When i change the value of instance, SelectedItem is not being updated and Combobox is not changed.EDIT: code
Combobox:
<ComboBox x:Name="categoryComboBox" Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="2" Margin="10" ItemsSource="{Binding Categories}" DisplayMemberPath="Name" SelectedValue="{Binding NodeCategory, Mode=TwoWay}"/>
Property:
private Category _NodeCategory; public Category NodeCategory { get { return _NodeCategory; } set { _NodeCategory = value; OnPropertyChanged("NodeCategory"); } } [Serializable] public class Category : INotifyPropertyChanged { private string _Name; [XmlAttribute("Name")] public string Name { get { return _Name; } set { _Name = value; OnPropertyChanged("Name"); } } public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } [field:NonSerialized] public event PropertyChangedEventHandler PropertyChanged; }
and what I am trying is: when I set
NodeCategory = some_list_of_other_objects.Category;
to have that item selected in
Combobox
with appropriateDisplayMemberPath
-
Mare Infinitus almost 12 yearsCan you post some code please, especially xaml
-
Andy almost 12 yearsDoes binding the SelectedItem property work instead of selected value?
-
Andy almost 12 yearsTry adding the update source trigger to your bindings UpdateSourceTrigger=PropertyChanged
-
Bip almost 12 yearsi've edited the post again with explanation at the end.
-
Bip almost 12 yearstried that already :) no success :/ because i change the value in the backend
-
Mare Infinitus almost 12 yearsyou want to have an item selected by an external list? i have a small sample on how to achieve this... one moment
-
-
Mare Infinitus almost 12 yearsThats exactly what i wanted to post now.
-
Bip almost 12 yearslet me explain a bit more. I have list of categories. Category1, Category2...etc. I have a datagrid right near it and i clicked datagrid row. Ok. Now, when i clicked it everything else is populated with its data(i have few textboxes) BUT combobox selected item is blank
-
Bip almost 12 yearsit is impossible in this stage of project to add logics to UI, sorry. But tnx for answer. voted up :)
-
akjoshi almost 12 years@PredragPejic in case your ComboBox and DataGrid are two different lists, having different objects then using SelectedValuePath would be a good option.
-
akjoshi almost 12 years@PredragPejic Added another solution which won't require you to make much changes in your current code.
-
Bip almost 12 yearsthat is not the issue. the issue is because NodeCategory has been changed, but the combobox selected item is not obviously.
-
akjoshi almost 12 yearsYes, because the Category
object
present in NodeCategory is not present in Categories(bound to ComboBox) collection. -
Bip almost 12 yearsthank you man, it is working now. i changed SelectedValue to SelectedItem and removed SelectedValuePath. i will buy you a beer if we ever meet :D cheers!
-
akjoshi almost 12 years@PredragPejic Thanks, Glad it helped.
-
Mare Infinitus almost 12 yearsokay, no problem. the solution is very similar as far as i can see
-
Bahamut over 11 yearsThank you so much. Not setting the SelectedValuePath screwed me up, but with your help i got it working =)
-
akjoshi over 11 years@Bahamut Glad it helped you :)
-
afterxleep over 7 yearsThis answer enabled me to get going so +1. For a start-to-finish example, I've blogged about it here: technical-recipes.com/2017/…
-
Luca Ziegler over 6 yearsYes DisplayMemberPath is indispensable when you use objects
-
scsfdev over 6 years"should be referring to same object" save my day! Thanks for the info.