Is there a way to hide a specific column in a Data

2019-01-17 15:51发布

问题:

I have a WPF 4.0 DataGrid that is bound to a DataTable using AutoGenerateColumns=True. The columns are dynamic, however I know there is always going to be a column named ID and I would like to hide this column. Is there a way I can do this?

回答1:

in your datagrid, subscribe for the AutoGeneratingColumn event, the event args (DataGridAutoGeneratingColumnEventArgs) has the column name and a "Cancel", if the column name is ID then set Cancel = true. should do the trick.



回答2:

You can use a behavior (reusable code) to do the job... This way you can use attribute which would centralize the column visibility in one place.

Usage:

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

<DataGrid ...
    extension:DataGridBehavior.UseBrowsableAttributeOnColumn="True">

...

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

Code:

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" stackoverflow user on webpage: 
                    // https://stackoverflow.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;
                    }
                }
            }
        }
    }
}


回答3:

Other possibility would be 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:

I can't speak for 4, however it was not possible in 3.5 SP1, at least without registering for an event which I wanted to avoid at all costs.

What you could do instead is change your generation code to AutoGenerateColumns=False then just place the columns you care about within the XAML as the underlying data will all still be placed within the columns appropriately

            <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}"/>

This will allow you to display the only columns you care about in relation to the underlying model as well as change the Header to display as you see fit, so you are not tied to the Property name on the model.



回答5:

I wouldn't say it's great solution... but... you can have one more abstraction layer for example let's say you have an object like:

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

    public string Property2 { get; set; }

    public string Property3 { set; get; }
}

You don't want column for Id, so you create new object

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

    public string Property3 { set; get; }
}

then map/convert Foo to Foo2 and you are done.

Another possible way (not always possible) is to change access modifier to internal

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

    public string Property2 { get; set; }

    public string Property3 { set; get; }
}

this way you won't have Id column generated either.