What is the difference betweeen the following:
SelectedItem
SelectedValue
SelectedValuePath
All these dependency properties are defined in Selector class. I often confuse SelectedItem with SelectedValue , and SelectedValue with SelectedValuePath.
I would like to know the difference between them, and also when do we use them, especially SelectedValue and SelectedValuePath. Please explain their use with some simple examples.
Their names can be a bit confusing :). Here's a summary:
The SelectedItem property returns the entire object that your list is bound to. So say you've bound a list to a collection of Category objects (with each Category object having Name and ID properties). eg. ObservableCollection<Category>. The SelectedItem property will return you the currently selected Category object. For binding purposes however, this is not always what you want, as this only enables you to bind an entire Category object to the property that the list is bound to, not the value of a single property on that Category object (such as its ID property).
Therefore we have the SelectedValuePath property and the SelectedValue property as an alternative means of binding (you use them in conjunction with one another). Let's say you have a Product object, that your view is bound to (with properties for things like ProductName, Weight, etc). Let's also say you have a CategoryID property on that Product object, and you want the user to be able to select a category for the product from a list of categories. You need the ID property of the Category object to be assigned to the CategoryID property on the Product object. This is where the SelectedValuePath and the SelectedValue properties come in. You specify that the ID property on the Category object should be assigned to the property on the Product object that the list is bound to using SelectedValuePath='ID', and then bind the SelectedValue property to the property on the DataContext (ie. the Product).
The example below demonstrates this. We have a ComboBox bound to a list of Categories (via ItemsSource). We're binding the CategoryID property on the Product as the selected value (using the SelectedValue property). We're relating this to the Category's ID property via the SelectedValuePath property. And we're saying only display the Name property in the ComboBox, with the DisplayMemberPath property).
<ComboBox ItemsSource="{Binding Categories}"
SelectedValue="{Binding CategoryID, Mode=TwoWay}"
SelectedValuePath="ID"
DisplayMemberPath="Name" />
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Product
{
public int CategoryID { get; set; }
}
It's a little confusing initially, but hopefully this makes it a bit clearer... :)
Chris
To answer a little more conceptually:
SelectedValuePath defines which property (by its name) of the objects bound to the ListBox's ItemsSource will be used as the item's SelectedValue.
For example, if your ListBox is bound to a collection of Person objects, each of which has Name, Age, and Gender properties, SelectedValuePath=Name will cause the value of the selected Person's Name property to be returned in SelectedValue.
Note that if you override the ListBox's ControlTemplate (or apply a Style) that specifies what property should display, SelectedValuePath cannot be used.
SelectedItem, meanwhile, returns the entire Person object currently selected.
(Here's a further example from MSDN, using TreeView)
Update: As #Joe pointed out, the DisplayMemberPath property is unrelated to the Selected* properties. Its proper description follows:
Note that these values are distinct from DisplayMemberPath (which is defined on ItemsControl, not Selector), but that property has similar behavior to SelectedValuePath: in the absence of a style/template, it identifies which property of the object bound to item should be used as its string representation.
SelectedItem and SelectedValue are an object.
and SelectedValuePath is a string.
for example using the ListBox:
Below listbox1.SelectedValue becomes a string value.
string value = listbox1.SelectedValue;
if you say give me listbox1.SelectedItem it will give you the entire object.
ListItem item = listbox1.SelectedItem;
string value = item.value;
inspired by this question I have written a blog along with the code snippet here. Below are some of the excerpts from the blog
SelectedItem – Selected Item helps to bind the actual value from the DataSource which will be displayed. This is of type object and we can bind any type derived from object type with this property. Since we will be using the MVVM binding for our combo boxes in that case this is the property which we can use to notify VM that item has been selected.
SelectedValue and SelectedValuePath – These are the two most confusing and misinterpreted properties for combobox. But these properties come to rescue when we want to bind our combobox with the value from already created object. Please check my last scenario in the following list to get a brief idea about the properties.
Every control that uses Collections to store data have SelectedValue, SelectedItem property. Examples of these controls are ListBox, Dropdown, RadioButtonList, CheckBoxList.
To be more specific if you literally want to retrieve Text of Selected Item then you can write:
ListBox1.SelectedItem.Text;
Your ListBox1 can also return Text using SelectedValue property if value has set to that before. But above is more effective way to get text.
Now, the value is something that is not visible to user but it is used mostly to store in database. We don't insert Text of ListBox1, however we can insert it also, but we used to insert value of selected item. To get value we can use
ListBox1.SelectedValue
Source
Related
I create data grid combo box column in wpf, now I want to set value of pairs in it.I want to display full value but selected value path is ID.
Yes you can.
Bind your itemssource to a collection of an object which has two properties. Id and whatever you want to call the other one. Gender maybe.
Genders are going to be completely static, so you could define that as a resource in a resourcedictionary.
Make SelectedValuePath Id
SelectedValueBinding whatever you're setting to ID.
DisplayMemberPath Gender, or whatever you want to call the longer string.
More information here:
https://social.technet.microsoft.com/wiki/contents/articles/26347.wpf-combobox-binding-in-datagrid.aspx
and
https://social.technet.microsoft.com/wiki/contents/articles/19493.wpf-best-combobox-tutorial-ever.aspx
The program is a minidatabase-ish thing for product ordering purposes, where I keep the unique orders in a struct, and the productNames in an enum (for practice basically). I only have 3 productnames (Product0, Product1, Product2), and they are added to a combobox (cbo_productNameEdit.DataSource = Enum.GetNames(typeof(productNames));).
Anyway, after saving an order, I want this combobox to change it's selected item to the saved product's name, but it fails to do so. I checked it with a MessageBox, to see if it didn't store it properly...
MessageBox.Show(Orders[cbo_productID.SelectedIndex].productName.ToString());
cbo_productNameEdit.SelectedItem = Orders[cbo_productID.SelectedIndex].productName;
... the messagebox returned Product2, which is indeed the correct one, but the selected item stayed at Product0.
One thing you could do to solve it is to set the SelectedIndex instead of SelectedItem property on the combobox. By default Enums are 0 based integers, so the index will corespond to the value of the enum.
cbo_productNameEdit.SelectedIndex = (int)Enum.Parse(typeof(productNames),
Orders[cbo_productID.SelectedIndex].productName.ToString());
Because you used .DataSource property for filling ComboBox with items
You need to use .SelectedValue for setting selecting item
cbo_productNameEdit.SelectedValue = Orders[cbo_productID.SelectedIndex].productName;
From MSDN: ComboBox.SelectedValue
In my program I have a comboBox and a listBox. The listBox is full of different commands. The selectedItem and contents of the comboBox depend on which command is selected. The selectedItem in the comboBox stays selected for that command. For example, when the user has content selected in the comboBox and they switch to a different command, and then switch back, the same item will still be selected in the comboBox.
Because the comboBox gets populated with different items depending on which command is selected should I make an ObservableCollection for each set of items? I'm only allowed to bind the ItemsSource to one thing, so how would that work?
If that's not the right approach please advise. If this isn't clear enough, please let me know.
Thanks!
Here's a sample of what my program will look like:
Then, if command 2 is selected, the list in the combo box might be a, b, c, d, e, for example.
You can have a separate ObservableCollection for each listbox command.
When the user selects a new listbox command, set the comboBox.ItemsSource to the appropriate ObservableCollection. That should solve your problem.
Based on your description, the contents of the combobox are tied to the selected item in the listbox. Without knowing any more of the details, seems like your business object would be a “Command” object that contains an ObservableCollection of “SubCommand”? objects. Your application would then contain an Observablecollection of “Command” objects. The listbox would be data bound to the "Command" objects list, and the combobox would be bound to the selected items "SubCommand" collection.
Seems to me you're looking for a Master / Detail structure here:
Data Items:
public class MyCommandDefinition
{
public string DisplayName {get;set;}
public List<MyParameter> Parameters {get;set;}
public Parameter SelectedParameter {get;set;}
}
public class MyParameter
{
public string DisplayName {get;set;}
//Additional properties depending on your needs.
}
ViewModel:
public class MyViewModel
{
public List<MyCommandDefinition> Commands {get;set;}
public MyCommandDefinition SelectedCommand {get;set;}
}
XAML:
<ListBox ItemsSource="{Binding Commands"}"
SelectedItem="{Binding SelectedCommand}"
DisplayMemberPath="DisplayName"/>
<ComboBox ItemsSource="{Binding SelectedCommand.Parameters}"
SelectedItem="{Binding SelectedCommand.SelectedParameter}"
DisplayMemberPath="DisplayName"/>
Don't forget NotifyPropertyChanged() in all these properties if you're going to change them programatically and expect that to be reflected in the UI.
I have the code below
FooCB.DisplayMember = "FooNome";
FooCB.ValueMember = "Foo";
FooCB.DataSource = FooRepository.Instance.All();
FooCB.DataBindings.Add("SelectedItem", Bar, "Foo");
but when I display the form the SelectedItem is always the first.
What am I doing wrong?
I have been struggling a little with the behaviour of Winforms comboboxes and databinding recently and these are my observations (.Net4) when binding the ComboBox.DataSource to a list of items and also binding an object property to ComboBox.SelectedItem.
When binding a list of objects (in your case List<Foo>) to ComboBox.DataSource, the first object in the list is always shown in the combobox.
If you bind an object property to ComboBox.SelectedItem (in your case Bar.Foo) and that object property matches one of the combobox list objects then that object is displayed in the combobox. If the object property is null (Bar.Foo == null) or the object property is not in the combobox list then the first object is shown in the combobox.
Setting ComboBox.SelectedItem = null or ComboBox.SelectedIndex = -1 clears the displayed item on the combobox even though this seems to warn against it. And will set your bound object property to null.
If a user clears the combobox selection when using ComboBox.DropDownStyle == DropDown (with backspace) then the bound object property is set to null.
If you have implemented INotifyPropertyChanged on the object whose property is bound to Combobox.SelectedItem (Bar.Foo) and you programatically set the bound property to a value and that value appears in the combobox list then the changed value will be displayed. If you set the property to null or a value not in the list then the combobox displayed value will not change.
So what can you do about it? The only real issue I have is having no value displayed when my bound property is null so I have just been explicitly setting Combobox.SelectedItem = null as in point #3. You may be able to extend ComboBox and override the default behaviour but so far I have been content with an extra line of code here and there combined with using default values on non-nullable properties.
Probably you are missing some decleration. If you created the Combobox from the Tool Box, -I had the similar problem- you might want to add name of the Combobox's Name as a tag on XAML.
Other than that, if you created it dynamically by code, check if you are missing any decleration for class.
I can't tell from the OP's code whether I'm answering their question, but maybe this will help somebody reading this question. The ComboBox has four ways to set the current value:
SelectedIndex
SelectedItem
SelectedText
SelectedValue
You need to be consistent about what you're setting (and about which event handler you're using). You'll get an error if you set SelectedIndex to something dumb (less than -1 or longer than the list). However, you don't get errors setting the other three to something that doesn't exist for that type of selection.
Suppose you use a Dictionary (that's pseudo code) as a binding source and set DisplayMember = "Value" and ValueMember = "Key", the mapping would look like:
SelectedIndex - -1 to index of last item
SelectedItem - KeyValuePair<Key, Value>
SelectedText - Dictionary value
SelectedValue - Dictionary key
Supplying either value or key to SelectedItem will not generate an error, it will simply act like the OP has described. And that's why I thought this answer might help somebody.
I might also note that, if you're swapping out the contents of the ComboBox, it's not always safe to use SelectedIndex. Suppose the same basic kind of data is in the ComboBox, but selections are limited in some cases compared to others. Using SelectedIndex to persist a previous selection that was still valid in the new list of options is only going work if that previous selection held the exact same place in the list. You'd almost think this was the voice of very, very recent experience speaking...
I'm attempting to take a string value from a Combo box then pass it through an object variable to a class and store it there in a string variable.
private void cboTimeZone_SelectedValueChanged(object sender, EventArgs e)
{
extTime1.timeZone = cboTimeZone.SelectedItem;
}
I'm not totally use to the combo box options to use so.
Does the cboTimeZone contain string objects? In this case, a simple cast should be enough if extTime1.timeZone is a string:
extTime1.timeZone = (string)cboTimeZone.SelectedItem
if cboTimeZone was filled with objects of type myObject, u can use the ToString() method on the item if you overwrote it in your myObject class:
extTime1.timeZone = cboTimeZone.SelectedItem.ToString()
If you selected a specific property MyProperty of myObject to be shown in the combo box, you can first cast to the object and then access the property by using
extTime1.timeZone = ((myObject)cboTimeZone.SelectedItem).MyProperty
to get that property as a result.
Hope that helps.
It's not clear from your question whether your ComboBox is data-bound or not; either way, I think it would be a good idea to first figure out if SelectedItem is indeed the correct property to use, or if there's another, more appropriate one.
If you've set a DataSource for your ComboBox, you've probably also set a DisplayMember. In that case, the DisplayMember will determine which property of the currently selected item of the data source will be shown in the ComboBox as text.
If you've set a ValueMember, you can also use the SelectedValue property to retrieve that property of the currently selected data source item.
SelectedItem simply retrieves the currently selected data source item. This may be a complex object, or a string object, or something else; check with your data source.
The ComboBox's Text property simply contains the text that's currently displayed in the ComboBox's text input field and has type string.