单击时 WPF 数据网格折叠详细信息行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13354603/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:10:09  来源:igfitidea点击:

WPF datagrid collapse details row on click

wpfdatagridcollapserowdetails

提问by Yelnic

I needed to collapse the details row of a WPF DataGrid when a user clicked on it, and re-display it when they clicked again. I also wanted to preserve the DataGridRoDetailsVisibilityMode of VisibleWhenSelected, using single selection.

我需要在用户单击 WPF DataGrid 时折叠它的详细信息行,并在他们再次单击时重新显示它。我还想使用单选保留 VisibleWhenSelected 的 DataGridRoDetailsVisibilityMode。

I came up with this solution, based off of this post elsewhere: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0a45b3a7-46d0-45a9-84b2-0062f07f6fec#eadc8f65-fcc6-41df-9ab9-8d93993e114c

我根据其他地方的这篇文章提出了这个解决方案:http: //social.msdn.microsoft.com/Forums/en-US/wpf/thread/0a45b3a7-46d0-45a9-84b2-0062f07f6fec#eadc8f65-fcc6- 41df-9ab9-8d93993e114c

    private bool _rowSelectionChanged;


    private void dgCompletedJobs_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        _rowSelectionChanged = true;
    }

    private void dgCompletedJobsMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        DependencyObject dep = (DependencyObject)e.OriginalSource;

        //navigate up the tree
        while (dep != null &&
            !(dep is DataGridCell) &&
            !(dep is DataGridColumnHeader))
        {
            dep = VisualTreeHelper.GetParent(dep);
        }

        if (dep == null)
        {
            return;
        }

        DataGridCell dgc = dep as DataGridCell;
        if (dgc != null)
        {
            //navigate further up the tree
            while (dep != null && !(dep is DataGridRow))
            {
                dep = VisualTreeHelper.GetParent(dep);
            }

            DataGridRow dgr = dep as DataGridRow;
            DataGrid dg = sender as DataGrid;
            if (dg != null && dgr != null)
            {
                if (dgr.IsSelected && !_rowSelectionChanged)
                {
                    dg.RowDetailsVisibilityMode =
                        (dg.RowDetailsVisibilityMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
                            ? DataGridRowDetailsVisibilityMode.Collapsed
                            : DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
                }
                else
                {
                    dg.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
                }
            }
        }
        _rowSelectionChanged = false;
    }

This appears to solve my problem nicely, but I have a haunting suspicion that this could be done more simply and elegantly, especially since I'm using MVVM on this project. However, I see this as an acceptable usage of event-driven code-behind, because it's purely presentation logic.

这似乎很好地解决了我的问题,但我一直怀疑这可以更简单、更优雅地完成,尤其是因为我在这个项目中使用了 MVVM。但是,我认为这是事件驱动代码隐藏的可接受用法,因为它纯粹是表示逻辑。

Does anyone have a cleaner solution?

有人有更清洁的解决方案吗?

回答by Stephen Holt

To do this with "proper" MVVM, you should bind the RowDetailsVisibilityMode to a property on the view model:

要使用“正确的”MVVM 执行此操作,您应该将 RowDetailsVisibilityMode 绑定到视图模型上的属性:

<DataGrid x:Name="dgCompletedJobs" RowDetailsVisibilityMode="{Binding RowDetailsVisible}"/>

Your view model property would be something like:

您的视图模型属性将类似于:

private DataGridRowDetailsVisibilityMode _rowDetailsVisible;
public DataGridRowDetailsVisibilityMode RowDetailsVisible
{
    get { return _rowDetailsVisible; }
    set {
        _rowDetailsVisible = value;
        if (PropertyChanged != null) {
             PropertyChanged(this, new PropertyChangedEventArgs("RowDetailsVisible"));
        }
    }
}

To link the mouse click event to the changing of the property, you could either do some fancy attached behaviour commanding as indicated here, or just use code behind to call the view model directly (I often do this myself for simple tasks):

要链接的鼠标点击事件的特性改变,你既可以做一些花哨的附加行为,居高临下指示的位置,或者只是使用后面的代码直接调用视图模型(我经常这样做我自己简单的任务):

private void dgCompletedJobsMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    Window1ViewModel viewModel = (Window1ViewModel)DataContext;
    if (viewModel.RowDetailsVisible == DataGridRowDetailsVisibilityMode.Collapsed) {
        viewModel.RowDetailsVisible = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
    } else {
        viewModel.RowDetailsVisible = DataGridRowDetailsVisibilityMode.Collapsed;
    }
}

回答by Grafix

Why don't you use the sender param? If the event is defined on the DataGrid, the sender is always the DataGrid! Use a safe cast en check for null to be safe, but that should do the trick.

为什么不使用发件人参数?如果事件是在 DataGrid 上定义的,则发送方始终是 DataGrid!使用安全强制转换检查 null 是安全的,但这应该可以解决问题。

The code seems unnecessary complicated as you are working back from the original source to your DataGrid through the visual tree.

当您通过可视化树从原始源返回到 DataGrid 时,代码似乎没有必要变得复杂。

        private void dataGridMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        DataGrid dg = sender as DataGrid;
        if (dg == null)
            return;
        if (dg.RowDetailsVisibilityMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
            dg.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed;
        else
            dg.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
    }

回答by Prethen

I came up with a different way, but not a "proper" MVVM way since it uses code behind (as does some of the code in the proposed answers above) but it does the trick with just a few lines of code.

我想出了一种不同的方式,但不是“正确的”MVVM 方式,因为它使用了隐藏代码(就像上面建议的答案中的一些代码一样),但它只用几行代码就可以解决问题。

By coding against the PreviewMouseUp event I was able to get the exact behavior I needed. The code ensures that you've actually clicked on something in the grid and to collapse it has to be the same row already opened.

通过针对 PreviewMouseUp 事件进行编码,我能够获得所需的确切行为。该代码可确保您实际单击了网格中的某些内容,并且折叠它必须是已经打开的同一行。

 private void UIElement_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        DataGrid grid = sender as DataGrid;

        if (grid != null)
        {
            FrameworkElement element = e.OriginalSource as FrameworkElement;

            if (element?.DataContext is MyCustomObject)
            {
                if (grid.SelectedItem == (MyCustomObject) ((FrameworkElement) e.OriginalSource).DataContext)
                {
                    grid.SelectedIndex = -1;
                    e.Handled = true;
                }
            }
        }
    }