【问题标题】:WPF datagrid collapse details row on clickWPF datagrid 单击时折叠详细信息行
【发布时间】:2012-11-01 12:28:03
【问题描述】:

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

我根据其他地方的这篇帖子提出了这个解决方案: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;
    }

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

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

【问题讨论】:

    标签: wpf datagrid collapse rowdetails


    【解决方案1】:

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

    当您通过可视化树从原始源返回到 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;
        }
    

    【讨论】:

    • 当您选择另一行时,这不会按预期工作 - 新选择的行的详细信息可见,具体取决于前一行中的详细信息状态。
    【解决方案2】:

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

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

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

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

    要将鼠标点击事件链接到属性的更改,您可以执行一些花哨的附加行为命令,如here 所示,或者只是使用后面的代码直接调用视图模型(为了简单起见,我经常自己这样做任务):

    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;
        }
    }
    

    【讨论】:

    • 完美运行。谢谢。
    • 在真正纯粹的 MVVM 中——如果你想在 WPF 之外重用 VM——VM 不应该依赖于 System.Windows.Controls 所在的 DataGridRowDetailsVisibilityMode
    • @Jinjinov 是的,在 Viewmodel 上创建一个布尔或枚举属性并使用转换器。留给读者作为练习。
    【解决方案3】:

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

    通过针对 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;
                    }
                }
            }
        }
    

    【讨论】:

      【解决方案4】:

      这结合了 Grafix 的答案和 Prethen 的答案。

      如果您希望仅在已选择行时切换行详细信息,请使用它:

      private void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
      {
          if (sender is DataGrid dataGrid && 
              e.OriginalSource is FrameworkElement frameworkElement && 
              frameworkElement.DataContext == dataGrid.SelectedItem)
          {
              if (dataGrid.RowDetailsVisibilityMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
                  dataGrid.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed;
              else
                  dataGrid.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-01
        • 2010-11-28
        • 2016-03-18
        • 1970-01-01
        • 1970-01-01
        • 2019-06-06
        • 2019-03-26
        • 2023-04-06
        相关资源
        最近更新 更多