【问题标题】:Show/hide rows functionality in WPF DataGrid using MVVM pattern使用 MVVM 模式在 WPF DataGrid 中显示/隐藏行功能
【发布时间】:2020-05-21 23:30:19
【问题描述】:

我正在尝试实现一个简单的隐藏/显示行功能。

向用户显示一个带有行的 DataGrid,左侧有一个“隐藏”按钮,用于隐藏给定的行。 还有一个“显示隐藏行”按钮,它将显示所有行,以及隐藏行。隐藏的行应该在左侧“显示行”上有一个按钮,以将其带回主 DataGrid。之后,用户可以再次按下“隐藏隐藏行”。

所有行都是自动生成的。

我的做法:

DataGrid 的来源是:

 private DataView _dataView;

        public DataView DataView
        {
            get { return _dataView; }
            set
            {
                _dataView = value;
                RaisePropertyChanged("DataView");
            }
        }

XAML 添加“隐藏”按钮:

<DataGrid.Columns>
                <DataGridTemplateColumn Header="Hide Row">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="{Binding Path=DataContext.HideRowButtonText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}"  CommandParameter="{Binding Path=SelectedIndex, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Command="{Binding Path=DataContext.HideRowCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
</DataGrid.Columns>

我的尝试:

  1. 操作数据视图
private void HideRow(object obj)
        {
            DataView.Table.Rows.RemoveAt(Convert.ToInt32(obj));
        }

这种修改实际 DataView 的方法的问题是,一旦用户按下“显示隐藏的行”,我希望能够显示所有行。我可以创建几个 DataView,它们将保存隐藏的行、当前行和被带回的行。这似乎不直观。

  1. DataGridRow 上的可见性属性基于this.
<DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="Visibility" Value="{Binding Path=DataContext.RowVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
                </Style>
</DataGrid.RowStyle>

如果我将 RowVisibilty 设置为“Collapsed”,它会折叠所有行,我无法仅隐藏某一行。

  1. 我也知道DataTriggers,但它不依赖于行数据本身,而是依赖于用户。我还查看了Row Filters,但似乎这些取决于正在操作的 DataView。我还研究了一个 CheckBox,它会使用 Visibility Converter 隐藏特定行,但话又说回来,不允许我管理隐藏的行。

我正在尝试找到一种方法来隐藏 x 行,并能够管理它们。我希望能够让它们再次出现,标记为隐藏,这样用户就可以让它们再次可见!

【问题讨论】:

    标签: c# wpf xaml datagrid


    【解决方案1】:

    正确的方法是使用Button.Click 事件注册事件处理程序。这种行为是视图逻辑,不属于视图模型。视图模型不执行视图相关的逻辑。它总是执行模型相关的逻辑。

    另一种解决方案是实现附加行为,它是具有行为的附加属性。

    MainWindow.xaml

    <StackPanel>
      <Button Content="Show All Hidden Rows"  
              Click="ShowAllRows_OnButtonClicked" />
    
      <DataGrid x:Name="MyDataGrid">
        <DataGrid.Columns>
          <DataGridTemplateColumn Header="Hide Row">
            <DataGridTemplateColumn.CellTemplate>
              <DataTemplate>
                <Button Content="Hide Row"
                        Click="HideRow_OnButtonClicked" />
              </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
          </DataGridTemplateColumn>
        </DataGrid.Columns>    
      </DataGrid>
    </StackPanel>
    

    MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
      private void HideRow_OnButtonClicked(object sender, RoutedEventArgs e)
      {
        // Use the extension method to traverse the visual tree to search for the parent row
        if ((sender as DependencyObject).TryFindVisualParentElement(out DataGridRow dataGridRow))
        {
          dataGridRow.Visibility = Visibility.Collapsed;
        }
      }
    
      private void ShowAllRows_OnButtonClicked(object sender, RoutedEventArgs e)
      {
        foreach (object rowData in this.MyDataGrid.Items)
        {
          (this.MyDataGrid.ItemContainerGenerator.ContainerFromItem(rowData) as FrameworkElement).Visibility =
            Visibility.Visible;
        }
      }
    }
    

    HelperExtensions.cs

    public static class HelperExtensions
    {
      public static bool TryFindVisualParentElement<TParent>(this DependencyObject child, out TParent resultElement)
        where TParent : DependencyObject
      {
        resultElement = null;
    
        DependencyObject parentElement = VisualTreeHelper.GetParent(child);
    
        if (parentElement is TParent parent)
        {
          resultElement = parent;
          return true;
        }
    
        return parentElement?.TryFindVisualParentElement(out resultElement) ?? false;
      }
    }
    

    【讨论】:

    • 这看起来是一个了不起的解决方案!我唯一的问题是“ShowAllRows”函数显示所有行,而不标记以前隐藏的行!这个想法是,用户可以在隐藏后选择几行恢复可见性。
    猜你喜欢
    • 1970-01-01
    • 2011-07-18
    • 2020-01-06
    • 2011-12-24
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多