【问题标题】:Let user select what columns to display on WPF DataGrid让用户选择要在 WPF DataGrid 上显示的列
【发布时间】:2011-06-07 13:24:48
【问题描述】:

我的DataGrid 有一组默认显示的列,但我还想让用户选择/取消选择在他们的应用程序上显示的列。在 WPF 中是否有相对简单的方法来做到这一点?

DataGrid 绑定到 DataTable

注意:如果上述功能过于复杂,我可以通过RadioButton 解决方案使用简单的“默认列/所有列”。

【问题讨论】:

    标签: c# wpf wpf-controls wpfdatagrid


    【解决方案1】:

    简短的回答是,将每列的 Visibility 属性绑定到您可以设置的布尔标志(通过 CheckBox 或其他机制),并使用 BooleanToVisibilityConverter 使列可见 当标志未设置时折叠。

    挖掘这个similar question,尤其是this answer!他的博客文章列出了我理想的解决方案。 :)

    【讨论】:

      【解决方案2】:

      DataGrid.ColumnsDataTemplate 绑定到ItemsControl,其中包含CheckBox 用于可见性切换,除了VisbilityToBoolConverter 之外不需要任何代码:

      <Window
          ...
          DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}" Loaded="Window_Loaded">
          <Window.Resources>
              <local:VisibilityToBoolConverter x:Key="VisibilityToBoolConv"/>
          </Window.Resources>
          <StackPanel Orientation="Vertical">
              <DataGrid ItemsSource="{Binding Data}" Name="DGrid"/>
              <ItemsControl ItemsSource="{Binding ElementName=DGrid, Path=Columns}" Grid.IsSharedSizeScope="True" Margin="5">
                  <ItemsControl.ItemTemplate>
                      <DataTemplate>
                          <Grid>
                              <Grid.ColumnDefinitions>
                                  <ColumnDefinition SharedSizeGroup="A"/>
                                  <ColumnDefinition SharedSizeGroup="B"/>
                              </Grid.ColumnDefinitions>
                              <TextBlock Text="{Binding Header}" Margin="5"/>
                              <CheckBox Grid.Column="1"  IsChecked="{Binding Visibility, Converter={StaticResource VisibilityToBoolConv}}" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                          </Grid>
                      </DataTemplate>
                  </ItemsControl.ItemTemplate>
              </ItemsControl>
          </StackPanel>
      </Window>
      

      注意:我有一个TextBlock,它假定 Column-Header 是一个字符串,如果不是这样,可能需要调整。


      可见性转换器:

      [ValueConversion(typeof(Visibility), typeof(bool))]
      public class VisibilityToBoolConverter : IValueConverter
      {
          #region IValueConverter Members
      
          public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
          {
              Visibility vis = (Visibility)value;
              switch (vis)
              {
                  case Visibility.Collapsed:
                      return false;
                  case Visibility.Hidden:
                      return false;
                  case Visibility.Visible:
                      return true;
              }
              return false;
          }
      
          public object ConvertBack(object value, Type targetType, object parameter,
              System.Globalization.CultureInfo culture)
          {
              if ((bool)value) return Visibility.Visible;
              else return Visibility.Collapsed;
          }
      
          #endregion
      }
      

      【讨论】:

      • +1 表示努力,@H.B.这是我在回答中懒得写的很多代码。 :)
      • 我确实在这方面投入了太多时间......诅咒你 Stack-Overflow!
      【解决方案3】:

      我更喜欢扩展 DataGrid 类并添加此功能。

      public class DataGridEx : DataGrid
      {
          public DataGridEx() : base()
          {
              // Create event for right click on headers
              var style = new Style { TargetType = typeof(DataGridColumnHeader) };
              var eventSetter = new EventSetter(MouseRightButtonDownEvent, new MouseButtonEventHandler(HeaderClick));
              style.Setters.Add(eventSetter);
              ColumnHeaderStyle = style;
          }
      
          private void HeaderClick(object sender, MouseButtonEventArgs e)
          {
              ContextMenu menu = new ContextMenu();
              // Fill context menu with column names and checkboxes
              var visibleColumns = this.Columns.Where(c => c.Visibility == Visibility.Visible).Count();
              foreach (var column in this.Columns)
              {
                  var menuItem = new MenuItem
                  {
                      Header = column.Header.ToString(),
                      IsChecked = column.Visibility == Visibility.Visible,
                      IsCheckable = true,
                      // Don't allow user to hide all columns
                      IsEnabled = visibleColumns > 1 || column.Visibility != Visibility.Visible
                  };
                  // Bind events
                  menuItem.Checked += (object a, RoutedEventArgs ea)
                      => column.Visibility = Visibility.Visible;
                  menuItem.Unchecked += (object b, RoutedEventArgs eb)
                      => column.Visibility = Visibility.Collapsed;
                  menu.Items.Add(menuItem);
              }
              // Open it
              menu.IsOpen = true;
          }
      }
      

      现在你可以使用这个控件代替原来的DataGrid

      <dg:DataGridEx ItemsSource="{Binding OfflineData, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False">
          <dg:DataGridEx.Columns>
              <DataGridTextColumn Binding="{Binding PortID}" Header="ID" Width="50" Visibility="Collapsed"/>
              <DataGridTextColumn Binding="{Binding SwitchIP}" Header="Switch IP" Width="100" Visibility="Visible"/>
              <DataGridTextColumn Binding="{Binding Port}" Header="Port" Width="50" Visibility="Visible"/>
          </dg:DataGridEx.Columns>
      </dg:DataGridEx>
      

      现在用户可以右键单击列标题以打开带有复选框的菜单:

      【讨论】:

        猜你喜欢
        • 2016-02-28
        • 1970-01-01
        • 2012-11-13
        • 1970-01-01
        • 2013-04-19
        • 2019-02-14
        • 2017-08-03
        • 2014-08-01
        • 1970-01-01
        相关资源
        最近更新 更多