Weird databinding issues in wpf combobox - wpf

I am writing what is turning out to be a simple GUI in WPF. At the moment I have a static list inside of a ComboBox, like this:
<ComboBox HorizontalAlignment="Left" Height="22" Margin="24,97,0,0" VerticalAlignment="Top" Width="83"
SelectedItem="{Binding fruit, Mode=TwoWay}">
<ComboBoxItem>apple</ComboBoxItem>
<ComboBoxItem>orange</ComboBoxItem>
<ComboBoxItem>grape</ComboBoxItem>
<ComboBoxItem>banana</ComboBoxItem>
</ComboBox>
I'm binding the SelectedItem to a singleton in my code that has already been initialized and used elsewhere.
I put a breakpoint on the get of fruit and it returns "grape", but the selected item is always blank. I even added a button so that I could call RaisePropertyChanged manually, but the RaisePropertyChange call didn't do anything either.
Finally, MVVMLight gives blendability. For no important reason I changed the binding in the combobox from SelectedItem to Text As soon as I did that, my design time form filled in with the expected values, but, when the code is running, the box continues to sit at the empty state

This is because you have items of type ComboBoxItem in the ComboBox but the property you are trying to bind to is of type string.
You have three options:
1.Instead of adding ComboBoxItem items add String items:
<ComboBox HorizontalAlignment="Left" Height="22" Margin="24,97,0,0" VerticalAlignment="Top" Width="83"
SelectedItem="{Binding fruit, Mode=TwoWay}">
<sys:String>apple</sys:String>
<sys:String>orange</sys:String>
<sys:String>grape</sys:String>
<sys:String>banana</sys:String>
</ComboBox>
2.Instead of SelectedItem bind to SelectedValue and specify SelectedValuePath as Content:
<ComboBox HorizontalAlignment="Left" Height="22" Margin="24,97,0,0" VerticalAlignment="Top" Width="83"
SelectedValue="{Binding fruit, Mode=TwoWay}"
SelectedValuePath="Content">
<ComboBoxItem>apple</ComboBoxItem>
<ComboBoxItem>orange</ComboBoxItem>
<ComboBoxItem>grape</ComboBoxItem>
<ComboBoxItem>banana</ComboBoxItem>
</ComboBox>
3.Do not specify items directly in XAML, but use ItemsSource property to bind to a collection of strings:
<ComboBox HorizontalAlignment="Left" Height="22" Margin="24,97,0,0" VerticalAlignment="Top" Width="83"
ItemsSource="{Binding Fruits}"
SelectedItem="{Binding fruit, Mode=TwoWay}"/>

You should bind ComboBox.ItemSource to a list of strings (make the List of strings an ObservableCollection<string> in case you add items to this list) and then set the fruit variable to an instance in the List of strings.
I think you have your problem because your fruit variable references a different instance than you have in your list of ComboBoxItems. (even though the strings are the same)

Related

How to hide drop down arrow from combobox in case list size equals 1?

I want to display a list with one or more elements. For several elements the natural choice is a combobox. For one element I want it to appear as a textbox. My current solution is to display both, a combobox and a textbox at the same position and hide one of them depending on the number of elements in the list (see below).
I wonder whether there is a more elegant solution, something like to tell the combobox to hide its drop-down arrow in case the list's size equals one.
<Grid>
<ComboBox
HorizontalAlignment="Center" VerticalAlignment="Center"
ItemsSource="{Binding List}"
SelectedItem="{Binding ListSelected}"
Visibility="{Binding IsList, Converter={StaticResource InverseBoolToHiddenOrVisibleConverter}}"
/>
<TextBox
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding ListSelected}"
Visibility="{Binding IsList, Converter={StaticResource BoolToHiddenOrVisibleConverter}}"
/>
You can get rid of the TextBox, and instead change ComboBox's IsEnabled state depending on the number of items inside. On a side note, I believe you actually wanted a TextBlock, not a TextBox, so user can't change the text inside.
So, according to your example and my suggestion:
<ComboBox
HorizontalAlignment="Center" VerticalAlignment="Center"
ItemsSource="{Binding List}"
SelectedItem="{Binding ListSelected}"
IsEnabled="{Binding IsComboEnabled}" />
You don't need the Visibility part anymore, since it will always be Visible.
Code behind:
public bool IsComboEnabled
{
get
{
return List.Count > 1 ? true : false;
}
}
Or, I guess you could make it even easier for yourself. By just overwriting the Visibility property with this (and deleting the TextBox control either way):
IsEnabled="{Binding IsList}"

ComboBox doesn't show current value of assigned field inside a ListView

I have a DataTemplate with a Combobox inside a ListView like this
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.Dimensions, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
DisplayMemberPath="Description"
SelectedValuePath="Id"
SelectedItem="{Binding DimName}"/>
</DataTemplate>
The combobox is populated correctly, but it doesn't select the content according to underlying field (ie. Dimension.DimName).
Here's how the ListView is declared
<ListView
Name="lstCriteria"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Margin="5"
AlternationCount="2"
ItemContainerStyle="{StaticResource CriteriaItemStyle}"
ItemsSource="{Binding Source={StaticResource CriteriaList}}" DockPanel.Dock="Top"
IsSynchronizedWithCurrentItem="True">
If I replace combobox with a TextBlock it does show the DimName Field's value, like this
<TextBox Text="{Binding DimName}"/>
What am I missing ?
Does your DimName come directly from the Dimensions list?
By default, if a ComboBox's Items is set to a custom class, it will compare the SelectedItem to an item in the ItemSource by reference. It will not match the item if they do not refer to the exact same object in memory, even if the object's data is the same.
To get around that you can either set SelectedValue and SelectedValuePath instead of SelectedItem on your ComboBox, or you can overwrite the Equals() method of your DimName class to return true if an object's data is equal
Edit
In regards to your comment below, is DimName a Dimension object? If so then setting SelectedItem should work fine. If it's an long you'll need to set SelectedValue, not SelectedItem. If it's something else, you may need a converter to convert it into a Dimension object
As Rachel suggested, I added a new Property to my class called Dimension of class Dimension like this
public Dimension Dimension
{
get { return _dimension; }
set { _dimension = value; }
}
and then set SelectedItem="{Binding Dimension}" as follows,
<ComboBox ItemsSource="{Binding DataContext.Dimensions, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
DisplayMemberPath="Description"
SelectedValuePath="Id"
SelectedItem="{Binding Dimension}">
</ComboBox>
The silly mistake I was making was,
As my combobox was populating correctly, I was hoping that WPF will somehow match the DimName content with one of the items in the ComboBox automatically, which is not possible.

Silverlight data bind combobox items and value separately

I can use databinding to bind the contents of a combobox to a collection, or I can bind the selected value in the combobox to a member of a class, but I can't do both at the same time. I want to be able to bind the contents to one thing and the selected value to something else, I guess the combobox can't handle two datacontexts or I'm not specifying them explicitly. Example below, I'd appreciate any help! Thanks.
In XAML:
<ComboBox Name="Combo" ItemsSource="{Binding}"
SelectedValue="{Binding ID, Mode=TwoWay}"/>
In code:
LayoutRoot.DataContext = myClass;
Combo.DataContext = items;
This should do it for you, or at least be close.
<Grid DataContext="{Binding Source=MyObject}">
<ComboBox x:Name="Combo"
ItemsSource="{Binding Source=MyCollection}"
SelectedValue="{Binding Path=ID, Mode=TwoWay}"/>
</Grid>

WPF: ComboBox with selecteditem set make not use of SelectedIndex=0?

Why is the first element in my combobox popup menu not shown in the selected item area of
my combobox , when I use the SelectedItem binding? Without that it is showing up ?? Using
the same code selecteditem + selectedindex that is no problem!
<ComboBox
ItemsSource="{Binding SchoolclassSubjectViewModels}"
SelectedItem="{Binding SelectedSchoolclassSubjectViewModel}"
SelectedIndex="0"
Height="23"
HorizontalAlignment="Left"
Margin="375,13,0,0"
VerticalAlignment="Top"
Width="151">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SchoolclassName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding SubjectName}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Well as workaround I used:
SchoolclassSubjectViewModels.Add(schoolclassSubjectVM);
SelectedSchoolclassSubjectViewModel = schoolclassSubjectVM;
and this:
SelectedItem="{Binding SelectedSchoolclassSubjectViewModel,Mode=TwoWay}"
but I would prefer the xaml only way as it should really work.
It is because the reference inside your ItemsSource collection is not the same as the one in your SelectedItem property. I would venture to guess that you are using one object context to query your database for the list of SchoolclassSubject objects which the ItemsSource is bound to, but another context to query the actual data item to which you bind the SelectedItem. Even though the list contains a reference which represents the value held by your object, it is not really the same reference, but a separate instance of the same data.
There are ways to solve this issue, most of them involve using the SelectedValuePath and SelectedValue instead of the SelectedItem properties, but the concrete solution would be different depending on your particular ORM.

WPF 2 ComboBox binding problem

I have the following problem:
there is a class with a couple of string properties
there is a collection of such class entities
That collection is shown in tree on the left of some windows and details shown on the right. I'm binding string properties of selected node to comboboxes in details.
First combobox always have the same ItemsSource but the second one ItemsSource depends on SelectedItem of the first combo...
<ComboBox
Grid.Column="1"
SelectedIndex="0"
x:Name="cbClass"
Style="{DynamicResource ComboBoxValidationError}"
SelectedValue="{Binding Path=Description.Node.ClassName, ElementName=userControl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Source={StaticResource classesProvider}}"
Width="Auto"
Height="Auto"
DisplayMemberPath="Description"
SelectedValuePath="FQN" />
<ComboBox
Grid.Column="1"
SelectedIndex="0"
Grid.Row="1"
x:Name="cbMethod"
SelectedValue="{Binding Path=Description.Node.MethodName, ElementName=userControl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,diag:PresentationTraceSources.TraceLevel=High}"
ItemsSource="{Binding Path=SelectedItem.Methods, ElementName=cbClass, Mode=Default,diag:PresentationTraceSources.TraceLevel=High}"
Style="{DynamicResource ComboBoxValidationError}"
Width="Auto"
Height="Auto"
SelectedValuePath="Name"
DisplayMemberPath="Description" />
Now when i create new node in the tree, both string properties have null reference. And when first combo changes its SelectedItem for the NEW node, second ComboBox binds null to the string value of the OLD node, which were selected before creating new node in the tree... I wonder what should i do in this case?
I've just found an answer.
Binding are notified in the order of their declaration, WPF is not going to analyse dependencies of bindings :)
So swapping declarations of ComboBoxes solves the problem... It's acceptable in this scenario because I place these ComboBoxes in Grid manually setting their Grid.Row and Grid.Column...
Though solution is not very pleasing, it works!

Resources