2
votes

I have a WPF DataGrid bound to an ObservableCollection called "Personnel". I have a DataGridCheckBoxColumn in the DataGrid that is editable. The CheckBoxColumn is bound to a bool value called "AircraftCommanderSelected" in my collection. When a row is selected and the checkbox is checked, an event is fired to update the collection so that all AircraftCommanderSelected values for each "Personnel" are set to false (except for the one that was just set to true). With that said, my collection is updating correctly, but my datagrid will not 'uncheck' the previously checked boxes, who's bound value has been changed to false. How can I notify that the value has been changed? Below is my code (modified for easier reading).

Class

 public class Personnel
 {
      ///
      ///Other objects removed for reading purposes. All follow same format.
      ///
      private bool aircraftCommanderSelected;
      public bool AircrafCommanderSelected
      {
            get { return this.aircraftCommanderSelected; }
            set
            {
                if(this.aircraftCommanderSelected != value)
                {
                     this.aircraftCommanderSelected = value;
                     this.NotifyPropertyChanged("AircraftCommanderSelected");
                }
            }
      }

      public event PropertyChangedEventHandler PropertyChanged;
      public void NotifyPropertyChanged(strin propName)
      {
           if(this.PropertyChanged != null)
           {
               this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
           }
      }
 }

XAML

 <DataGrid Name="dataGrid" AutoGenerateColumns="False" SelectedItem="{Binding Personnel}" CanUserDeleteRows="False" CanUserAddRows="False" IsReadOnly="False" SelectionMode="Single" CellEditEnding="dataGrid_CellEditEnding">
     <DataGrid.Columns>
         <DataGridCheckBoxColumn local:DataGridUtil.Name="ac" Header="AC" Binding="{Binding AircraftCommanderSelected}"/>
     </DataGrid.Columns>
 </DataGrid>

Code Behind

 private void dataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
 {
         foreach (Personnel p in vm.personnel)//Loop through each item in the collection
         {
             //per.ID is the ID of the person who was just edited.
             //This sets everyones value to false except the person that was just edited.
             if (p.ID != per.ID) { p.AircraftCommanderSelected = false; }
         }
  }

When the collection is modified and the property changed event is fired, shouldn't the datagrid update?

I have found a solution but it involves multithreading, which seems like an improper solution to this problem. I also don't like how it refreshes the whole grid and deselects my current selection

 dataGrid.Dispatcher.BeginInvoke(new Action(() => dataGrid.Items.Refresh()), System.Windows.Threading.DispatcherPriority.Background);

Any help is appreciated.

Thanks

-Justin

3

3 Answers

3
votes

There's a series of things you need to check:

  • Are the objects in your ObservableCollection implementing INotifyPropertyChanged properly? (Not in the code it posted)
  • Are there any misspellings or capitalization changes with the property name? If you are on .NET 4.6 you can use the new nameof() property to make sure of that.
  • If the value can be changed from code-behind, then you must use Mode=TwoWay

By default most bindings are OneWay. If your binding mode is one way and you change the value in code behind, the binding will break and no longer work until you reload the XAML.

2
votes

Even though you Personnel class has a PropertyChanged event, its declaration does not indicate it implements INotifyPropertyChanged. Change the class declaration so it reads:

public class Personnel : INotifyPropertyChange {
    // rest of code here
}

Also, the binding needs to be two way. I don't know what the default is for a DataGridCheckBoxColumn, but it can't hurt to make it explicit.

1
votes

Update your binding with BindingMode.TwoWay

<DataGridCheckBoxColumn local:DataGridUtil.Name="ac" Header="AC" Binding="{Binding AircraftCommanderSelected, Mode=TwoWay,  UpdateSourceTrigger=PropertyChanged}"/>

because you are trying to change value from code.