SelectedItem and SelectedValue returns the wrong item - c#

I have List<string> MyList with 4 values. These are shown in a ComboBox control. The binding works perfectly in my MVVM WPF project.
I also have a string SelectedMyList which binds to my XAML and is supposed to show the selected item. The problem I have is, regardless of using SelectedItem or SelectedValue, it always passes the first item in MyList
private MyClass()//constructor
{
MyList = new List<string>() {"Hi", "Bye", "Hello", "See ya"};
}
private string _selectedMyList;
public string SelectedMyList
{
get
{
return this._selectedMyList;
}
set
{
//value is always Hi
if (this._selectedMyList== value)
return;
this._selectedMyList= value;
OnPropertyChanged("SelectedMyList");
}
}
private List<string> _myList;
public List<string> MyList
{
get
{
return this._myList;
}
set
{
if (this._myList== value)
return;
this._myList= value;
OnPropertyChanged("MyList");
}
}
And my XAML
<ComboBox ItemsSource="{Binding MyList}" SelectedValue="{Binding SelectedMyList, UpdateSourceTrigger=PropertyChanged}" />
There are no errors/binding errors etc in the output window.
Why does the SelectedItem/SelectedValue not pass what I consider to be the selected item from the ComboBox?

This works for me.
private string _selectedMyList;
public string SelectedMyList
{
get
{
return this._selectedMyList;
}
set
{
//value is always Hi
if (this._selectedMyList != value)
{
this._selectedMyList= value;
OnPropertyChanged("SelectedMyList");
}
}
}
private List<ObservableCollection> _myList;
public ObservableCollection<string> MyList
{
get
{
return this._myList;
}
set
{
if (this._myList== value)
{
this._myList= value;
OnPropertyChanged("MyList");
}
}
}
Xaml:
<ComboBox ItemsSource="{Binding MyList}"
SelectedItem="{Binding SelectedMyList}"
IsSynchronizedWithCurrentItem="True"/>

If you want to use the SelectedValue attribute then you need to use it with the SelectedValuePath attribute. See this link to a similar question.

Related

How to capture the value from ComboBox in ViewModel

I'm trying to capture the value of the selected item from a ComboBox in my ViewModel. I do get the value but for some reason, when I do a string comparison in an IF statement to determine which item has been selected the comparison doesn't work.
What am I missing?
Is this the right way to capture the value in ViewModel?
XAML
<ComboBox x:Name="comboBox"
SelectedItem="{Binding SelectedItemInFilter, UpdateSourceTrigger=PropertyChanged}>
<ComboBoxItem IsSelected="True">No Selection</ComboBoxItem>
<ComboBoxItem>Car</ComboBoxItem>
<ComboBoxItem>Truck</ComboBoxItem>
</ComboBox>
ViewModel
public class MyViewModel : ViewModelBase{
public string _selectedItemInFilter;
public string SelectedItemInFilter
{
get { return _selectedItemInFilter; }
set {
if (_selectedItemInFilter != value) {
_selectedItemInFilter = value;
ComboBoxChanged();
Console.WriteLine("SelectedItem: {0}", SelectedItemInFilter); // outputs the right item name
RaisePropertyChanged();
}
}
}
private void ComboBoxChanged()
{
if (SelectedItemInFilter.ToString() == "Car") {
Console.WriteLine("Do something with car...");
}
else {
Console.WriteLine("Is not Car...");
}
}
}
Since you explicitly add ComboBoxItems (instead of setting or binding the ItemsSource to a collection of strings), the SelectedItem also is a ComboBoxItem, and not a string. You may however bind to the Content string of the selected item by using SelectedValue and SelectedValuePath:
<ComboBox SelectedValue="{Binding SelectedItemInFilter}"
SelectedValuePath="Content">
<ComboBoxItem>No Selection</ComboBoxItem>
<ComboBoxItem>Car</ComboBoxItem>
<ComboBoxItem>Truck</ComboBoxItem>
</ComboBox>
Even simpler would be not to use ComboBoxItems at all:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
...
<ComboBox SelectedItem="{Binding SelectedItemInFilter}">
<sys:String>No Selection</sys:String>
<sys:String>Car</sys:String>
<sys:String>Truck</sys:String>
</ComboBox>
You are getting it wrong because the items aren't really strings, if you need to do this way you could do the following:
public object _selectedItemInFilter;
public object SelectedItemInFilter
{
get
{
return _selectedItemInFilter;
}
set
{
if (_selectedItemInFilter != value)
{
_selectedItemInFilter = value;
ComboBoxChanged();
Console.WriteLine("SelectedItem: {0}", SelectedItemInFilter); // outputs the right item name
NotifyPropertyChanged("SelectedItemInFilter");
}
}
}
private void ComboBoxChanged()
{
if (((ComboBoxItem)SelectedItemInFilter).Content.ToString() == "Car")
{
Console.WriteLine("Do something with car...");
}
else
{
Console.WriteLine("Is not Car...");
}
}
It's not the same to bind an ObservableCollection than declaring the items into the ComboBox control.

Add combobox text to its Itemssource

I have a combobox binded to a table called Tenderness through MVVM. I'm using Entity Framework.It displays all the records properly, but I need to add another functionality to it. Suppose the user types in text which is not contained inside the combobox's Itemssource, I want to be able to add it directly to the table and then update the Itemssource as well. Now I have been able to do this without MVVM, I would want to know, how to achieve it using MVVM.
Just do what you did previously in the LostFocus event handler in the setter of a source property that you bind to the Text property of the ComboBox.
View Model:
public ObservableCollection<string> Items { get; } = new ObservableCollection<string>() { "a", "b", "c" };
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged(nameof(Text));
//add the missing value...
if (!Items.Contains(_text))
Items.Add(_text);
}
}
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged(nameof(SelectedItem));
}
}
View:
<ComboBox IsEditable="True" Text="{Binding Text, UpdateSourceTrigger=LostFocus}" ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}" />

WPF binding to an already bound property

What can I do if I want to bind to some property which is already bound to something else?
In my case, I got a window which has a TextBox. The Text property of this TextBox is data bound to a combo box to it's selectedItem. My Window class got a public string property which I want to update with whatever value is in the TextBox so I wanted to data bind with the Text property but as I said, it's already bound.
How can I update my property with the text in TextBox? Must it use a routed event of TextChanged or can I do it via Xaml?
Also specifically with properties you define them yourself in your window.cs ... how can you bind them to the TextBox.Text? I tried doing it with the <Window> declaration, meaning <Window MyProperty={Binding ...} /> but the property is not recognized there. Why and how do I do it?
You could solve this easily using the MVVM pattern.
ViewModel:
public class ChooseCategoryViewModel : ViewModelBase
{
private string[] _categories =
{ "Fruit", "Meat", "Vegetable", "Cereal" };
public string[] Categories
{
get { return _categories; }
}
private string _selectedCategory;
public string SelectedCategory
{
get { return _selectedCategory; }
set
{
_selectedCategory = value;
OnPropertyChanged("SelectedCategory");
if (value != null && CategoryName != value)
CategoryName = value;
}
}
private string _categoryName;
public string CategoryName
{
get { return _categoryName; }
set
{
_categoryName = value;
OnPropertyChanged("CategoryName");
if (Categories.Contains(value))
{
SelectedCategory = value;
}
else
{
SelectedCategory = null;
}
}
}
}
XAML:
<ComboBox ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory}" />
<TextBox Text="{Binding CategoryName}" />

Combo box binding in mvvm

I am not able to find out Why is combo box binding not working?
I have a view model which looks like (2 properties)
public ProcessMaintenanceDataObject CurrentProcess
{
get
{
return _CurrentProcess;
}
set
{
_CurrentProcess = value;
OnPropertyChanged("CurrentProcess");
}
}
public ObservableCollection<ProcessMaintenanceDataObject > Processes
{
get
{
return _Processes;
}
set
{
_Processes = value;
OnPropertyChanged("Processes");
}
}
public ObservableCollection<FolderInfo> Folders
{
get
{
return _folders;
}
set
{
_folders = value;
OnPropertyChanged("Folders");
}
}
The following is the ProcessMaintenanceDataObject definition
[DataMember]
public string ProcessName
{
get
{
return _ProcessName;
}
set
{
_ProcessName = value;
OnPropertyChanged("ProcessName");
}
}
[DataMember]
public string Id
{
get
{
return _Id;
}
set
{
_Id = value;
OnPropertyChanged("Id");
}
}
[DataMember]
public string FolderId
{
get
{
return _FolderId;
}
set
{
_FolderId = value;
OnPropertyChanged("FolderId");
}
}
[DataMember]
public FolderInfo Folder
{
get
{
return _Folder;
}
set
{
_Folder = value;
if (_Folder != null)
FolderId = _Folder.FolderId;
OnPropertyChanged("Folder");
}
}
The FolderInfo class has FolderName and FolderId Property.
I have a method in viewmodel which fills the Processes.
In my view I have structure something like, I have a treeview which will be bound to Processes and while selecting any of the item from the treeview, i need to allow user to edit that entity.
In the view the combo box binding is as:
<ComboBox ItemsSource="{Binding Path=Folders, Mode=OneWay}"
DisplayMemberPath="FolderName"
SelectedItem="{Binding Source={StaticResource viewModel}, Path=CurrentProcess.Folder, Mode=TwoWay}">
...
This binding doesn't work I mean when I select any object from the tree it fills other information like ProcesName in the textBox but it doesn't make the Folder object as the selected item in combobox, however the combo box will be filled.
Any suggestion.
Do refer this:
If you want to bind a ComboBox to your folders property in two way mode with edit support,
Then you should define data template for your combo box and then bind properties of FolderInfo class to those text boxes
Binding display member path will not solve your problem
I'd suggest you to change DisplayMemberPath with appropriate DataTemplate:
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FolderName}">
</StackPanel>
<DataTemplate>
This will fix SelectedItem context.
Maybe just maybe, your Folderinfo class is not a notificationObject. If it is the case make sure it implements INotifyPropertyChange.
you have to use SelectedValuePath and SelectedValue instead of SelectedItem like below,
<ComboBox ItemsSource="{Binding Path=Folders, Mode=OneWay}"
DisplayMemberPath="FolderName"
SelectedValuePath="FolderId"
SelectedValue="{Binding Path=FolderId, Mode=TwoWay}">
SelectedItem binds the whole object whereas SelectedValue binds only particular properties of the object.

combobox databinding to selectedvalue event

I want to execute some function when user selects a different value in the combo box.
I am using MVVM pattern .
Any Idea how I Data Bind in this case ?
bind to a property on SelectedItem.
in the property's setter, execute your function.
SelectedItem="{Binding Path=SomeProperty}"
You'd want to either bind to the SelectedValue, SelectedItem, or SelectedIndex depending on what you want to do:
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<MyObj> MyCollection { get; private set; }
private MyObj _theItem;
public MyObj TheItem
{
get { return _theItem; }
set
{
if (Equals(value, _theItem)) return;
_theItem= value;
//Or however else you implement this...
OnPropertyChanged("TheItem");
//Do something here.... OR
//This will trigger a PropertyChangedEvent if you're subscribed internally.
}
}
private string _theValue;
public string TheValue
{
get { return _theValue; }
set
{
if (Equals(value, _theValue)) return;
_theValue= value;
OnPropertyChanged("TheValue");
}
}
private int _theIndex;
public int TheIndex
{
get { return _theIndex; }
set
{
if (Equals(value, _theIndex)) return;
_theIndex = value;
OnPropertyChanged("TheIndex");
}
}
}
public class MyObj
{
public string PropA { get; set; }
}
<!-- Realistically, you'd only want to bind to one of those -->
<!-- Most likely the SelectedItem for the best usage -->
<ItemsControl ItemsSource="{Binding Path=MyCollection}"
SelectedItem="{Binding Path=TheItem}"
SelectedValue="{Binding Path=TheValue}"
SelectedIndex="{Binding Path=TheIndex}"
/>

Categories

Resources