<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Change}" Width="Auto"/>
当
Change
的值更新时,其列不会更新以适应新值。因此该列太小并且该值被剪裁。DataGrid 将增加列大小以适应数据变长的情况,但当数据长度减少时它不会自动减小列大小。在您的示例中,您右对齐“更改”列,并将其余空间用于“名称”列。
现在,当“更改”属性增长到足以增加列的宽度时,“名称”列拒绝缩小以适应,因此您必须自己强制刷新。
1) 在 DataGridTextColumn 绑定中(除 * 大小的列之外的所有绑定)设置 NotifyTargetUpdated=True。
2) 在 DataGrid 上,向 TargetUpdated 事件添加处理程序。
3) 在您的 TargetUpdated 事件处理程序中:
-- a) 将 DataGrid 的 * 大小列的宽度设置为 0。
-- b) 在 DataGrid 上调用 UpdateLayout() 方法。
-- c) 将 DataGrid 的 * 大小列的宽度设置回新的 DataGridLength(1, DataGridLengthUnitType.Star)
<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>
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
}
}
我的列表视图也有类似的问题,我在 stackoverflow 上的 how-to-autosize-and-right-align-gridviewcolumn-data-in-wpf 上找到了解决方案。
在我的例子中,它将这段代码添加到列表视图绑定到的可观察集合的 CollectionChanged 事件处理程序中:
void listview_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
// this is a listview control
GridView view = this.View as GridView;
foreach(GridViewColumn c in view.Columns) {
if(double.IsNaN(c.Width)) {
c.Width = c.ActualWidth;
}
c.Width = double.NaN;
}
}
它对我有用,尽管有时用户会注意到列上“闪烁”。
如果需要,WPF 只会调整数据网格的列宽设置为“自动”,即:内容无法完全显示。因此,当内容的宽度缩小时,列的大小不会调整,因为内容仍然可以完全看到。
我能看到强制 wpf 重新计算列宽度的唯一方法是将它们全部强制为 0,然后在后面的代码中返回到 auto,并抛出一两个 updateLayout() ,但这不是很好编程:-/
基本上,在你的代码后面:
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;
并且您可能需要一个或两个
dg.UpdateLayout()
(可能在更新并设置回自动之后)
<DataGridTextColumn Binding="{Binding Change}" ElementStyle="{StaticResource ChangeColumnStyle}"/>
在您的资源词典中:
<Style TargetType="{x:Type DataGridTextColumn }" x:Key="ChangeColumnStyle">
<Setter Property="Width" Value="{Binding ColumnWidth}"
</Style>
ColumnWidth 应该是对象的属性。现在,如果您从“更改”属性的设置器更新此属性(通过使用一些自定义算法,考虑字体等内容),并调用:
RaisePropertyChanged("ColumnWidth");
它应该更新您的列宽。
public int Change
{
get { return m_change; }
set
{
if (m_change != value)
{
m_change = value;
ColumnWidth = WidthAlgo(numberOfCharacters);
RaisePropertyChanged("Change");
RaisePropertyChanged("ColumnWidth");
}
}
}
ListView
,我能够利用Scott's优秀的答案来让它工作:
<ListView x:Name="myThing" ItemsSource="{Binding ACollectionOfStuff, NotifyOnTargetUpdated=True}" TargetUpdated="lv_TargetUpdated">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="MyHeader" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=PropertyOnMyClass}" FontSize="14" Margin="2,5,2,0" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
using System.Windows.Controls;
using System.Windows.Data;
namespace MyCompany.App.Views;
public partial class ThingView : UserControl
{
public ThingView()
{
InitializeComponent();
}
private void lv_TargetUpdated(object sender, DataTransferEventArgs e)
{
var grid = myThing.View as GridView;
if (grid != null)
{
foreach (var column in grid.Columns)
{
if (double.IsNaN(column.Width))
{
column.Width = column.ActualWidth;
}
column.Width = double.NaN;
}
}
}
}
也能够利用这个优秀答案中的信息:
<DataGridTextColumn Binding="{Binding Path= Id}" Header="ID" IsReadOnly="True" Width="1*" />