Scenario:
A list of user control of MyControl type:
public List<MyControl> Controls { get; set; }
public MyControl SelectedControl { get; set; }
A ComboBox with the ItemsSource linked to the Controls property:
<ComboBox ItemsSource="{Binding Path=Controls}" SelectedItem="{Binding Path=SelectedControl}" DisplayMemberPath="HeaderTitle" >
The problem is that the ComboBox shows the items correctly but when I select an Item it doesn't appear in the ComboBox. Why?
PS: HeaderTitle is a DependencyProperty of the MyControl type.
I think this is a duplicate of WPF - Combobox SelectedItem not getting set?
Therefore I'd like to quote Heinz K's answer https://stackoverflow.com/a/3506262/6071619
I had the same problem and solved it by overriding the Equals() Method in my CustomObject and compared the Id Property.
If the item that is selected is not the same instance that is contained in the List, you must override Equals() in the CustomObject to let the ComboBox know that it is the same object.
If it's the same instance, maybe it's only a simple thing such as setting the BindingMode to TwoWay:
SelectedItem="{Binding Path=CustomSettingProperty,Mode=TwoWay}"
try to bind it like this..
<ComboBox ItemsSource="{Binding Controls}" SelectedItem="{Binding SelectedControl, Mode=TwoWay}" DisplayMemberPath="{Binding HeaderTitle}" >
you dont really need to have the selected property bound to its class... it can be just a string also. so just store the selected item in type string and then work on getting the items from your list that match that selected item.
Try setting the DataContext for the ComboBox?
<ComboBox DataContext="{Binding Controls}" ItemsSource="{Binding Controls}" DisplayMemberPath="HeaderTitle">
You shouldn't have to bind the SelectedItem property as long as the ItemsSource and DisplayMemberPath are set.
Related
I have a ComboBox in WPF. The ComboBox is inside of a grid, and the grid's DataContext is bound to the SelectedItem of a ListView. The ItemsSource of the ComboBox is set to a StaticResource, located in the window resources. The ItemsSource does not change. I have tried to use both SelectedValue and SelectedItem but both of them cause the same issue for me. The issue is that when the SelectedItem of the ListView is changed, the ComboBox is actually setting the property value from the PREVIOUSLY selected item, to the property value of the NEWLY selected item. Clearly I am doing something wrong, because I have used comboboxes many times in the past without this issue. I have scoured the web and can't find an answer. The closest, most similar question I found was: Strange behaviour (or bug?) with ComboBox in WPF when changing DataContext and having bound ItemsSource and SelectedItem
But it doesn't seem to have a solution. The solutions listed in comments did not work for me.
I created SelectionChanged events for both the ListView and the ComboBox and set breakpoints at each of them and the property that is being set. The property is actually being set BEFORE either one of those are triggered. So even if I wanted to create some hack workaround, I couldn't.
For the record, the ComboBox functionality works perfectly fine. When an object is selected in the ListView, I can see the Template name property, as I should, and the list of items is correct. If I manually change the selected item, the property is changed to a new item, just like it should. The problem is that when I change the selected item in the ListView, the "Template" property of the newly selected object is being set to the "Template" property of the previously selected object. So the combobox is changing before anything else.
The xaml for the ListView and ComboBox are below.
<ListView x:Name="my_ListBox" FlowDirection="RightToLeft"
Margin="5" Grid.RowSpan="2" SelectedIndex="0"
ItemsSource="{Binding Source={StaticResource myList}}"
DisplayMemberPath="Name"
SelectionChanged="my_ListBox_SelectionChanged"/>
<Grid DataContext="{Binding ElementName=my_ListBox, Path=SelectedItem}">
<ComboBox Name="comboBox_myTemplate"
ItemsSource="{Binding Source={StaticResource myTemplatesList}}"
SelectedValue="{Binding Template}"
SelectionChanged="comboBox_myTemplate_SelectionChanged"
DisplayMemberPath="Name" FontSize="20" Margin="5"/>
</Grid>
If I set "IsSynchronizedWithCurrentItem="True"" in the ComboBox the problem is resolved. If someone wants to explain what exactly that is doing and how it works I'd love to hear it. Thanks.
I have a combobox with items like below:
{[1, US]}
{[2, UK]}
My combobox will display it with the Value. My problem is I can't set the SelectedValue property of my combobox.
<ComboBox Name="cbSource" Grid.Row="1" Grid.Column="3"
ItemsSource="{Binding Datas.Countries, Mode=OneWay}"
SelectedValue="{Binding CurrentObject.Country, Mode=TwoWay}"
DisplayMemberPath="Value" SelectedValuePath="Key"></ComboBox>
Now my CurrentObject.Country is a string property with a value of UK. I also tried this one below but no luck.
DisplayMemberPath="Value" SelectedValuePath="Value"
What can I do here?
It is not possible to achieve your behavior using a key value pair. See the example below.
Just create a class having 2 properties one for key and one for value. Then bind a collection of this class as the itemssource and bind the selectedvalue to a string property. Ie Datas.Countries is the collection of the class.
<ComboBox Name="cbSource" Grid.Row="1" Grid.Column="3"
ItemsSource="{Binding Datas.Countries, Mode=OneWay}"
SelectedValue="{Binding SomePropertyToHoldKeyValue, Mode=TwoWay}"
DisplayMemberPath="Value" SelectedValuePath="Key"></ComboBox>
I think we can understand the difference between SelectedItem, SelectedValue, DisplayMemberPath and SelectedValuePath better with an example. See this class:
public class Employee
{
public int Id;
public string Name;
}
and the following xaml:
<ComboBox ItemsSource="{Binding Source={StaticResource Employees}}"
DisplayMemberPath="Name"
SelectedValuePath="Id"/>
DisplayMemberPath points to the Name property, so the value displayed in the ComboBox and the Employee entries contained in the drop down list, will be the Name property of the Employee object.
To understand the other two, you should first understand SelectedItem. SelectedItem will return the currently selected Employee object from the ComboBox. You can also assign SelectedItem with an Employee object to set the current selection in the ComboBox.
SelectedValuePath points to Id, which means you can get the Id of currently selected Employee by using SelectedValue. You can also set the currently selected Employee in the ComboBox by setting the SelectedValue to an Id (which we assume will be present in the Employees list).
Imagine your working on a UI for an Wedding Planner app. You'll have a list of guests and you want to display their name on the screen next to a combobox containing values of 'Will Attend' / 'Maybe' / 'No'.
I've tried to something just that....I have a collection of items inside a view model (the guests). For each of those items I want to display a Label and a ComboBox. Each ComboBox has the same values in the drop down (the possible responses).
I've created an ItemTemplate that contains a label and a combobox. I bind it to my collection of guests and it works as expected. I'm using ancestor binding so that the ComboBox's ItemsSource is bound to the list of possible responses. That works great.
What I'm struggling with is how to bind the SelectedItem to get the values the user selects? I want to have a collection of selected values on the ViewModel somehow, but I'm having a lot of trouble finding the correct words to describe this / search for it.
Can anyone help me? Am I going about this the wrong way?
You may create an enum for the attendance state and add an Attendance property to your Guest class:
public enum Attendance
{
Yes,
No,
Maybe
}
public class Guest
{
...
public Attendance Attendance { get; set; } // raise PropertyChanged event if necessary
}
Now you could set the Tag property of the ComboBox items to the appropriate enum value and bind the SelectedValue property:
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding Attendance}" SelectedValuePath="Tag">
<TextBlock Tag="Yes">Will Attend</TextBlock>
<TextBlock Tag="No">Won't Attend</TextBlock>
<TextBlock Tag="Maybe">May Attend</TextBlock>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
Xaml:
<ComboBox Grid.Row="1"
Name="CmbClasse"
Grid.Column="3"
Margin="5,5,5,5"
ItemsSource="{Binding DataContext.Classeses}"
SelectedValuePath="ClasseId"
DisplayMemberPath="ClasseName"
SelectedValue="{Binding DataContext.CurrentSelectedPersonagem.IdClasse, Mode=TwoWay}"/>
When I open my application, the ComboBox do not have display any default item. But the item list is working, have all the items on it. Please help, if a image is needed just ask.
Thanks.
Here is a method I use all the time.
Firstly, your View Model should have two properties, one to represent the collection, and the other to represent the selected item.
public IEnumerable<YourObject> MyObjects { get; private set; }
public YourObject SelectedObject { get; private set; }
Note: It would be a good idea to use an ObservableCollection for MyObjects, and also implement INotifyPropertyChanged. Use this only if you need to create brand new instances of your collection in the View Model.
Your ComboBox should then bind to these properties, like so:
<ComboBox ItemsSource="{Binding MyObjects}"
SelectedItem="{Binding SelectedObject}"
...
/>
Now, here comes the magic. When you create your collection, simply set the SelectedObject to be the FirstOrDefault item in the list.
private void LoadData()
{
//TODO: Load the data into the collection
//Set the first item
this.SelectedObject = MyObjects.FirstOrDefault();
}
This will ensure that the first item is always selected. You do not need to implement INotifyPropertyChanged on the SelectedObject property unless you are planning on manually changing the value of this property in your View Model.
I have a combo box and button as such
<ComboBox ItemsSource="{Binding MessageTypesList}"
DisplayMemberPath="MessageType"
SelectedValue="MessageType" />
<Button Content="Search"
Command="{Binding Path=SearchMessageTypes}"
x:Name="SearchMessageTypeButton"/>
The MessageTypesList list is generated from a SQL query and once the Message Type is selected from the list the Search button needs to pass the selected value to a string property in my ViewMainModel.
When I debug the application the value passed to the MessageType property is always NULL. I have this working for a similar date time searchs but cant see how to pass the MessageType value in my XAML to the MessageType propery form binding generated lists.
You should bind the SelectedValue property to a property in your viewmodel.
Create a property in your viewmodel:
public MessageType SelectedType {get;set;}
Bind selectedItem to this property in XAML:
<ComboBox ItemsSource="{Binding MessageTypesList}" SelectedItem="{Binding SelectedType, Mode=TwoWay" />