I have an issue with WPF DataGrid
, which drives me crazy.
Let's consider this view model:
public class ViewModel : INotifyPropertyChanged
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected
{
get { return isSelected; }
set
{
System.Diagnostics.Debug.WriteLine("{0}'s IsSelected new value is: {1}", Name, value);
if (isSelected != value)
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
private bool isSelected;
// INPC implementation
}
... this XAML:
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid ItemsSource="{Binding}" IsReadOnly="True" AutoGenerateColumns="False"
SelectionMode="Extended" SelectionUnit="FullRow">
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</DataGrid.ItemContainerStyle>
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="Is selected" Binding="{Binding IsSelected}"/>
<DataGridTextColumn Header="Id" Binding="{Binding Id}"/>
<DataGridTextColumn Header="Name" Width="*" Binding="{Binding Name}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
...and this code-behind:
public partial class MainWindow : Window
{
private IList<ViewModel> GenerateViewModels()
{
var viewModels = new List<ViewModel>();
for (var i = 0; i < 100; i++)
{
viewModels.Add(new ViewModel
{
Id = i,
Name = string.Format("Item {0}", i)
});
}
return viewModels;
}
public MainWindow()
{
InitializeComponent();
DataContext = GenerateViewModels();
}
}
Case 1.
Debug output:
Item 0's IsSelected new value is: True
Item 0's IsSelected new value is: False
Item 10's IsSelected new value is: True
Item 10's IsSelected new value is: False
Case 2.
Debug output:
Item 0's IsSelected new value is: True
Item 1's IsSelected new value is: True
Item 2's IsSelected new value is: True
Item 2's IsSelected new value is: False
Item 10's IsSelected new value is: True
The problem is reproducing, when the selection mode is extended. When it is single, everything works fine.
Questions:
1. Am I missing something?
2. Anybody knows a workaround?
UPDATE.
I've added SelectionChanged
event handler for the grid:
private void MyGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems != null)
{
foreach (var item in e.AddedItems.Cast<ViewModel>())
{
System.Diagnostics.Debug.WriteLine("** Item {0} is added to selection.", item.Id);
}
}
if (e.RemovedItems != null)
{
foreach (var item in e.RemovedItems.Cast<ViewModel>())
{
System.Diagnostics.Debug.WriteLine("** Item {0} is removed from selection.", item.Id);
}
}
e.Handled = true;
}
Debug output says, that SelectedItems
collection is updated properly. E.g., for the first case output will be:
Item 0's IsSelected new value is: True
** Item 0 is added to selection.
Item 0's IsSelected new value is: False
Item 10's IsSelected new value is: True
** Item 10 is added to selection.
** Item 0 is removed from selection.
Item 10's IsSelected new value is: False
** Item 0 is added to selection.
** Item 10 is removed from selection.
But the bound data property IsSelected
isn't updated!
At least, one workaround is found, and its related to the question's update.
Let's modify SelectionChanged
event handler a little:
private void MyGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems != null)
{
foreach (var item in e.AddedItems.Cast<ViewModel>())
{
System.Diagnostics.Debug.WriteLine("** Item {0} is added to selection.", item.Id);
if (!item.IsSelected)
{
// if bound data item still isn't selected, fix this
item.IsSelected = true;
}
}
}
if (e.RemovedItems != null)
{
foreach (var item in e.RemovedItems.Cast<ViewModel>())
{
System.Diagnostics.Debug.WriteLine("** Item {0} is removed from selection.", item.Id);
if (item.IsSelected)
{
// if bound data item still is selected, fix this
item.IsSelected = false;
}
}
}
e.Handled = true;
}
But it's definitely a bug in DataGrid
, isn't it?