Datagrid Column Width Doesn't Auto-Update

DataGrid column width doesn't auto-update

The DataGrid will increase column sizes to fit as the data becomes longer, but it does not automatically decrease column sizes when the length of the data decreases. In your example, you're right aligning the 'Change' column, and using the rest of the space for the 'Name' column.

Now, when a 'Change' property grows large enough that it should increase the column's width, the 'Name' column is refusing to shrink to accommodate, so you have to force a refresh yourself.

The following steps should do this for you (I've included a sample app to demo):

1) In your DataGridTextColumn Bindings (all except your * sized column) set NotifyTargetUpdated=True.

2) On your DataGrid, add a handler to the TargetUpdated event.

3) In your TargetUpdated event handler:

-- a) Set the DataGrid's * sized column's width to 0.

-- b) Call the UpdateLayout() method on the DataGrid.

-- c) Set the DataGrid's * sized column's width back to new DataGridLength(1, DataGridLengthUnitType.Star)

Example XAML:

<Window x:Class="DataGridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource x:Key="MyObjectCollection" />
</Window.Resources>
<DockPanel>
<Button DockPanel.Dock="Bottom" Content="Click to Make Item 1s Text Longer" Click="Button_Click" />
<Grid>
<DataGrid x:Name="dg" ItemsSource="{Binding Source={StaticResource MyObjectCollection}}" AutoGenerateColumns="False" TargetUpdated="dg_TargetUpdated">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding First}" Width="1*"/>
<DataGridTextColumn Binding="{Binding Last, NotifyOnTargetUpdated=True}" Width="Auto" />
</DataGrid.Columns>
</DataGrid>
</Grid>

</DockPanel>
</Window>

Example Code Behind:

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.ComponentModel;

namespace DataGridTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<MyObject> myObjectList = new ObservableCollection<MyObject>();

public MainWindow()
{
InitializeComponent();
(this.FindResource("MyObjectCollection") as CollectionViewSource).Source = this.myObjectList;
this.myObjectList.Add(new MyObject() { First = "Bob", Last = "Jones" });
this.myObjectList.Add(new MyObject() { First = "Jane", Last = "Doe" });
}

private void Button_Click(object sender, RoutedEventArgs e)
{
this.myObjectList[0].Last = "BillyOBrian";
}

private void dg_TargetUpdated(object sender, DataTransferEventArgs e)
{
dg.Columns[0].Width = 0;
dg.UpdateLayout();
dg.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
}
}

public class MyObject : INotifyPropertyChanged
{
private string firstName;
public string First
{
get { return this.firstName; }
set
{
if (this.firstName != value)
{
this.firstName = value;
NotifyPropertyChanged("First");
}
}
}

private string lastName;
public string Last
{
get { return this.lastName; }
set
{
if (this.lastName != value)
{
this.lastName = value;
NotifyPropertyChanged("Last");
}
}
}

public MyObject() { }

#region -- INotifyPropertyChanged Contract --

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}

#endregion INotifyPropertyChanged Contract
}
}

DataGrid-Column widths not updating on ItemsSource change

did not make any sense for me, sorry.

I understand the code, but this part:

Column widths shrink to fit correctly when increasing in column size but do
not properly shrink to fit when decreasing in column size. It will not
decrase the size of the column on an ItemsSource update after it has increased

has me puzzled

I understood this like that:

if the width of a column's content increases, the column's width increases, but if the
content's width decreases, the column's width does not.

Is that right ?

if so, this behaviour is normal: Wpf will just resize a datagrid's column width set to Auto if needed, i.e: the content cannot be displayed entirely. So when the content's width shrinks, the column does not resize as the content can still been seen entirely.

the only way I can see to force wpf to recalculate the columns' widths would be to force them all to 0 and then back to auto in the code behind, with one or two updateLayout() thrown in, but this is not very nice programming :-/

Edit:
basically, in your code behind:

foreach (DataGridColumn c in dg.Columns)
c.Width = 0;

// Update your DG's source here

foreach (DataGridColumn c in dg.Columns)
c.Width = DataGridLength.Auto;

and you probably need a dg.UpdateLayout() or two somewhere in there (after the update and the setting back to auto probably)

XAML Datagrid columns width Issue

Issue resolved after applying below solution suggested by Scott on other stackoverflow post "DataGrid column width doesn't auto-update".

1) In your DataGridTextColumn Bindings (all except your * sized column) set NotifyTargetUpdated=True.

2) On your DataGrid, add a handler to the TargetUpdated event.

3) In your TargetUpdated event handler:

-- a) Set the DataGrid's * sized column's width to 0.

-- b) Call the UpdateLayout() method on the DataGrid.

-- c) Set the DataGrid's * sized column's width back to new DataGridLength(1, DataGridLengthUnitType.Star)

GridView column width does not update when changing ItemsSource

Use this code after updating ItemsSource:

public void AutoSizeGridViewColumns(ListView listView) 
{
GridView gridView = listView.View as GridView;
if (gridView != null)
{
foreach (var column in gridView.Columns)
{
if (double.IsNaN(column.Width))
column.Width = column.ActualWidth;
column.Width = double.NaN;
}
}
}

WPF DataGrid Column Width Auto and Scrollbar

In XAML set DataGrid ColumnWidth="Auto"

In UserControl constructor add

dataGrid.Loaded += (s, e) => { // Column widths
dataGrid.Columns.AsParallel().ForEach(column => {
column.MinWidth = column.ActualWidth;
column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
});
};

Using this with a custom DataGrid and works great.

Dynamically resize datagrid columns when rows are collapsed

I solved the issue.

  1. Instead of binding the datagrid itemsource to an ObservableCollection, it is now bound to CollectionView.
    In this way rows in the datagrid can be shown/hidden by using the CollectionViewSource Filter property.
    The filtering takes place in the ViewModel.
  2. After the CollectionView has been filtered, The column widths of the datagrid is resetted.
    Because a datagrid is a control, the reset takes place in the code behind of the view (using Messenger from the MVVM Light Toolkit)

XAML

<DataGrid x:Name='dg'
ItemsSource='{Binding ChangesMadeView}'
AutoGenerateColumns='False'
IsReadOnly='True' .../>
<CheckBox IsChecked='{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}' .../>

Window code behind

public partial class TestWindow : Window
{
public static readonly Guid Token = new Guid();
public TestWindow()
{
InitializeComponent();
Messenger.Default.Register<NotificationMessage>(this, Token, ResetColumnWidth);
}

private void ResetColumnWidth(NotificationMessage notMessage)
{
if (notMessage.Notification == "ResetColumnWidth")
{
foreach (DataGridColumn c in dg.Columns)
{
c.Width = 0;
c.Width = DataGridLength.Auto;
}
}
}
}

ViewModel

private IList<CheckinPath> _changesMade = new List<CheckinPath>();
public ICollectionView ChangesMadeView { get; private set; }

public TestViewModel()
{
LoadData(); //Loads data for _changesMade
ChangesMadeView = CollectionViewSource.GetDefaultView(_changesMade);
}

private bool _isChecked;

public bool IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked != value)
{
_isChecked = value;
RaisePropertyChanged(nameof(IsChecked));
ChangesMadeView.Filter = checkinPath => { //do logic for filtering. Returns true or false ;};
Messenger.Default.Send(new NotificationMessage("ResetColumnWidth"), TestWindow.Token); //notify the code behind of the view
};
}
}


Related Topics



Leave a reply



Submit