【问题标题】:Is there a way to hide a specific column in a DataGrid when AutoGenerateColumns=True?当 AutoGenerateColumns=True 时,有没有办法隐藏 DataGrid 中的特定列?
【发布时间】:2026-02-18 09:25:01
【问题描述】:

我有一个使用 AutoGenerateColumns=True 绑定到 DataTable 的 WPF 4.0 DataGrid。这些列是动态的,但是我知道总会有一个名为 ID 的列,我想隐藏此列。有什么办法可以做到吗?

【问题讨论】:

    标签: wpf xaml datagrid


    【解决方案1】:

    在您的数据网格中,订阅AutoGeneratingColumn 事件,事件args (DataGridAutoGeneratingColumnEventArgs) 具有列名和“Cancel”,如果列名是ID,则设置Cancel = true。应该做的伎俩。

    【讨论】:

    • 那行得通……虽然它立即违反了 MVVM 模式……但毫无疑问会奏效。
    • 谢谢,这会很好用。在这种情况下,我不太关心 MVVM,因为 DataGrid 是自定义 UserControl 的一部分,如果它只影响视图,我使用代码隐藏没有问题。
    • @Aaron,如果你依赖 View 来生成 MV,那么我想你会发现它不符合 MVVM :)
    • 您可以构建一个视图模型,同时公开DataTable 和自动生成应该跳过的列列表,让AutoGeneratingColumn 事件使用该列表,然后晚上睡觉确保您仍然将视图与视图模型分开。
    【解决方案2】:

    您可以使用一种行为(可重用代码)来完成这项工作...这样您就可以使用将列可见性集中在一个地方的属性。

    用法:

    <Window
    ...
     xmlns:extension="clr-namespace:WpfControlLibrary.Extension;assembly=WpfControlLibrary">
    
    <DataGrid ...
        extension:DataGridBehavior.UseBrowsableAttributeOnColumn="True">
    

    ...

    public class YourObjectItem
    {
        [Browsable(false)]
            public Assembly Assembly { get; set; }
    

    代码:

    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace HQ.Wpf.Util.Behaviors
    {
        /// <summary>
        /// Using this behavior on a dataGRid will ensure to display only columns with "Browsable Attributes"
        /// </summary>
        public static class DataGridBehavior
        {
            public static readonly DependencyProperty UseBrowsableAttributeOnColumnProperty =
                DependencyProperty.RegisterAttached("UseBrowsableAttributeOnColumn",
                typeof(bool),
                typeof(DataGridBehavior),
                new UIPropertyMetadata(false, UseBrowsableAttributeOnColumnChanged));
    
            public static bool GetUseBrowsableAttributeOnColumn(DependencyObject obj)
            {
                return (bool)obj.GetValue(UseBrowsableAttributeOnColumnProperty);
            }
    
            public static void SetUseBrowsableAttributeOnColumn(DependencyObject obj, bool val)
            {
                obj.SetValue(UseBrowsableAttributeOnColumnProperty, val);
            }
    
            private static void UseBrowsableAttributeOnColumnChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                var dataGrid = obj as DataGrid;
                if (dataGrid != null)
                {
                    if ((bool)e.NewValue)
                    {
                        dataGrid.AutoGeneratingColumn += DataGridOnAutoGeneratingColumn;
                    }
                    else
                    {
                        dataGrid.AutoGeneratingColumn -= DataGridOnAutoGeneratingColumn;
                    }
                }
            }
    
            private static void DataGridOnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
            {
                var propDesc = e.PropertyDescriptor as PropertyDescriptor;
    
                if (propDesc != null)
                {
                    foreach (Attribute att in propDesc.Attributes)
                    {
                        var browsableAttribute = att as BrowsableAttribute;
                        if (browsableAttribute != null)
                        {
                            if (!browsableAttribute.Browsable)
                            {
                                e.Cancel = true;
                            }
                        }
    
                        // As proposed by "dba" * user on webpage: 
                        // https://*.com/questions/4000132/is-there-a-way-to-hide-a-specific-column-in-a-datagrid-when-autogeneratecolumns
                        // I added few next lines:
                        var displayName = att as DisplayNameAttribute;
                        if (displayName != null)
                        {
                            e.Column.Header = displayName.DisplayName;
                        }
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 这正是我想要的!在 .NET 4.6.1 上测试和工作:)
    • 谢谢!很高兴知道它仍然可以正常工作:)!
    • DataGrid 应该以这种方式开箱即用恕我直言,并从 DisplayNameAttriibute 中获取标题!
    • 扩展 @EricOuellet 的优秀解决方案来尊重 Displayname 属性只需将 var displayName = att as DisplayNameAttribute; if (displayName != null) { e.Column.Header = displayName.DisplayName; } 在循环中
    • 有人能告诉我为什么我们将 clr-namespace 设置为 WpfControlLibrary.Extension 而不是代码中的内容吗? IE。对于同一项目中的班级:xmlns:extension="clr-namespace:HQ.Wpf.Util.Behaviors"
    【解决方案3】:

    其他可能是Visibility.Collapsed:

        private void dataGrid_AutoGeneratingColumn(object sender, 
            DataGridAutoGeneratingColumnEventArgs e)
        {
            //Set properties on the columns during auto-generation 
            switch (e.Column.Header.ToString())
            {
                case "rownameYouWantToHide":
                    e.Column.Visibility = Visibility.Collapsed;
                    break;
            }
        }
    

    【讨论】:

      【解决方案4】:

      我不会说这是一个很好的解决方案...但是...您可以再拥有一个抽象层 例如,假设您有一个对象:

      public class Foo
      {
          public string Id { get; set; }
      
          public string Property2 { get; set; }
      
          public string Property3 { set; get; }
      }
      

      您不想要 Id 列,因此您创建新对象

      public class Foo2
      {
          public string Property2 { get; set; }
      
          public string Property3 { set; get; }
      }
      

      然后将 Foo 映射/转换为 Foo2 就完成了。

      另一种可能的方式(并非总是可能)是将访问修饰符更改为internal

      public class Foo
      {
          internal string Id { get; set; }
      
          public string Property2 { get; set; }
      
          public string Property3 { set; get; }
      }
      

      这样您也不会生成 Id 列。

      【讨论】:

        【解决方案5】:

        我使用Browsable 属性和Visibility: Collapsed 实现了这一点

        型号

        class CourseModel
        {
            [Description("")]
            [ReadOnly(false)]
            public bool Select { get; set; } = true; // Checkbox
        
            [Description("Course ID")]
            [ReadOnly(true)]
            [Browsable(false)]
            public string ID { get; set; } // Hidden column
        
            [Description("Course Title")]
            [ReadOnly(true)]
            public string Title { get; set; }
        }
        

        自定义控件扩展:

        using System.ComponentModel;
        using System.Windows;
        using System.Windows.Controls;
        
        namespace MyProject.FrontEnd.Controls
        {
            class CustomDataGrid : DataGrid
            {
                // Take attributes of POCO, if available (https://*.com/a/17255496/979621)
        
                protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
                {
                    try
                    {
                        base.OnAutoGeneratingColumn(e);
                        var propertyDescriptor = e.PropertyDescriptor as PropertyDescriptor;
                        e.Column.Header = propertyDescriptor.Description;
                        e.Column.IsReadOnly = propertyDescriptor.IsReadOnly;
                        e.Column.Visibility = propertyDescriptor.IsBrowsable 
                                              ? Visibility.Visible 
                                              : Visibility.Collapsed;
                    }
                    catch
                    {
                        // ignore; retain field defaults
                    }
                }
            }
        }
        

        视图模型

        public ObservableCollection<CourseModel> Courses { get; set; }
        

        XAML

        <Window 
            ...
            xmlns:controls="clr-namespace:MyProject.FrontEnd.Controls" 
            ...
        >
        ...
        <controls:CustomDataGrid x:Name="courses" 
            ItemsSource="{Binding Path=Courses, Mode=TwoWay, 
                          NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True}" />
        

        【讨论】:

          【解决方案6】:

          我不能代表 4,但在 3.5 SP1 中这是不可能的,至少在没有注册我想不惜一切代价避免的事件的情况下。

          您可以做的是将您的生成代码更改为 AutoGenerateColumns=False 然后只需将您关心的列放在 XAML 中,因为基础数据仍将全部放置在适当的列中

                      <dg:DataGridTextColumn Header="Display" Binding="{Binding DisplayName}"/>
                      <dg:DataGridTextColumn Header="Host" Binding="{Binding HostName}"/>
                      <dg:DataGridTextColumn Header="Database" Binding="{Binding Database}"/>
                      <dg:DataGridTextColumn Header="Username" Binding="{Binding Username}"/>
                      <dg:DataGridTextColumn Header="Password" Binding="{Binding Password}"/>
          

          这将允许您显示与基础模型相关的唯一列,并将Header 更改为您认为合适的显示,因此您不会被模型上的Property 名称绑定.

          【讨论】:

          • 这不是我的选择,因为我事先不知道列名
          • 这不是从模型生成的吗?数据是什么样的......?
          • 模型只包含一个 DataTable 属性,该属性包含要在 DataGrid 中显示的数据。
          【解决方案7】:

          我最近做了这个,想分享我的解决方案:

          我刚刚创建了一个视图模型,我希望数据网格遵循它,并且对于我希望它忽略的字段(即不自动生成列),只需将这些字段设置为私有。像魅力一样工作,不需要不必要的代码。

          例如,这是我传递给包含数据网格的视图的视图模型。我只需将不希望作为列的字段设置为私有字段即可获得所需的一切,如示例中的“FullPath”字段所示。我知道这可能并非在所有情况下都可行,但对我来说效果很好。

          namespace dev
          {   
              /// <summary>
              /// View model for tag list view in data grid
              /// </summary>
              public class TagDataViewModel : BaseViewModel
              {
                  /// <summary>
                  /// Default constructor
                  /// </summary>
                  /// <param name="path">The JSONPath to this item</param>
                  public TagDataViewModel(string path)
                  {
                      FullPath = path;
                  }
          
                  /// <summary>
                  /// Gets and sets the JSONPath to this item
                  /// </summary>
                  private string FullPath { get; set; }
          
                  /// <summary>
                  /// Gets the name
                  /// </summary>
                  public string Name => ProjectHelpers.GetPropertyValue(FullPath, "Name");
          
                  /// <summary>
                  /// Gets the address
                  /// </summary>
                  public string Address => ProjectHelpers.GetPropertyValue(FullPath, "Address");
          
                  /// <summary>
                  /// Gets the data type
                  /// </summary>
                  public string DataType => ProjectHelpers.GetPropertyValue(FullPath, "DataType");
          
                  /// <summary>
                  /// Gets the scan rate
                  /// </summary>
                  public string ScanRate => ProjectHelpers.GetPropertyValue(FullPath, "ScanRate");
          
                  /// <summary>
                  /// Gets the scaling type
                  /// </summary>
                  public string ScalingType => ProjectHelpers.GetPropertyValue(FullPath, "ScalingType");
              }
          }
          

          【讨论】:

            最近更新 更多