简体   繁体   中英

INotifyPropertyChanged not working with WPF data binding

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.

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.

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM