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.
- 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. - 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
Top Level Domain from Url in C#
Process Queue with Multithreading or Tasks
How to Simply 'Read' a File That Is in Use
Client Id for Property (ASP.NET MVC)
Image.Fromstream() Method Returns Invalid Argument Exception
The Type Initializer for 'Emgu.Cv.Cvinvoke' Threw an Exception
Caching the Result from a [N Async] Factory Method Iff It Doesn't Throw
Visual Studio 2005 Designer Moves Controls and Resizes Form
Dynamically Create a Generic Type for Template
Broadcastblock with Guaranteed Delivery in Tpl Dataflow
How to Query for an Event Log Details with a Given Event Id
Why Is Modulus Operator Not Working for Double in C#
Canadian Postal Code Validation
How to Generate a 3-D Surface from Isolines
Take Screenshot of Multiple Desktops of All Visible Applications and Forms