Ryan Searle
Ryan Searle

Reputation: 1627

Hide a Column from a DataGrid when the ItemSource is an Observable Collection

I have a DataGrid where the ItemSource is an Observable Collection bound using MVVM archetype. I would like to not show the ID property of the class displayed in my DataGrid however I still need the property to exist.

My Code:

XAML

<DataGrid ItemsSource="{Binding MyData}" IsReadOnly="True" Name="dtSearch" />

View Model

    private ObservableCollection<MyDataClass> myData;
    public ObservableCollection<MyDataClass> MyData
    {
        get { return myData; }
        set
        {
            myData= value;
            RaisePropertyChanged("MyData");
        }
    }

Observable Class

public partial class MyDataClass
{
    public int ID { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
}

Is there an attribute I can give my ID property to hide it from the DataGrid?

Do I need to create another class for visible properties?

Upvotes: 6

Views: 7804

Answers (4)

mstyrcz
mstyrcz

Reputation: 1

You can modify columns in the AutoGeneratedColumns event of the DataGrid object. You can rename them and remove those that you don't want to be displayed.

Upvotes: 0

ΩmegaMan
ΩmegaMan

Reputation: 31721

This issue will happen regardless of whether the data resides in an ObservableCollection or not.

To correct this, one must set the grid to not auto generate the columns. That is done by setting the property AutoGenerateColumns=False and then in the xaml specify the columns desired.

<DataGrid ItemsSource="{Binding  MyData}" AutoGenerateColumns="False" >
   <DataGrid.Columns>
      <DataGridTextColumn Header="The Code"
                          Binding="{Binding Code}"/>
      <DataGridTextColumn Header="The Name"
                          Binding="{Binding Name}"/>
      <DataGridTextColumn Header="The Type"
                          Binding="{Binding Type}"/>
   </DataGrid.Columns>
  </DataGrid>

Check out more column options in the documentation for the DataGrid.

Upvotes: 9

Ivan Stoev
Ivan Stoev

Reputation: 205899

WPF data binding engine binds to all public properties of the object. So, the simplest is to make your ID property internal (if that doesn't break any other code).
However, there is a more general approach when binding to a list of objects. First, put the following in some common place:

public class BindableCollection<T> : ObservableCollection<T>, ITypedList
{
    string ITypedList.GetListName(PropertyDescriptor[] listAccessors) { return null; }
    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        return TypeDescriptor.GetProperties(typeof(T), PropertyFilter);
    }
    static readonly Attribute[] PropertyFilter = { BrowsableAttribute.Yes };
}

and use that class instead of ObservableCollection<T>. Then just use Browsable attribute to hide members of the item class. For your example it's something like this:

View Model

private BindableCollection<MyDataClass> myData;
public BindableCollection<MyDataClass> MyData
{
    get { return myData; }
    set
    {
        myData= value;
        RaisePropertyChanged("MyData");
    }
}

Observable Class

public partial class MyDataClass
{
    [Browsable(false)]
    public int ID { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
}

Upvotes: 8

jsanalytics
jsanalytics

Reputation: 13188

XAML:

  <DataGrid x:Name="dataGrid1" Margin="0" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
                <DataGridTextColumn Binding="{Binding Code}" Header="Code"/>
                <DataGridTextColumn Binding="{Binding Type}" Header="Type"/>
            </DataGrid.Columns>
   </DataGrid>

Code behind:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ObservableCollection<MyDataClass> data = new ObservableCollection<MyDataClass>();
        data.Add(new MyDataClass { Code = "Code 1", ID = 1, Name = "Name 1", Type = "Type 1" });
        data.Add(new MyDataClass { Code = "Code 2", ID = 2, Name = "Name 2", Type = "Type 2" });
        data.Add(new MyDataClass { Code = "Code 3", ID = 3, Name = "Name 3", Type = "Type 3" });
        data.Add(new MyDataClass { Code = "Code 4", ID = 4, Name = "Name 4", Type = "Type 4" });
        data.Add(new MyDataClass { Code = "Code 5", ID = 5, Name = "Name 5", Type = "Type 5" });

        dataGrid1.ItemsSource = data;
    }

Result:

enter image description here

Upvotes: 2

Related Questions