Home » WPFRSS

WPF Data Grid - How to hide the next column/row that is visible?

I'm using a WPF data grid to bind to an object (i.e. not a database). I have the horizontal alignment on Stretch. I currently have it within a Border, which is within a Grid.

However when I run the application the DataGrid has a blank column and grid showing. That is say I have 5 columns & 5 rows, then there is a blank 6th column and row showing. See image:

alt text

Question - How can I get rid of these blank rows? Note that the contents of the DataGrid are populated programmatically (i.e. are not static).

thanks

 

17 Answers Found

 

Answer 1

Did you try to set the CanUserAddRows property of the datagrid  to False?

Bruno

 

Answer 2

that fixed the extra row  below (thanks) however I still have the extra column  on the right

the issue with the extra column on the right seems to be to do with automatically setting column widths.  The DataGrid is actually setup (see XAML below) such that there is a GridSplitter just on it's right.  When I move the GridSplitter I note  that the DataGrid columns  don't resize automatically.  So overall the issue is both (a) on startup there is a partial extra column visible, and (b) after moving the GridSplitter they don't resize either.

Any ideas on how to get this working?

<Grid><Grid.ColumnDefinitions><ColumnDefinitionWidth="Auto"/><ColumnDefinitionWidth="Auto"/><ColumnDefinitionWidth="*"/></Grid.ColumnDefinitions><GridGrid.Column="0"><Grid.RowDefinitions><RowDefinitionHeight="Auto"/><RowDefinitionHeight="Auto"/><RowDefinitionHeight="*"/></Grid.RowDefinitions><LabelContent="Summary"Grid.Row="0"HorizontalAlignment="Center"/><GridGrid.Row="1"><Grid.ColumnDefinitions><ColumnDefinitionWidth="*"/><ColumnDefinitionWidth="*"/><ColumnDefinitionWidth="*"/><ColumnDefinitionWidth="*"/></Grid.ColumnDefinitions><RadioButtonIsChecked="{Binding Path=Period, Converter={StaticResource enumBooleanConverter}, ConverterParameter=AllTime}"Grid.Column="0">All Time</RadioButton><RadioButtonIsChecked="{Binding Path=Period, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Month}"Grid.Column="1">Month</RadioButton><RadioButtonIsChecked="{Binding Path=Period, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Week}"Grid.Column="2">Week</RadioButton><RadioButtonIsChecked="{Binding Path=Period, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Day}"Grid.Column="3">Day</RadioButton></Grid><BorderGrid.Row="2"><DataGridName="SummaryDataGrid"HorizontalGridLinesBrush="#FF726868"VerticalGridLinesBrush="#FF726868"AlternatingRowBackground="#FFD0F896"CanUserReorderColumns="False"CanUserResizeRows="False"CanUserAddRows="False"CanUserSortColumns="True"CanUserResizeColumns="False"ColumnWidth="Auto"/></Border></Grid><GridSplitterHorizontalAlignment="Right"VerticalAlignment="Stretch"Grid.Column="1"ResizeBehavior="PreviousAndNext"Width="5"Background="#FFBCBCBC"/><GridGrid.Column="2"Name="RTChartGrid">
					<-- CUT -->

				</Grid></Grid>

 

Answer 3

You are setting the column  widths as auto. If you set at least one column with as "*" (star), it will fill the empty space

Bruno

 

Answer 4

oh - the problem is that I'm binding programmatically  to an ObservableCollection, so the columns  get created automatically in that sense.  I've tried in the VS designer to make the ColumnWidth ="*" however what then happens is that the first column then takes the entire width of the entire application  window, so you don't even see the RTChartGrid section.

Any ideas given this?  Is there a way to programmatically set the column  widths manually, even though the values will come dynamically from the ObservableCollection?  e.g. so if I know there will be 3 columns in the collection how to set the 0th, 1st and 2nd?

 

Code re how I'm binding:

 

private ObservableCollection<SummaryItem> _summaryData = new ObservableCollection<SummaryItem>();

SummaryDataGrid.ItemsSource = _summaryData;

 

 

 

 

Answer 5

Hello

we can register one event handler for auto generated column. When it is generated, we update its property to expected value.

<DataGrid AutoGeneratingColumn="DG1_AutoGeneratingColumn"  />

private void DG1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    //Set properties on the columns  during auto-generation
    switch (e.Column.Header.ToString())
    {
 .....
    }
}

 

Hope this helps.

 

Answer 6

oh - the problem is that I'm binding programmatically  to an ObservableCollection, so the columns  get created automatically in that sense.  I've tried in the VS designer to make the ColumnWidth ="*" however what then happens is that the first column then takes the entire width of the entire application  window, so you don't even see the RTChartGrid section.

Any ideas given this?  Is there a way to programmatically set the column  widths manually, even though the values will come dynamically from the ObservableCollection?  e.g. so if I know there will be 3 columns in the collection how to set the 0th, 1st and 2nd?

 

Code re how I'm binding:

 

private ObservableCollection<SummaryItem> _summaryData = new ObservableCollection<SummaryItem>();

SummaryDataGrid.ItemsSource = _summaryData;

 

 

 

 

Answer 7

Hello

we can register one event handler for auto generated column. When it is generated, we update its property to expected value.

<DataGrid AutoGeneratingColumn="DG1_AutoGeneratingColumn"  />

private void DG1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    //Set properties on the columns  during auto-generation
    switch (e.Column.Header.ToString())
    {
 .....
    }
}

 

Hope this helps.

 

Answer 8

One thing that you can do is set a column  width to star on code. In the constructor, add:

Loaded += (s,e) => datagrid.Columns[0].Width =

 

newDataGridLength(1,DataGridLengthUnitType.Star);

Bruno

 

Answer 9

@Bruno - thanks however in the constructor this didn't seem to do anything.  I did try putting the width setting after the first records are programmatically  added to the ObservableCollection however this caused the column  to stretch  across the whole width.  

So got this:

the image

i.e. compared to before attempt of:

the image

 

 


 

Answer 10

@Yiling Lai - thanks but I didn't quite follow  :(

Re "register one event handler for auto generated column" - how do you do this exactly?  By your code are you suggesting WPF will automatically register events if the names match <elementname>_<column_name>?  Just trying to guess how this might work...  Perhaps best if you assume I'm aware of WPF events but haven't used them much yet.  thanks


 

Answer 11

Please, verify if you have set an explicit width for the datagrid. If you have, just remove the Width="xxx" from the datagrid

Bruno

 

Answer 12

no have haven't actually Bruno - nothing set programmatically, and the XAML is:

<DataGrid Name="SummaryDataGrid"  HorizontalGridLinesBrush="#FF726868" VerticalGridLinesBrush="#FF726868" AlternatingRowBackground="#FFD0F896"  CanUserAddRows="False" CanUserSortColumns="True" />

 

 

 

Answer 13

this simple example seems to exhibit the same issue I'm having:

the image

<Windowx:Class="MyInternetUsage.test_datagrid"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="test_datagrid"Height="300"Width="300"><Grid><DataGridName="TestDataGrid"CanUserAddRows="False"/></Grid></Window>

 

publicpartialclass test_datagrid : Window
  {

    private ObservableCollection<TestItem> _testData = new ObservableCollection<TestItem>();

    public test_datagrid()
    {
      InitializeComponent();

      TestDataGrid.ItemsSource = _testData;
      //// Test ONlyvar item = new TestItem { ProcessName = "Firefox", Total = 1234, Average = 123 };
      _testData.Add(item);
      item = new TestItem { ProcessName = "IE", Total = 2345, Average = 233 };
      _testData.Add(item);
      item = new TestItem { ProcessName = "Groupwise", Total = 3453, Average = 23 };
      _testData.Add(item);

    }
  }

  publicclass TestItem : INotifyPropertyChanged
  {
    publicevent PropertyChangedEventHandler PropertyChanged;

    privatestring _processName;
    publicstring ProcessName
    {
      get { return _processName; }
      set
      {
        _processName = value;
        NotifyPropertyChanged("ProcessName");
      }
    }

    privatelong _total;
    publiclong Total
    {
      get { return _total; }
      set
      {
        _total = value;
        NotifyPropertyChanged("Total");
      }
    }

    privatelong _average;
    publiclong Average
    {
      get { return _average; }
      set
      {
        _average = value;
        NotifyPropertyChanged("Average");
      }
    }

    privatevoid NotifyPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs((propertyName)));
      }
    }

  }

 

 

 

Answer 14

Change the sample code to:
public test_datagrid()
  {
   InitializeComponent();

   TestDataGrid.ItemsSource = _testData;
   //// Test ONlyvar item = new TestItem { ProcessName = "Firefox", Total = 1234, Average = 123 };
   _testData.Add(item);
   item = new TestItem { ProcessName = "IE", Total = 2345, Average = 233 };
   _testData.Add(item);
   item = new TestItem { ProcessName = "Groupwise", Total = 3453, Average = 23 };
   _testData.Add(item);
   Loaded += (s, e) => TestDataGrid.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
  }

 

Bruno

 

Answer 15

oh yes - I see this works in the cutdown sample where I'm populating the test data  during initialization - thanks

if I do this in my app I get a ArgumentOutOfRangeException as no doubt the data isn't actually populated  in the collection at that point (but rather later).  So I guess the Load event isn't the right point for what I want.   So, for better or worse, what I'm currently doing is loading the page with the databinding to the observableCollection in place, then later once data is available it starts adding items to the observableCollection.  So the datagrid  wouldn't know how many columns there are until the first item in the observableCollection is in place.

Would this imply I'd need to use the concept "register one event handler for auto generated column", that YiLing mentioned, but for which I'm not exactly sure how to setup?  

 

 


 

 

Answer 16

Yes, that could be ok. You can change the constructor to:
public MainWindow()
{
  InitializeComponent();
  TestDataGrid.ItemsSource = _testData;
  //// Test ONlyvar item = new TestItem { ProcessName = "Firefox", Total = 1234, Average = 123 };
  _testData.Add(item);
  item = new TestItem { ProcessName = "IE", Total = 2345, Average = 233 };
  _testData.Add(item);
  item = new TestItem { ProcessName = "Groupwise", Total = 3453, Average = 23 };
  _testData.Add(item);

  TestDataGrid.AutoGeneratingColumn += (s, e) =>
                     {
                       if (e.Column.Header.ToString() == "ProcessName")
                         e.Column.Width = new DataGridLength(1,
                                           DataGridLengthUnitType.
                                             Star);
                     };
  
}

 

Bruno
 

Answer 17

thanks Bruno - that seems to work nicely

 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter