none
DataGrid row selection bug

    Question

  •  I created WPF Application (VS 2010, .NET 4) project, you can reproduce this through copying a code into the corresponding files.

    Code for MainWindow.xaml:

     

    <
    Window
     x:Class
    =
    "
    WpfBadDataGridRowIsSelectedBinding.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
    "
    
      ResizeMode
    =
    "
    NoResize
    "
    >
    
     <
    Grid
    >
    
      <
    DataGrid
     ItemsSource
    =
    "
    {Binding List}
    "
     AutoGenerateColumns
    =
    "
    False
    "
     SelectionMode
    =
    "
    Extended
    "
     IsReadOnly
    =
    "
    True
    "
    >
    
       <
    DataGrid.Columns
    >
    
        <
    DataGridTextColumn
     Width
    =
    "
    *
    "
     Header
    =
    "
    Number
    "
     Binding
    =
    "
    {Binding Number, Mode=OneWay}
    "
     />
    
        <
    DataGridCheckBoxColumn
     Width
    =
    "
    *
    "
     Header
    =
    "
    IsSelected
    "
     Binding
    =
    "
    {Binding IsSelected, Mode=TwoWay}
    "
     />
    
       </
    DataGrid.Columns
    >
    
    
       <
    DataGrid.RowStyle
    >
    
        <
    Style
     TargetType
    =
    "
    DataGridRow
    "
    >
    
         <
    Setter
     Property
    =
    "
    IsSelected
    "
     Value
    =
    "
    {Binding IsSelected, Mode=TwoWay}
    "
     />
    
        </
    Style
    >
    
       </
    DataGrid.RowStyle
    >
    
      </
    DataGrid
    >
    
     </
    Grid
    >
    
    </
    Window
    >
    
    

     

    Code for MainWindow.xaml.cs:

     

    namespace
     WpfBadDataGridRowIsSelectedBinding
    {
     using
     System.Collections;
     using
     System.Collections.ObjectModel;
     using
     System.ComponentModel;
    
     ///
     <summary>
    
     ///
     Interaction logic for MainWindow.xaml
    
     ///
     </summary>
    
     public
     partial
     class
     MainWindow
     {
      private
     readonly
     ObservableCollection<SimpleViewModel> list = new
     ObservableCollection<SimpleViewModel>();
    
      public
     MainWindow()
      {
       InitializeComponent();
    
       this
    .DataContext = this
    ;
    
       for
     (var
     i = 0; i < 100; i++)
       {
        this
    .list.Add(new
     SimpleViewModel(i));
       }
      }
    
      public
     IEnumerable List
      {
       get
    
       {
        return
     this
    .list;
       }
      }
    
      private
     sealed
     class
     SimpleViewModel : INotifyPropertyChanged
      {
       private
     readonly
     int
     number;
       private
     bool
     isSelected;
    
       public
     SimpleViewModel(int
     number)
       {
        this
    .number = number;
       }
    
       public
     int
     Number
       {
        get
    
        {
         return
     this
    .number;
        }
       }
    
       public
     bool
     IsSelected
       {
        get
    
        {
         return
     this
    .isSelected;
        }
    
        set
    
        {
         if
     (value == this
    .isSelected)
         {
          return
    ;
         }
    
         this
    .isSelected = value;
    
         this
    .OnPropertyChanged("IsSelected"
    );
        }
       }
    
       #region
     INotifyPropertyChanged Members
    
       public
     event
     PropertyChangedEventHandler PropertyChanged;
    
       private
     void
     OnPropertyChanged(string
     propertyName)
       {
        var
     handler = this
    .PropertyChanged;
    
        if
     (handler != null
    )
        {
         handler(this
    , new
     PropertyChangedEventArgs(propertyName));
        }
       }
    
       #endregion
    
      }
     }
    }
    
    

     

     

    If I click the first row in DataGrid after run then the corresponding checkbox in the column "IsSelected" is checked, and this is OK. The checking works for second, third.. etc rows of the first page. The second page starts from the 15th row and there I have a problem. If I click row 20 the corresponding checkbox isn't checked, the same with row 21, 22 and so on. And if I scroll DataGrid to the end and return scrolling to row 0 then click the row I also don't see checked checkbox, and now this be on all rows in DataGrid.

    What have I done wrong?

    I doubt whether you have testers?

     

    • Changed type shuralex Tuesday, August 10, 2010 11:29 AM
    • Edited by shuralex Tuesday, August 10, 2010 11:31 AM
    Monday, August 09, 2010 1:23 PM

Answers

  • Hi Shuralex,

    This problem is caused by the VisualizingStackPanel, set the VirtualizingStackPanel.IsVirtualizing as false will solve this problem.

    Something likes the follows:

    <DataGrid ItemsSource="{Binding List}" AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" VirtualizingStackPanel.IsVirtualizing="False">

        <DataGrid.Columns>

            <DataGridTextColumn Width="*" Header="Number" Binding="{Binding Number, Mode=OneWay}" />

            <DataGridCheckBoxColumn Width="*" Header="IsSelected" Binding="{Binding IsSelected, Mode=TwoWay}" />

        </DataGrid.Columns>

        <DataGrid.RowStyle>

            <Style TargetType="DataGridRow">

                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />

            </Style>

        </DataGrid.RowStyle>

    </DataGrid>

    Hope this helps.

    Best regards,
    Kevin Pan


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Thursday, August 12, 2010 8:43 AM
    Moderator

All replies

  • Interesting.

    I think you should make the relative binding one way only(OneWay and OneWayToSource). It works when I changed your code to:

    <DataGrid ItemsSource="{Binding List}" AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" > <DataGrid.Columns> <DataGridTextColumn Width="*" Header="Number" Binding="{Binding Number, Mode=OneWay}" /> <DataGridCheckBoxColumn Width="*" Header="IsSelected" Binding="{Binding IsSelected, Mode=OneWay}" /> </DataGrid.Columns> <DataGrid.RowStyle> <Style TargetType="DataGridRow"> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}" /> </Style> </DataGrid.RowStyle> </DataGrid>
    Monday, August 09, 2010 2:28 PM
  • Thank you, Rulin Hong, but I'am need TwoWay mode.
    Monday, August 09, 2010 3:01 PM
  • I retest it that it works for twoway if you set up UpdateSourceTrigger=PropertyChanged in

    <

     

     

    Style TargetType="DataGridRow">

     

     

     

    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

    Monday, August 09, 2010 3:15 PM
  • Not completely correct. Select the row 0, then select row 1 with Ctrl, scroll to end, and select the row 99 without Ctrl, and now scroll to begin,

    voila, the row 0 still selected...

    Monday, August 09, 2010 3:35 PM
  • And another code with slight modifications:

    Code for MainWindow.xaml:

    <Window x:Class="WpfBadDataGridRowIsSelectedBinding.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"
      ResizeMode="NoResize">
      <DockPanel LastChildFill="True">
        <StackPanel DockPanel.Dock="Top" Margin="5" Orientation="Horizontal">
          <Button Height="23" Content="Select" Click="Button_Click"/>
        </StackPanel>
        <DataGrid ItemsSource="{Binding List}" AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True">
          <DataGrid.Columns>
            <DataGridTextColumn Width="*" Header="Number" Binding="{Binding Number, Mode=OneWay}" />
            <DataGridCheckBoxColumn Width="*" Header="IsSelected" Binding="{Binding IsSelected, Mode=TwoWay}" />
          </DataGrid.Columns>
    
          <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
              <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            </Style>
          </DataGrid.RowStyle>
        </DataGrid>
      </DockPanel>
    </Window>
    
    

    Code for MainWindow.xaml.cs:

    namespace WpfBadDataGridRowIsSelectedBinding
    {
      using System.Collections;
      using System.Collections.ObjectModel;
      using System.ComponentModel;
    
      /// <summary>
      /// Interaction logic for MainWindow.xaml
      /// </summary>
      public partial class MainWindow
      {
        private readonly ObservableCollection<SimpleViewModel> list = new ObservableCollection<SimpleViewModel>();
    
        public MainWindow()
        {
          InitializeComponent();
    
          this.DataContext = this;
    
          for (var i = 0; i < 100; i++)
          {
            this.list.Add(new SimpleViewModel(i));
          }
        }
    
        public IEnumerable List
        {
          get
          {
            return this.list;
          }
        }
    
        private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
          for (var i = 0; i < list.Count; i += 2)
          {
            this.list[i].IsSelected = true;
          }
        }
    
        private sealed class SimpleViewModel : INotifyPropertyChanged
        {
          private readonly int number;
          private bool isSelected;
    
          public SimpleViewModel(int number)
          {
            this.number = number;
          }
    
          public int Number
          {
            get
            {
              return this.number;
            }
          }
    
          public bool IsSelected
          {
            get
            {
              return this.isSelected;
            }
    
            set
            {
              if (value == this.isSelected)
              {
                return;
              }
    
              this.isSelected = value;
    
              this.OnPropertyChanged("IsSelected");
            }
          }
    
          #region INotifyPropertyChanged Members
    
          public event PropertyChangedEventHandler PropertyChanged;
    
          private void OnPropertyChanged(string propertyName)
          {
            var handler = this.PropertyChanged;
    
            if (handler != null)
            {
              handler(this, new PropertyChangedEventArgs(propertyName));
            }
          }
    
          #endregion
        }
      }
    }
    
    
    Start the application, click button "Select", and scroll down, nice, huh?

    If you replace the style DataGridRow to:

    <Style TargetType="DataGridRow">
              <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            </Style>
    

    So it will not change anything.

    Monday, August 09, 2010 8:10 PM
  • Hi Shuralex,

    This problem is caused by the VisualizingStackPanel, set the VirtualizingStackPanel.IsVirtualizing as false will solve this problem.

    Something likes the follows:

    <DataGrid ItemsSource="{Binding List}" AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" VirtualizingStackPanel.IsVirtualizing="False">

        <DataGrid.Columns>

            <DataGridTextColumn Width="*" Header="Number" Binding="{Binding Number, Mode=OneWay}" />

            <DataGridCheckBoxColumn Width="*" Header="IsSelected" Binding="{Binding IsSelected, Mode=TwoWay}" />

        </DataGrid.Columns>

        <DataGrid.RowStyle>

            <Style TargetType="DataGridRow">

                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />

            </Style>

        </DataGrid.RowStyle>

    </DataGrid>

    Hope this helps.

    Best regards,
    Kevin Pan


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Thursday, August 12, 2010 8:43 AM
    Moderator
  • Hi Kevin,

    Thank you, I know about it, it just slowly working on real data sources. Temporarily did. I am writing now, "DataGrid" based on
    ListBox (selection there is OK)

    Thursday, August 12, 2010 9:24 AM
  • I can't believe this. O.O Not the only one with a bug there.
    Silvernex Software > Consulting and Development!
    Tuesday, July 12, 2011 9:16 PM