I'm looking to bind a ComboBox created at runtime to a property on the ViewModel.
I've tried something along these lines
combobox.SetBinding(ComboBox.SelectedValueProperty,
new Binding("WCSettings.ViewModels.WinCAPSIniViewModel.selectedItem")
{
Source = combobox.SelectedValue,
Mode = BindingMode.OneWayToSource
});
The binding only needs to go one way (View --> ViewModel), so the value can be stored in a database.
'combobox' is the instance of the ComboBox being created.
Binding the SelectedValue property of a ComboBox and at the same time setting the Source of the binding to the same property doesn't make sense.
You need to have an instance of the view model and use that as the binding source. And unless you also set the SelectedValuePath property of the ComboBox, you should bind the SelectedItem property.
WCSettings.ViewModels.WinCAPSIniViewModel viewModel = ...
combobox.SetBinding(ComboBox.SelectedItemProperty,
new Binding("selectedItem")
{
Source = viewModel ,
Mode = BindingMode.OneWayToSource
});
And just in case you forgot, selectedItem needs to be a public property in class WinCAPSIniViewModel.
Related
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
I've got an ItemsControl subclass that behaves like a Selector, but it can't be a subclass of Selector because the selected item isn't necessarily in the Items collection. So I'm stuck reimplementing a lot of Selector stuff.
My class has a SelectedValuePath property. If that property has a value, I create a binding so that when SelectedItem changes, the value of "SelectedItem." + SelectedValuePath gets assigned to SelectedValue. This works perfectly -- as long as the consumer binds my SelectedValue to a property of the same type as the value property on SelectedItem.
Here's the problem:
However, if the selected item has an int ID property that's being used as a value property, and SelectedValue is bound to a Nullable<int> SelectedID property on a view model, the binding fails to set the property on the view model except in the case where SelectedItem is null.
I've noticed that the WPF ComboBox class doesn't have this problem, so it must be solvable without requiring the consumer to provide a value converter. I've tried a CoerceValueCallback and that doesn't do anything for me. It doesn't know the target type. It has no information about the binding that's receiving the value.
What is ComboBox.SelectedValue doing that I'm not?
I'm reasonably familiar with IValueConverter and how value converters are added to bindings in XAML at the point where a control is used. I don't need help with that. I'm asking if anybody knows how any binding on ComboBox.SelectedValue converts int to int? without the consumer of the control adding a value converter to the binding.
As I should have expected, the problem wasn't where I expected. There was no type conversion issue.
It appears that the problem was internal to my class. I was updating SelectedValue with a binding.
Binding binding = new Binding("SelectedItem." + SelectedValuePath);
binding.Mode = BindingMode.OneWay;
binding.Source = this;
BindingOperations.SetBinding(this, MenuComboBox.SelectedValueProperty, binding);
This appears to have interfered with the consumer's two-way binding to SelectedValue.
I have a BindingTarget class which derives from DependencyObject. It exposes a single DependencyProperty called Value, and fires an event when Value changes. I already wrote it to forward values to the "read only" DependencyProperty SelectionBoxItem, where the setter is protected. So instead of creating a binding from "SelectedItem."+SelectedValuePath with SelectedValue as the target as above, I used a private BindingTarget instance as the target, and set SelectedValue in its ValueChanged handler. The consumer's binding now works as expected.
// The type argument to BindingTarget is the type of the property.
_selectedValueBindingTarget = new BindingTarget<Object>();
_selectedValueBindingTarget.ValueChanged += (s, e2) =>
{
SelectedValue = e2.NewValue;
};
Binding binding = new Binding("SelectedItem." + SelectedValuePath);
binding.Mode = BindingMode.OneWay;
binding.Source = this;
BindingOperations.SetBinding(_selectedValueBindingTarget,
BindingTarget<Object>.ValueProperty, binding);
I've got a data binding source, and it has an associated property. When this source property is text/integer based etc, everything works fine. I can bind that to a text box or label okay.
Some of my properties are lists. This is also fine, I can create a new listBindingSource, point it's datasource at the origional binding source, and the datamember as the list and point my, say, listview at that. I set the DisplayMember to the property of the item in the list and it works fine.
However, if the property is neither list, or text/int, but just a single object... I'm stuck. There's no way of telling it I want to bind the properties's property to the object. There's no 'DisplayMember' to help.
An example:
I have an object MeteredSpace. It has the properties
public string Name {get;set;}
public List<MeteredSpace> ChildMeteredSpaces {get;set;}
public MeteredSpace ParentMeteredSpace {get;set;}
Then I define the following met
//underlying datasource
this.meteredSpaceBindingSource.DataSource = typeof(SEMS.LinqObjects.MeteredSpace);
//data source of children
this.childMeteredSpacesBindingSource.DataMember = "ChildMeteredSpaces";
this.childMeteredSpacesBindingSource.DataSource = this.meteredSpaceBindingSource;
Now for my controls:
//nice and easy, picking directly from the underlying data source
this.nameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text",this.meteredSpaceBindingSource, "Name", true));
//our child metered space list box is pretty easy too:
this.meteredSpaceListBox.DataSource = this.childMeteredSpacesBindingSource;
this.meteredSpaceListBox.DisplayMember = "Name";
//then we come to our parent text box
this.nameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text",this.meteredSpaceBindingSource, "ParentMeteredSpace", true));
I have no way of pointing it at ParentMeteredSpace's Name property like I do with the list box. I also can't create a nice new binding source for it.
Anyone know of a way around this? I had a look into overriding a control and adding my own DisplayMember, but I started to think there might be a better way of doing it.
Thanks
You should be able to reference through the parent property:
Binding b = new Binding("Text",
this.meteredSpaceBindingSource,
"ParentMeteredSpace.Name",
true);
this.nameTextBox.DataBindings.Add(b);
I am implementing MVC in a WinForms Application. In the view there is a combobox control. I have declare a property called SheetLoader with getter and setter:
public BindingSource SheetLoader
{
get { return (BindingSource)comboBox_workSheetList.DataSource; }
set { this.comboBox_workSheetList.DataSource = (BindingSource)value; }
}
In controller I want to access setter above and bind the BindingSource to the combobox.
view.SheetLoader = _bindingSource;
But this way is not working. The combobox will not assign any item.
I have debugged it, However the value gets data.
Please help me to bind data from controller to View -> Control.
Ensure you set the DisplayMember and ValueMember of your combobox.
Using Entity data model in a Windows Forms Project, I want to bind simultaneously Orders entity to datagridview and to textBox, and textBox has to display OrderID value depending on the current line in the datagrid.
The code I used in Form load event is next:
using(NorthwindEntities context = new NorthwindEntities())
{
ordersDataGridView.DataSource = context.Orders;
OrderNumberTextBox. ...
}
For this case, what is the right syntax to bind Textbox ? Thank you.
Bind a BindingSource object to your context.Orders, bind your DataGridView to the BindingSource, and then through the TextBox.DataBindings property, bind to appropriate property of your TextBox to your BindingSource. The BindingSource object will manage the currency state so that the TextBox will change when you select different items in your DataGridView.
The binding will look similar to something to this:
OrderNumberTextBox.DataBindings("Text", bindingSource, "OrderID");