WPF DataGrid全行选择

时间:2011-04-01 21:00:07

标签: wpf listview datagrid selection

我正在使用WPF和.NET 4.0。最近在我的一个程序中,我使用ListView和GridView切换到DataGrid。

我希望能够像在ListView中一样选择并突出显示整行。

在ListView中,当我点击最后一列的空白区域时,我仍然可以选择该行。整行都突出显示,而不仅仅是细胞。

然而,在DataGrid中,在设置SelectionMode =“Single”和SelectionUnit =“FullRow”之后,只有当我点击其中的任何单元格而不是在最后一列的空白区域时,才可以选择该行。

如何在此处使用ListView中的突出显示行为?

4 个答案:

答案 0 :(得分:9)

有两种解决方案:

  1. 将DataGrid中最后一列的宽度设置为Width =“*”。
  2. 第二种解决方案是解决方法。在最后一列之后添加额外的空列(即既未设置其标题也未设置绑定属性)并将其宽度设置为Width =“*”
  3. 我个人更喜欢第一种解决方案,它比第二种解决方案更干净。

答案 1 :(得分:1)

如果您可以在项目中使用代码,还有一个解决方案。您可以处理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;
    }

答案 2 :(得分:1)

根据Aleksey L.先前的评论,以下是带有 FullRowSelect 依赖属性的 DataGridBehavior 类的解决方案。

行为将自动附加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
    }
}

答案 3 :(得分:1)

其中一些解决方案在我的情况下不起作用。所以我所做的是将事件重新路由到行的最后一个单元格(最接近点击)。您可以将其添加到行为或代码隐藏中:

_dataGrid.MouseLeftButtonDown += (sender, args) =>
{
        //If click was on row border, reroute to latest cell of row
        if (!(args.OriginalSource is Border border) || !(border.Child is SelectiveScrollingGrid grid)) return;

        var cellsPresenter = grid.Children.OfType<DataGridCellsPresenter>().FirstOrDefault();
        if (cellsPresenter == null || cellsPresenter.Items.Count < 1) return;

        var lastCell = (DataGridCell)cellsPresenter.ItemContainerGenerator.ContainerFromIndex(cellsPresenter.Items.Count - 1);
        lastCell.RaiseEvent(args);
};