【发布时间】:2009-05-10 12:45:09
【问题描述】:
我有一个带有GridView 的ListView WPF 控件。当列的内容发生变化时,我想调整 GridView 列的大小。
我有几个不同的数据集,但是当我从一个更改到另一个时,每列的大小都适合以前的数据。我想动态更新。我该怎么做?
【问题讨论】:
-
我也有同样的问题。更改数据源,列宽不会调整大小。我很乐意设置源并调用 AutoSizeColumns 方法或类似方法。
我有一个带有GridView 的ListView WPF 控件。当列的内容发生变化时,我想调整 GridView 列的大小。
我有几个不同的数据集,但是当我从一个更改到另一个时,每列的大小都适合以前的数据。我想动态更新。我该怎么做?
【问题讨论】:
最后,关于这个的一些结果。我找到了一种方法来执行与最初以及双击列标题上的抓手时相同的自动调整大小。
public void AutoSizeColumns()
{
GridView gv = listView1.View as GridView;
if (gv != null)
{
foreach (var c in gv.Columns)
{
// Code below was found in GridViewColumnHeader.OnGripperDoubleClicked() event handler (using Reflector)
// i.e. it is the same code that is executed when the gripper is double clicked
if (double.IsNaN(c.Width))
{
c.Width = c.ActualWidth;
}
c.Width = double.NaN;
}
}
}
【讨论】:
基于 Oskars 的回答,这是一种混合行为,可在内容更改时自动调整列的大小。
/// <summary>
/// A <see cref="Behavior{T}"/> implementation which will automatically resize the automatic columns of a <see cref="ListView">ListViews</see> <see cref="GridView"/> to the new content.
/// </summary>
public class GridViewColumnResizeBehaviour : Behavior<ListView>
{
/// <summary>
/// Listens for when the <see cref="ItemsControl.Items"/> collection changes.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
var listView = AssociatedObject;
if (listView == null)
return;
AddHandler(listView.Items);
}
private void AddHandler(INotifyCollectionChanged sourceCollection)
{
Contract.Requires(sourceCollection != null);
sourceCollection.CollectionChanged += OnListViewItemsCollectionChanged;
}
private void RemoveHandler(INotifyCollectionChanged sourceCollection)
{
Contract.Requires(sourceCollection != null);
sourceCollection.CollectionChanged -= OnListViewItemsCollectionChanged;
}
private void OnListViewItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
var listView = AssociatedObject;
if (listView == null)
return;
var gridView = listView.View as GridView;
if (gridView == null)
return;
// If the column is automatically sized, change the column width to re-apply automatic width
foreach (var column in gridView.Columns.Where(column => Double.IsNaN(column.Width)))
{
Contract.Assume(column != null);
column.Width = column.ActualWidth;
column.Width = Double.NaN;
}
}
/// <summary>
/// Stops listening for when the <see cref="ItemsControl.Items"/> collection changes.
/// </summary>
protected override void OnDetaching()
{
var listView = AssociatedObject;
if (listView != null)
RemoveHandler(listView.Items);
base.OnDetaching();
}
}
【讨论】:
ActualWidth 可能需要一些时间。因此,ActualWidth 可能仍然太小而无法容纳内容。
如果你和我一样年纪大了并且更喜欢 VB.NET,那么这里是 Oskars 代码:
Public Sub AutoSizeColumns()
Dim gv As GridView = TryCast(Me.listview1.View, GridView)
If gv IsNot Nothing Then
For Each c As GridViewColumn In gv.Columns
If Double.IsNaN(c.Width) Then
c.Width = c.ActualWidth
End If
c.Width = Double.NaN
Next
End If
End Sub
这在 WPF 中效果很好,终于有人解决了这个问题。谢谢奥斯卡。
【讨论】:
难道没有办法绑定到列的ActualWidth 吗?类似的东西:
<GridViewColumn x:Name="column1" Width="{Binding ElementName=column1, Path=ActualWidth}" />
我已经尝试过了,它似乎只在第一次工作。没有绑定错误。
【讨论】:
您可以以像素为单位测量最长的字符串,然后相应地调整列宽:
Graphics graphics = this.CreateGraphics();
SizeF textSize = graphics.MeasureString("How long am I?", this.Font);
如果您创建一个算法,将每列的大小设置为这些长度的比率,您应该会得到一个很好的结果。
【讨论】: