简体   繁体   中英

How to make an ObservableCollection update when an item property is changed

I've seen this question posted (and answered) a number of times, and I still can't seem to figure out what I'm missing...

I have a window with a list of checkboxes, and I want the ability to have checkboxes in the list enabled/disabled dynamically from code-behind. To do that I've got couple of radio buttons that call a code-behind function to toggle the 'Enabled' property of the first entry in the VisibleFeatures collection. Ideally, this would cause the first checkbox + text to enable/disable, but no UI changes occur.

What am I doing wrong?

ViewModel:

public class MyFeature
{
   private bool _supported;
   private bool _enabled;
   private bool _selected;
   public string Name { get; set; }

   public bool Supported
   {
      get { return _supported; }
      set { _supported = value; NotifyPropertyChanged("Supported"); }
   }
   public bool Enabled
   {
      get { return _enabled; }
      set { _visible = value; NotifyPropertyChanged("Enabled"); }
   }
   public bool Selected
   {
      get { return _selected; }
      set { _selected = value; NotifyPropertyChanged("Selected"); }
   }

   public MyFeature(string name)
   {
      Name = name;
      _supported = false;
      _enabled = false;
      _selected = false;
   }

   public event PropertyChangedEventHandler PropertyChanged;
   private void NotifyPropertyChanged(string propertyName)
   {
      if (PropertyChanged != null)
      {
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
   }
}

public ObservableCollection<MyFeature> VisibleFeatures { get; set; }

void VisibleFeatures_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
   if (e.NewItems != null)
      foreach (MyFeature item in e.NewItems)
         item.PropertyChanged += MyFeature_PropertyChanged;

   if (e.OldItems != null)
      foreach (MyFeature item in e.OldItems)
         item.PropertyChanged -= MyFeature_PropertyChanged;
}

void MyFeature_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
   // NotifyPropertyChanged() defined again elsewhere in the class
   NotifyPropertyChanged("VisibleFeatures");
}

public Init()
{
   VisibleFeatures = new ObservableCollection<MyFeature>();
   VisibleFeatures.CollectionChanged += VisibleFeatures_CollectionChanged;
   VisibleFeatures.Add(new MyFeature("Feature1"));
   VisibleFeatures.Add(new MyFeature("Feature2"));
   ...
}

XAML:

<StackPanel>
   <ListView ItemsSource="{Binding VisibleFeatures}">
      <ListBox.ItemTemplate>
         <DataTemplate>
            <StackPanel IsEnabled="{Binding Enabled, Mode=TwoWay}">
               <CheckBox IsChecked="{Binding Selected, Mode=TwoWay}">
                  <TextBlock Text="{Binding Name}" />
               </CheckBox>
            </StackPanel>
         </DataTemplate>
      </ListBox.ItemTemplate>
   </ListView>
</StackPanel>

Your class MyFeature needs to declare that it implements interface INotifyPropertyChanged . Otherwise, there will be no listener generated from XAML to listen to your property change notification.

Beside, from your example, I see no use of notifying VisibleFeatures change.

Derive your class "MyFeature" from INotifyPropertyChanged interface.

Inorder to reflect your runtime changes made in your observable collection in view, it is mandatory to derive your viewmodel class (here MyFeature class) from INotifyPropertyChanged interface.

Also, it is advisable to use same instance of your binding property wherever it is used instead of creating a new instance.

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