Despite the fact that this is an old post, I add my conclusions, as they may be relevant to other people reading this post. I had a similar problem (my * columns did not share the width evenly, as expected, they just determined based on the content). The main reason here was because I had a ListView with the ItemsSource element associated with the List. A ListView in WPF contains a ScrollViewer, while a ScrollViewer does not have a fixed width. Without a fixed width, the grid cannot correctly determine which width to pass to the column *, and switches to another calibration method.
Solution Now I use an ItemsControl element that does not contain a ScrollViewer, and thus the width is known, allowing the Grid to sort the columns correctly.
For more details on how exactly the Grid handles its size, I suggest you decompile the Grid class and look at the following method:
protected override Size MeasureOverride(Size constraint)
This is my MainWindow.xaml from my test application (comment out the ListView to see the difference in behavior):
<Window x:Class="WPFSO.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wpfso="clr-namespace:WPFSO" Title="MainWindow" Height="150" Width="525"> <Window.DataContext> <wpfso:SharedSizeScopeViewModel /> </Window.DataContext> <Window.Resources> <DataTemplate DataType="{x:Type wpfso:TestViewModel}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" x:Name="SecondColumn" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" x:Name="FourthColumn" /> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding Name}" /> <TextBlock Grid.Column="1" Background="LightGray" Text="{Binding Name2}"/> <TextBlock Grid.Column="2" Text="{Binding Name3}"/> <TextBlock Grid.Column="3" Background="Orange" Text="{Binding Name4}"/> </Grid> </DataTemplate> <DataTemplate x:Key="MainDataTemplate" DataType="wpfso:SharedSizeScopeViewModel" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <CheckBox Grid.Row="0" Grid.ColumnSpan="4" HorizontalAlignment="Left" FlowDirection="RightToLeft" Margin="0,0,0,25"> <TextBlock FlowDirection="LeftToRight" Text="Show differences" Style="{StaticResource LabelStyle}" /> </CheckBox> <TextBlock Grid.Row="1" Grid.Column="0" Text="PropertyName" Style="{StaticResource LabelStyle}" /> <TextBlock Grid.Row="1" Grid.Column="1" Text="Previous value" Style="{StaticResource LabelStyle}" /> <TextBlock Grid.Row="1" Grid.Column="3" Text="Current value" Style="{StaticResource LabelStyle}" /> <ListView Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" ItemsSource="{Binding Entries}" HorizontalAlignment="Stretch" Margin="0" HorizontalContentAlignment="Stretch"/> </Grid> </DataTemplate> </Window.Resources> <Grid Name="RootGrid"> <ItemsControl ItemsSource="{Binding Entries}" /> </Grid> </Window> The ViewModels used during this test: using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; namespace WPFSO { public class SharedSizeScopeViewModel : INotifyPropertyChanged { public SharedSizeScopeViewModel() { var testEntries = new ObservableCollection<TestViewModel>(); testEntries.Add(new TestViewModel { Name = "Test", Name2 = "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test", Name3 = "Short test", Name4 = "Nothing" }); Entries = testEntries; } private ObservableCollection<TestViewModel> _entries; public ObservableCollection<TestViewModel> Entries { get { return _entries; } set { _entries = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
First view model
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; namespace WPFSO { public class SharedSizeScopeViewModel : INotifyPropertyChanged { public SharedSizeScopeViewModel() { var testEntries = new ObservableCollection<TestViewModel>(); testEntries.Add(new TestViewModel { Name = "Test", Name2 = "Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test", Name3 = "Short test", Name4 = "Nothing" }); Entries = testEntries; } private ObservableCollection<TestViewModel> _entries; public ObservableCollection<TestViewModel> Entries { get { return _entries; } set { _entries = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
Second view model
using System.ComponentModel; using System.Runtime.CompilerServices; namespace WPFSO { public class TestViewModel : INotifyPropertyChanged { private string _name; private string _name2; private string _name3; private string _name4; public string Name { get { return _name; } set { _name = value; OnPropertyChanged(); } } public string Name2 { get { return _name2; } set { _name2 = value; OnPropertyChanged(); } } public string Name3 { get { return _name3; } set { _name3 = value; OnPropertyChanged(); } } public string Name4 { get { return _name4; } set { _name4 = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }