I have a combo box in a ItemControl. xaml is
<ComboBox ItemsSource="{Binding DataContext.NodeMembershipFunction,
RelativeSource={RelativeSource AncestorType={x:Type ItemsControl},
AncestorLevel=1}}"
DisplayMemberPath="_Name"
SelectedValue="{Binding Condition, Mode=TwoWay}"
SelectedValuePath="_Type">
</ComboBox>
My combobox works fine with above so I am not posting any code to explain above.
My problem is that when I add a new item to my ItemControl, the combox has nothing selected (which is correct according to the code I have). Is there any way to add a trigger or something in above which selects first item only when nothing is selected eg on adding new itemcontrol?
Set IsSynchronizedWithCurrentItem="True" on comboBox instance so that it always be in sync with current item of collection.
<ComboBox IsSynchronizedWithCurrentItem="True"..../>
Moreover, adding item in collection won't make SelectedItem to go away unless you are re-initializing the entire list.
I would suggest to use ObservableCollection<T> for property NodeMembershipFunction in case not doing it already and add item directly to the collection instead of repopulating it.
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.
If I have a combo box by iteself with an item source e.g.:
<ComboBox ItemsSource="{Binding Combobox.Options}"/>
This works fine. Where Combobox.Options is a list of strings {"option1","option 2",... etc}
However, I want to have a combobox within a datagrid which has an item source:
e.g.:
<DataGrid CanUserAddRows="False" AutoGenerateColumns="False" SelectionMode="Single" ItemsSource="{Binding Users.Table.Tables[0]}">
But I keep getting an empty combo box when I add it into a datagrid template column. I have also tried the Find Ancestor Relative soure but also got an empty combo box.
Finally managed to find the problem. Needed to add a DataContext when getting the list for the item source within the datagrid:
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}"/>
The Problem:
Combobox shows no selected item on startup. To be exact: Item and Value are null, index is -1 and valuepath is empty. While the functionality of the binding itself seems to work, it simply refuses to show a value on startup.
What I am trying to do:
I have two lists of objects. ListOne is the full list of all available objects.
ListTwo is a list of 21 "selected" objects out of the objects in list one.
So I want to bind ListOne to a combobox with the namevalue of the object to show. Meanwhile, the selected object should be bound to ListTwo[index].
Basically, if I change the selection in the combobox I want ListTwo[index] to be a copy of the now selected object.
What I have right now:
The Object in question:
public class Rezept
{
public string strName { set; get; }
public string strSomething { set; get; }
}
The XAML-Code:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedValue="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName"/>
This seems to be working, as in selecting something updates ListTwo just fine. But on startup the combobox has nothing selected.
Another XAML-Code try:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedItem="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName"/>
This seems to behave exactly as the first, even tho it sounds more "correct".
Try three on the XAML:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedItem="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName" SelectedValue="{Binding listTwo[0].strName}"/>
This changes nothing. Neither does binding to SelectedValuePath it seems.
What do i have to change so the combobox actually shows ListTwo[0] on startup? I did make sure ListTwo[0] actually has the right value. It does get populated by a xml file on startup tho, after the UI is loaded. Would this be a case of needing a "OnPropertyChanged"-Event somewhere? And if so, where? I am out of ideas otherwise.
Could still use a hand here tho :-(
Instead of binding with SelectedValue property, you should have bind it with SelectedItem property like as follows:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedItem="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName"/>
So, since noone seems to have a solution (including myself after another 5 days of searching) I will at least post my VERY dirty workaround.
I made a List where I added every combobox in question via a loop (21 ones). Then I did another loop and manually set the Index of listOne in every Combobox to match the right value in listTwo. So it simply checks which index contains the right name and set it to that like this:
for(int i = 0, i < 21, i++)
{
listCombo[i].SelectedIndex = listOne.IndexOf(listOne.Where(x => x.name == listTwo[i].name).First();
}
This only has to be called once one on startup of the programm, since listTwo actually has the right values in the right order (as seen in the XML save file as well).
Id still much rather find out how this is supposed to work in XAML Databinding tho. So if anyone has a real answer later on, feel free to poke me so i can update this one.
I have three ComboBoxes such that C's items list is dependent on the selected item in B and B's items list is dependent on the selected item in A. I have ObservableCollections of particular classes for the ItemsSource on each ComboBox, and I want the Name property of the selected item to be pushed to a property in another class. For example:
ObservableCollection<AClass> Items
=> ItemsSource of cbo_A ComboBox
And selectedInstanceOfAClass.Name should be pushed to Data.AClassName property. The problem I have is that when I choose a value in the A ComboBox the first time, the B ComboBox gets the appropriate items based on the selected item in A, as expected. Same for when I select an item in B for the first time--C gets the right items. However, when I choose a different value in A, the items in B get updated but the selected value of B stays the same, and when I try to select a new value in B from its new items, the selection doesn't change--it stays the same selected value as what I initially selected in B.
Here's the XAML I have right now:
<ComboBox x:Name="cbo_A"
ItemsSource="{Binding Path=Lists.AItems, Mode=OneWay}"
DisplayMemberPath="Name" SelectedValuePath="Name"
SelectedValue="{Binding Path=Data.AClassName, ValidatesOnDataErrors=True,
Mode=OneWayToSource}" />
<ComboBox x:Name="cbo_B"
ItemsSource="{Binding ElementName=cbo_A, Path=SelectedItem.BItems, Mode=OneWay}"
SelectedValuePath="Name" DisplayMemberPath="Name"
SelectedValue="{Binding Path=Data.BClassName, ValidatesOnDataErrors=True,
Mode=OneWayToSource}"/>
<ComboBox x:Name="cbo_C"
ItemsSource="{Binding ElementName=cbo_B, Path=SelectedItem.CItems, Mode=OneWay}"
SelectedValuePath="Name" DisplayMemberPath="Name"
SelectedValue="{Binding Path=Data.CClassName, Mode=OneWayToSource,
ValidatesOnDataErrors=True}" />
What is causing the weird behavior with the selected value not updating even when I explicitly click the ComboBox and try to change the value?
Edit: when debugging and I had a SelectionChanged handler on cbo_A and another on cbo_B, I entered the cbo_B handler before the cbo_A one, so the selected item from B's perspective was still the old item, because A had not been updated yet. :/
Edit 2: if I flip the order of my ComboBoxes in XAML, suggested by this question, such that C comes before B comes before A, I enter A's handler first. When I then enter the handler for cbo_B, the SelectedItem property shows the old value (previously selected, before I chose a new value in cbo_A), even though I clicked a value from the new list of items showing up in the ComboBox.
Edit 3: I'm trying a version of this answer and getting the same problem: I see new values in ComboBox B upon changing the selected value of ComboBox A, but I cannot change the selected value in B after I've already set it once. I'm beginning to think I've got something else going awry.
Wow. So, don't go quickly implementing a bunch of IEquatable<T> Equals methods for new classes, because you may end up doing what I did:
if (ReferenceEquals(this, other))
{
return false; // Say what??
}
Sigh. I got my ComboBoxes to work by:
Correcting my BClass.Equals(BClass other) method;
Using this answer about having another view model class with different properties like SelectedAItem and AItems; and
Using this answer about putting my XAML declarations in a different order so cbo_C comes before cbo_B and cbo_B comes before cbo_A.
I may try simplifying things and see what parts are absolutely necessary for my ComboBoxes.
I have a combo box which is populated on selection's from two other combo'.
No problem I have this working.
Problem is I only want to activate the Selected Item binding after this has happened.
Here is my combo
<cuc:ComboBox Name="GopLenTypeCombo" Width="240" Height="24"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding Mode=TwoWay, Source={StaticResource ProfileDataProvider}, XPath=GopLenType}"
IsEnabled="False"/>
How do I stop the SelectedValue binding working untill I have populated the combo ?
I don't know whether this is possible in pure XAML, but if you have an underlying ViewModel, this wouldn't be too hard:
What you would need to do is to bind your third ComboBox to a property on the ViewModel (let's call this property Combo3Items).
You would also need to bind the two first ComboBoxes to properties on the same ViewModel (let's call these Combo1Items and Combo2Items, respectively). In addition to that, you could bind both of these ComboBoxes' SelectedValue to properties on the ViewModel, so that the ViewModel knows which items are selected.
Initially, Combo3Items would be empty, but as soon as the two bound SelectedValues are properly assigned, you can fill Combo3Items and raise an INotifyPropertyChanged event.
The MVVM architecture is very powerful. If you don't already know it, you can read more about it here.