Sunday, February 27, 2011

Hide Extra Blank Column from WPF DataGrid

If you have worked with WPF DataGrid you will be familiar with the problem of extra blank column which appears after last column inside DataGrid. It looks ugly and definitely you would like to get rid of that column. In this post I am going to talk about two ways to hide that extra column. First approach will be based on popular MVVM pattern and second will use a simple event in code behind file to hide that column. You can download a ready to run  code from here which demonstrate both scenarios.

In both scenarios I am setting code behind file as DataContext for my MainWindow and I am binding my DataGrid with a property 'MyView', declared in code behind file, which returns a DataTable as DataView.

   1:  public DataView MyView
   2:  {
   3:       get
   4:       {
   5:            DataTable table = new DataTable();
   6:            DataColumn column1 = new DataColumn("Column1");
   7:            DataColumn column2 = new DataColumn("Column2");
   8:            table.Columns.Add(column1);
   9:            table.Columns.Add(column2);
  10:            //create ten rows
  11:            for (int i = 0; i < 10; i++)
  12:            {
  13:                 DataRow newRow = table.NewRow();
  14:                 newRow["Column1"] = i.ToString();
  15:                 newRow["Column2"] = (i + 100).ToString();
  16:                 table.Rows.Add(newRow);
  17:            }
  18:       return table.AsDataView();
  19:       }
  20:  }

In MVVM based scenario I am encapsulating my DataGrid inside a Grid. Inside Grid you have to declare same number of columns as in your DataView. I am declaring two columns in my Grid because I have two columns in my DataView. I am setting width of my Grid's columns equal to the actual width of columns inside DataGrid.

   1:  <Grid>
   2:       <Grid>
   3:            <Grid.ColumnDefinitions>
   4:                 <ColumnDefinition Width="{Binding ElementName=Col1, Path=ActualWidth}"/>
   5:                 <ColumnDefinition Width="{Binding ElementName=Col2, Path=ActualWidth}"/>
   6:            </Grid.ColumnDefinitions>
   7:   
   8:            <DataGrid Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Path=MyView}" AutoGenerateColumns="False">
   9:                  <DataGrid.Columns>
  10:                      <DataGridTextColumn MinWidth="100" x:Name="Col1" Header="Column1" Binding="{Binding Path=Column1}"/>
  11:                      <DataGridTextColumn MinWidth="100" x:Name="Col2" Header="Column 2" Binding="{Binding Path=Column2}"/>
  12:                 </DataGrid.Columns>
  13:            </DataGrid>
  14:       </Grid>
  15:  </Grid>
That's all, it will do the trick. You won't see any ugly extra column inside your DataGrid.

The second scenario, a non-MVVM based scenario, is sample. I am just handling DataGrid_AutoGeneratingColumn' event in code behind file.

   1:  <DataGrid ItemsSource="{Binding Path=MyView}" AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn"/>
In the actual event handler I am setting width of last column of MyView equal to 'Star'. Star in terms of WPF Grid Length means take all available space. So the last column of DataGrid will take all available space including space of extra blank column and as a result you won't see any extra blank column in DataGrid.

   1:  private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
   2:  {
   3:       if(e.Column.Header == "Column2")
   4:            e.Column.Width = new DataGridLength(1,  DataGridLengthUnitType.Star);
   5:  }
These are the two simple ways to get rid of the extra blank column which appear inside WPF DataGrid. You can download ready to run code I showed above from here.

9 comments:

  1. why not just set the Width to * in the xaml instead of using the event?

    ReplyDelete
  2. @Jeff Byboth: How can you set Width of last column to * in XAML when columns are auto generated i.e. AutogenerateColumn = true?

    ReplyDelete
  3. ahh, gotcha in my scenario i was not auto generating. This still helped me get to my solution.

    ReplyDelete
  4. one problem. when autogenerating i am not sure which column comes first and which last...so i don't know the column header of last column..

    ReplyDelete
  5. @Mahesh: I think auto generation creates the column in the same order as they exist in the data source. I am not sure just my guess. You can do a hit and trial to find out which column comes at the end and easily manipulate your code according to it

    ReplyDelete
  6. Hi Haris,
    Your solution works great , however when I apply a grouping on the grid, once again on expanding the blank column reappears.
    Here is the code :
    ListCollectionView collection = new ListCollectionView(classList);
    collection.GroupDescriptions.Add(new PropertyGroupDescription("Name"));

    and here is the method :
    private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
    if (String.Compare(e.Column.Header + "", "Name") == 0)
    {
    e.Column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);

    }
    }

    PS : I have defined a simple class with two attributes, Name and Age

    Could you kindly help me out ?

    ReplyDelete
  7. Best implementation of wpf extended datagrid can be found here WPF Extended DataGrid

    Project Description


    This is extended version of WPF toolkit DataGrid control.

    This grid has features like

    1:Column Choosers.
    2:AutoFilter Control.
    3:Export To Excel Feature.
    4:Copy Paste To Excel and Copy Paste From Excel 5:To DataGrid.
    6:Three State Sorting.
    7:Displaying Sort Order If Multiple Sort is done

    ReplyDelete
  8. Good Article. Worked very well for me

    ReplyDelete