【问题标题】:Force resize of GridView columns inside ListView强制调整 ListView 内的 GridView 列的大小
【发布时间】:2009-05-10 12:45:09
【问题描述】:

我有一个带有GridViewListView WPF 控件。当列的内容发生变化时,我想调整 GridView 列的大小。

我有几个不同的数据集,但是当我从一个更改到另一个时,每列的大小都适合以前的数据。我想动态更新。我该怎么做?

【问题讨论】:

  • 我也有同样的问题。更改数据源,列宽不会调整大小。我很乐意设置源并调用 AutoSizeColumns 方法或类似方法。

标签: c# .net wpf listview


【解决方案1】:

最后,关于这个的一些结果。我找到了一种方法来执行与最初以及双击列标题上的抓手时相同的自动调整大小。

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;
        }
    }
}

【讨论】:

  • 很好的解决方案。谢谢。
【解决方案2】:

基于 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 可能仍然太小而无法容纳内容。
  • @Danielku15 您是否发现正在发生这种情况?一个小样本会很好,所以我可以努力解决这个问题。
  • 我有一个绑定到 ObservableCollection 的 ListView。我的 CellTemplate 中有一个 40x40pt 的控件。附加 Behavior 会执行 OnListViewItemsCollectionChanged 方法,但 ActualWidth 仍然太小(在我的情况下为 25pt)。结果:它被裁剪了。执行处理程序时似乎布局过程没有运行。
  • 类似于@Danielku15 我有一个 ListViewBehavior 类,它实现了 ListView.ItemsChanged 事件处理程序中的 ActualWidth、Double.NaN 更改。将绑定源属性设置为新的项目集合时,会计算 Auto 列,但会在稍后的未知时间计算(因此我无法调整 Fill 列的大小,列溢出 ListView 宽度)。删除这些行并按预期计算 Auto 列并完全适合 ListView 宽度,但它们不会计算到新内容。
【解决方案3】:

如果你和我一样年纪大了并且更喜欢 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 中效果很好,终于有人解决了这个问题。谢谢奥斯卡。

【讨论】:

    【解决方案4】:

    难道没有办法绑定到列的ActualWidth 吗?类似的东西:

    <GridViewColumn x:Name="column1" Width="{Binding ElementName=column1, Path=ActualWidth}" />
    

    我已经尝试过了,它似乎只在第一次工作。没有绑定错误。

    【讨论】:

    • 我也试过:Width="{Binding Path=ActualWidth,RelativeSource={x:Static RelativeSource.Self}}"
    • 是的,您将 ActualWidth 复制到 Width 上,这就是永远的预期宽度。第一次禁用自动调整大小。 ActualWidth 然后再也不会改变,所以预期的宽度也不会改变。
    【解决方案5】:

    您可以以像素为单位测量最长的字符串,然后相应地调整列宽:

    Graphics graphics = this.CreateGraphics();
    SizeF textSize = graphics.MeasureString("How long am I?", this.Font);
    

    如果您创建一个算法,将每列的大小设置为这些长度的比率,您应该会得到一个很好的结果。

    【讨论】:

      猜你喜欢
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 2011-02-19
      • 1970-01-01
      相关资源
      最近更新 更多