Reputation: 8373
I have a combobox in my MainWindow.xaml file like so:
<ComboBox Name="material1ComboBox"
HorizontalAlignment="Center"
MinWidth="100"
ItemsSource="{Binding ViewProperties.MaterialDropDownValues}"
SelectedValue="{Binding ViewProperties.Material1SelectedValue}"
SelectionChanged="Material1ComboBoxSelectionChanged">
</ComboBox>
I've assigned the datacontext in the codebehind using this.datacontext = this
.
I created a ViewProperties
that is accessed as a property in the MainWindow
and is a class that implements INotifyPropertyChanged and contains the MaterialDropDownValues
as a property.
I even changed the the MaterialDropDownValues
to be an ObservableCollection
.
The problem is that the databinding works on initialisation however if the MaterialDropDownValues
property is changed the combobox values are not updated.
I have the following in the ViewProperties
class:
public ObservableCollection<string> MaterialDropDownValues
{
get { return this.materialDropDownValues; }
set
{
this.materialDropDownValues = value;
OnPropertyChanged("MaterialDropDownValues");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
Any ideas why this is not working? All the other answers I could find advised to implement INotifyPropertyChanged and make the property an observablecollection.
Upvotes: 2
Views: 4684
Reputation: 1
Posting this in case anyone else runs into this. I came up this as the best search result matching my symptoms, but it turns our that none of the answers worked above for me.
I was using WinUI3 and apparently it uses the newer x:Bind syntax for it's XAML. Apparently x:Bind defaults it's Mode to OneTime which is why it wouldn't update after the first value (I also tried Binding but couldn't get that to work)
From: <TextBlock Text="{x:Bind MyField}" x:Phase="1" Margin="0,5,0,5"/>
To: <TextBlock Text="{x:Bind MyField, Mode=OneWay}" x:Phase="1" Margin="0,5,0,5"/>
So if you are using x:Bind, make sure set Mode=OneWay AND implement INotifyPropertyChanged and then things should work
Upvotes: 0
Reputation: 19885
Solution 1:
Dont recreate this.materialDropDownValues
try to do
this.materialDropDownValues.Clear();
foreach(var mystring in myStrings)
this.materialDropDownValues.Add(mystring);
for all new items. If this doesnt work then try solution 2...
Solution 2:
As per my experience, I think ObservableCollection
of primitive types like int
, string
, bool
, double
etc. does not refresh on Property Change notification if ItemsControl.ItemTemplate
is not specified.
<ComboBox Name="material1ComboBox"
HorizontalAlignment="Center"
MinWidth="100"
ItemsSource="{Binding ViewProperties.MaterialDropDownValues}"
SelectedValue="{Binding ViewProperties.Material1SelectedValue}"
SelectionChanged="Material1ComboBoxSelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type System:String}">
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This is because the itemscontrol's items container creates non-observable item containers in it for primitive data by simply copying item.ToString(). In the code above the {Binding}
should update the data changes when the whole items source is changed.
Let me know if this works.
Upvotes: 1
Reputation: 22435
what happens if you change your xaml to
<ComboBox Name="material1ComboBox"
HorizontalAlignment="Center"
MinWidth="100"
DataContext="{Binding ViewProperties}"
ItemsSource="{Binding MaterialDropDownValues}"
SelectedValue="{Binding Material1SelectedValue}"
SelectionChanged="Material1ComboBoxSelectionChanged">
</ComboBox>
nevertheless you should just instantiate your collection once and just use remove, add and clear when you use a OberservableCollection.
Upvotes: 0
Reputation: 15999
Edit in response to comments
None of the below solved the problem, but is left as a reference.
Original Answer
The problem is that you have not specified the DataContext
for your view, which is where WPF looks for Binding
values by default.
Provided that your ViewProperties
property on MainWindow
is public you can simply change your binding to:
ItemsSource="{Binding ViewProperties.MaterialDropDownValues,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}"
This causes WPF to look for the property value on the first occurence of Window
that it finds above the combobox in the visual tree.
Alternatively, you can just set the Window.DataContext
property to your instance of ViewProperties
and change the binding to the following:
ItemsSource="{Binding MaterialDropDownValues}"
Either of these will work, but I would suggest using the latter as it is closer to the MVVM pattern that is generally preferred in WPF/XAML applications.
Upvotes: 0
Reputation: 6090
When I bump into things like this, the first thing I do is play around with the binding mode. Something like:
ItemsSource="{Binding Path=ViewProperties.MaterialDropDownValues, Mode=TwoWay}"
That sometimes trips you up. The other thing I would make sure of is that if you're instantiating new ViewProperties object(s) following your initial load, you notify change on that. If you don't, the XAML will be referring to an outdated version of the object while your code behind/view model is operating on a different one.
Upvotes: 0