WPF application uses DataGrid with touch screen how to make multiple selection?

Jane Jie Chen 506 Reputation points
2021-10-12T17:34:33.467+00:00

we have a Samples list view which needs to freeze the first three columns.
reference the link: https://learn.microsoft.com/en-us/answers/questions/548781/wpf-listviewgridview-is-it-possible-to-fix-first-s.html

the solution is "to use DataGrid, which is better than ListView. You can use DataGrid to make multiple selections with Ctrl+Click, because its SelectionMode property is set to SelectionMode="Extended" by default. DataGrid also supports sorting by clicking on the column headers. You could refer to the document and sort according to your requirements."

Our WPF application runs on touch screen.
WPF DataGrid behavior: click a row, it unselects previous selected row(s), select the clicked row.
To select multiple rows, press Ctrl key and click each row you want to select.

However, in touch screen, we cannot click ctrl key and the same time to click on each row.
how to make multiple row selections in DataGrid with touch screen? Thx!

Developer technologies | Windows Presentation Foundation
{count} votes

Accepted answer
  1. Jane Jie Chen 506 Reputation points
    2021-11-03T07:29:01.427+00:00

    we just notice that right mouse click on a row does not work.
    if all rows are selected, right mouse click on a row, it only selects that row and remove selections of other rows.

    we add the following codes to make click both Left and Right mouse to work:

    1. add following line " || e.RightButton == MouseButtonState.Pressed". private void PreviewMouseDownHandler(object sender, MouseButtonEventArgs e)
      {
      if ((e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)
      && e.OriginalSource is FrameworkElement element
      && GetVisualParentOfType<DataGridRow>(element) is DataGridRow row)
      {
      row.IsSelected = !row.IsSelected;
      e.Handled = true;
      }
      }

    2) DataGridCell style to set IsHitTestVisible="False" in

    <ControlTemplate TargetType="{x:Type DataGridCell}">  
                        <Border x:Name="borderDataGrid"  
                            Margin="-1"  
                                BorderBrush="LightGray"  
                                BorderThickness="1.5">  
                            <Grid MinHeight="35" MaxHeight="40"  
                                  x:Name="gridCell"  
                                  VerticalAlignment="Center"  
                                  Background="{TemplateBinding Background}">  
                                <!-- Disable right mouse click on grid cell-->  
                                <ContentPresenter VerticalAlignment="Center"   
                                                  **IsHitTestVisible="False"**/>  
                            </Grid>  
    

    Note: since disable "IsHitTestVisible" in cell level and also in cell ContentPresenter. So it will not able to show context menu.
    Disable in Cell ContentPresenter level, so right mouse click will not cause unselect other selected rows.

    0 comments No comments

5 additional answers

Sort by: Most helpful
  1. Jane Jie Chen 506 Reputation points
    2021-10-27T18:53:22.603+00:00

    Thanks for providing suggested solutions!

    If using a checkbox column for each row to show selection, we need to disable DataGridRow selection when clicking on DataGridRow.
    Only click on CheckBox cell in a row will select that row.

    How do we achieve that?
    Is there an example to show us how to achieve this? Thx!

    0 comments No comments

  2. Hui Liu-MSFT 48,681 Reputation points Microsoft External Staff
    2021-11-01T07:19:48.79+00:00

    You could try to refer to the following method to implement multiple selection without Ctrl in the DataGrid. For more methods, you can refer here.
    I set the style background of the DataGridRow to pink to distinguish whether the item is selected.
    The code of xaml:

    <StackPanel Background="AliceBlue" >  
            <DataGrid Name="dataGrid" ItemsSource="{Binding Persons}"  BorderBrush="Black"  
                      SelectionMode="Extended"   SelectionUnit="FullRow"    
                     BorderThickness="1" AutoGenerateColumns="False"  CanUserAddRows="True" >  
                <DataGrid.Resources>  
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>  
                </DataGrid.Resources>  
                <DataGrid.RowStyle>  
                    <Style TargetType="DataGridRow" >  
                        <EventSetter Event="MouseEnter" Handler="MouseEnterHandler"></EventSetter>  
                        <EventSetter Event="PreviewMouseDown" Handler="PreviewMouseDownHandler"></EventSetter>  
                        <Style.Triggers>  
                            <Trigger Property="IsSelected" Value="True">  
                                <Setter Property="Background" Value="Pink"/>  
                            </Trigger>  
                        </Style.Triggers>  
                    </Style>  
                </DataGrid.RowStyle>  
                <DataGrid.Columns>  
                    <DataGridTextColumn Binding="{Binding PersonName}" Header="Name"/>  
                </DataGrid.Columns>  
            </DataGrid>  
        </StackPanel>  
    

    The code of xmal.cs:

    using System.Windows;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System;  
    using System.Windows.Controls;  
    using System.Runtime.CompilerServices;  
    using System.Windows.Input;  
    using System.Windows.Media;  
    
    namespace SelectDataGridItems  
    {  
      public partial class MainWindow : Window  
      {  
        public MainWindow()  
        {  
          InitializeComponent();  
         DataContext=new ViewModel();  
        }  
        private void MouseEnterHandler(object sender, MouseEventArgs e)  
        {  
          if (e.LeftButton == MouseButtonState.Pressed &&  
              e.OriginalSource is DataGridRow row)  
          {  
            row.IsSelected = !row.IsSelected;  
            e.Handled = true;  
          }  
        }  
        private void PreviewMouseDownHandler(object sender, MouseButtonEventArgs e)  
        {  
          if (e.LeftButton == MouseButtonState.Pressed && e.OriginalSource is FrameworkElement element &&  
              GetVisualParentOfType<DataGridRow>(element) is DataGridRow row)  
          {  
            row.IsSelected = !row.IsSelected;  
            e.Handled = true;  
          }  
        }  
        private static DependencyObject GetVisualParentOfType<T>(DependencyObject startObject)  
        {  
          DependencyObject parent = startObject;  
    
          while (IsNotNullAndNotOfType<T>(parent))  
          {  
            parent = VisualTreeHelper.GetParent(parent);  
          }  
          return parent is T ? parent : throw new Exception($"Parent of type {typeof(T)} could not be found");  
        }  
    
        private static bool IsNotNullAndNotOfType<T>(DependencyObject obj)  
        {  
          return obj != null && !(obj is T);  
        }  
      }  
      public class ViewModel : INotifyPropertyChanged  
      {  
        private ObservableCollection<Person> persons = new ObservableCollection<Person>();  
    
        public ObservableCollection<Person> Persons  
        {  
          get { return persons; }  
          set { persons = value;   
           OnPropertyChanged("Persons");}  
        }  
        public ViewModel()  
        {  
          Persons.Add(new Person { PersonName="john"});  
          Persons.Add(new Person { PersonName="joe"});  
          Persons.Add(new Person { PersonName="johnny"});  
        }  
        public event PropertyChangedEventHandler PropertyChanged;  
        protected void OnPropertyChanged([CallerMemberName] string name = null)  
        {  
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));  
        }  
      }  
      public class Person : INotifyPropertyChanged  
      {  
        private string name;  
    
        public string PersonName  
        {  
          get { return name; }  
          set  
          {  
            name = value;  
            OnPropertyChanged("PersonName");  
          }  
        }  
        public event PropertyChangedEventHandler PropertyChanged;  
        protected void OnPropertyChanged([CallerMemberName] string name = null)  
        {  
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));  
        }  
      }  
    }  
    

    The picture of result :
    145367-2.gif


    If the response is helpful, please click "Accept Answer" and upvote it.
     Note: Please follow the steps in our [documentation][5] to enable e-mail notifications if you want to receive the related email notification for this thread.
     

    [5]: https://learn.microsoft.com/en-us/answers/articles/67444/email-notifications.html

    0 comments No comments

  3. Jane Jie Chen 506 Reputation points
    2021-11-02T23:42:12.647+00:00

    HuiLiu,

    Thanks for providing the solution!
    it is very helpful.

    we base on your solution to modify a little bit to make the CheckBox column works with row selections without need to press Ctrl key when click each row.

    the modified code as following line: <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" /> in DataGrid.RowStyle

    <DataGrid.RowStyle>
                                        <Style TargetType="DataGridRow" >
                                            ***<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />***
                                            <Setter Property="MaxHeight" Value="39" />
                                            <EventSetter Event="MouseEnter" Handler="MouseEnterHandler"></EventSetter>
                                            <EventSetter Event="PreviewMouseDown" Handler="PreviewMouseDownHandler"></EventSetter>
                                            <Style.Triggers>
                                                <Trigger Property="IsSelected" Value="True">
                                                    <Setter Property="Background" Value="WhiteSmoke"/>
                                                </Trigger>
                                            </Style.Triggers>
                                        </Style>
                                    </DataGrid.RowStyle>
    
    
     <DataGrid.Columns>
                                        <DataGridCheckBoxColumn Header="Upload" Binding="{Binding IsSelected, Mode=TwoWay}"
                                                                IsThreeState = "False"
                                                                ElementStyle="{StaticResource CheckBoxStyleDisable}"
                                                                Width="120"
                                                                MinWidth="100"
                                                                MaxWidth="130">
                                        </DataGridCheckBoxColumn>
    
    <!-- disable the checkbox, so when click on it, it does not do anything. so data grid row selection works 
             when data grid row selection changes, it will update CheckBox checked status
             Set the IsHitTestVisible property to false for a user interface element, 
             it will no longer respond to mouse input and will not fire mouse-related events.
             It does not disable UIElement -->
        <Style TargetType="{x:Type CheckBox}" x:Key="CheckBoxStyleDisable"
                                       BasedOn="{StaticResource CheckBoxStyle1}">
            <!--<Setter Property="IsEnabled" Value="False"/>-->
            <Setter Property="IsHitTestVisible" Value="False"/>
        </Style>
    
    0 comments No comments

  4. Jane Jie Chen 506 Reputation points
    2021-11-04T00:15:03.67+00:00

    for reference: Full GridCellStyle defined as following:
    <Style x:Key="gridCellStyle2" TargetType="{x:Type DataGridCell}">
    <Setter Property="Padding" Value="10,1,5,1" />
    <Setter Property="Foreground" Value="Black" />
    <Setter Property="Background" Value="LightGray" />
    <Setter Property="FontSize" Value="15" />
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="IsHitTestVisible" Value="False" />
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate TargetType="{x:Type DataGridCell}">
    <Border x:Name="borderDataGrid"
    Margin="-1"
    BorderBrush="LightGray"
    BorderThickness="1.5">
    <Grid MinHeight="35" MaxHeight="40"
    x:Name="gridCell"
    VerticalAlignment="Center"
    Background="{TemplateBinding Background}">
    <!-- Disable right mouse click on grid cell-->
    <ContentPresenter VerticalAlignment="Center"
    IsHitTestVisible="False"/>
    </Grid>
    </Border>
    <ControlTemplate.Triggers>
    <MultiTrigger>
    <MultiTrigger.Conditions>
    <Condition Property="IsSelected" Value="False" />
    <Condition Property="IsReadOnly" Value="True" />
    </MultiTrigger.Conditions>
    <Setter Property="Background" Value="LightGray" />
    </MultiTrigger>
    <MultiTrigger>
    <MultiTrigger.Conditions>
    <Condition Property="IsEnabled" Value="False" />
    <Condition Property="IsReadOnly" Value="True" />
    </MultiTrigger.Conditions>
    <Setter Property="Background" Value="{StaticResource GroupBackgroundColor2}" />
    </MultiTrigger>
    <!-- this trigger does not work when clicking on grid row, it only highlights selected row and highlight three row headers-->
    <!--<Trigger Property="IsSelected" Value="True">
    <Setter Property="Background" TargetName="gridCell" Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}"/>
    <Setter Property="Background" TargetName="borderDataGrid" Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}"/>
    </Trigger>-->
    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=IsSelected}" Value="True">
    <Setter Property="Background" TargetName="gridCell" Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}"/>
    <Setter Property="Background" TargetName="borderDataGrid" Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}"/>
    <Setter Property="Foreground" Value="White"/>
    </DataTrigger>
    </ControlTemplate.Triggers>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.