Выбор полной строки WPF DataGrid

Я использую WPF и .NET 4.0. Недавно в одной из моих программ я переключился с использования ListView с GridView на DataGrid.

Я хочу иметь возможность выбирать и выделять целую строку, как это было в ListView.

В ListView, когда я нажимаю на пустое пространство справа от последнего столбца, я все еще могу выбрать строку. Вся строка подсвечивается не только ячейками.

Однако в DataGrid после установки SelectionMode = "Single" и SelectionUnit = "FullRow" строка выбирается только тогда, когда я нажимаю на любую ячейку в ней, а не в пустое пространство справа до последнего столбца.

Как я могу использовать поведение выделения из ListView здесь?

Ответ 1

Существует два решения:

  • Установите ширину последнего столбца в DataGrid на Width = "*".
  • Второе решение является обходным решением. Добавьте дополнительный пустой столбец после последнего столбца (т.е. Не устанавливая его свойства заголовка или связывания) и установите его ширину в Width = "*"

Я лично предпочитаю первое решение, оно более чистое, чем второе.

Ответ 2

Есть еще одно решение, если вы можете использовать код в своем проекте. Вы можете обрабатывать событие mouse down в datagrid и программно выбирать строку с щелчком:

 private void SomeGridMouseDown(object sender, MouseButtonEventArgs e)
    {
        var dependencyObject = (DependencyObject)e.OriginalSource;

        //get clicked row from Visual Tree
        while ((dependencyObject != null) && !(dependencyObject is DataGridRow))
        {
            dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
        }

        var row = dependencyObject as DataGridRow;
        if (row == null)
        {
            return;
        }

        row.IsSelected = true;
    }

Ответ 3

Основываясь на предыдущем комментарии Алексея Л., вот решение с классом DataGridBehavior с свойством зависимости FullRowSelect.

Поведение автоматически присоединяет обработчик событий MouseDown. Кроме того, он установит "SelectionMode = DataGridSelectionMode.Single", чтобы он корректно работал с привязкой DataContext и SelectedItem.

XAML

<UserControl x:Class="WpfDemo.Views.Default"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:b="clr-namespace:WpfDemo.Behaviors"
         mc:Ignorable="d" 
         d:DesignHeight="300">

        <DataGrid b:DataGridBehavior.FullRowSelect="True">
              ...
        </DataGrid>             

Класс DataGridBehavior

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfDemo.Behaviors
{
    /// <summary>
    /// Extends <see cref="DataGrid"/> element functionality.
    /// </summary>
    public static class DataGridBehavior
    {
        #region - Dependency properties -

        /// <summary>
        /// Forces row selection on empty cell, full row select.
        /// </summary>
        public static readonly DependencyProperty FullRowSelectProperty = DependencyProperty.RegisterAttached("FullRowSelect",
            typeof(bool),
            typeof(DataGridBehavior),
            new UIPropertyMetadata(false, OnFullRowSelectChanged));

        #endregion

        #region - Public methods -

        /// <summary>
        /// Gets property value.
        /// </summary>
        /// <param name="grid">Frame.</param>
        /// <returns>True if row should be selected when clicked outside of the last cell, otherwise false.</returns>
        public static bool GetFullRowSelect(DataGrid grid)
        {
            return (bool)grid.GetValue(FullRowSelectProperty);
        }

        /// <summary>
        /// Sets property value.
        /// </summary>
        /// <param name="grid">Frame.</param>
        /// <param name="value">Value indicating whether row should be selected when clicked outside of the last cell.</param>
        public static void SetFullRowSelect(DataGrid grid, bool value)
        {
            grid.SetValue(FullRowSelectProperty, value);
        }

        #endregion

        #region - Private methods -

        /// <summary>
        /// Occurs when FullRowSelectProperty has changed.
        /// </summary>
        /// <param name="depObj">Dependency object.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnFullRowSelectChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            DataGrid grid = depObj as DataGrid;
            if (grid == null)
                return;

            if (e.NewValue is bool == false)
            {
                grid.MouseDown -= OnMouseDown;

                return;
            }

            if ((bool)e.NewValue)
            {
                grid.SelectionMode = DataGridSelectionMode.Single;

                grid.MouseDown += OnMouseDown;
            }
        }

        private static void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            var dependencyObject = (DependencyObject)e.OriginalSource;

            while ((dependencyObject != null) && !(dependencyObject is DataGridRow))
            {
                dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
            }

            var row = dependencyObject as DataGridRow;
            if (row == null)
            {
                return;
            }

            row.IsSelected = true;
        }

        #endregion
    }
}