90

我怎样才能:

  • 右对齐 ID 列中的文本
  • 根据具有最长可见数据的单元格的文本长度使每一列自动调整大小?

这是代码:

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="40"/>
            <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="100" />
            <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
        </GridView>
    </ListView.View>
</ListView>

部分答案:

感谢 Kjetil,GridViewColumn.CellTemplate 运行良好,并且 Auto Width 运行良好,但是当 ObservativeCollection“Collection”使用长于列宽的数据进行更新时,列大小不会自行更新,因此这只是解决数据的初始显示:

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" Width="Auto">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Id}" TextAlignment="Right" Width="40"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
            <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
        </GridView>
    </ListView.View>
</ListView>
4

13 回答 13

106

要使每个列自动调整大小,您可以在 GridViewColumn 上设置 Width="Auto"。

要右对齐 ID 列中的文本,您可以使用 TextBlock 创建单元格模板并设置 TextAlignment。然后设置 ListViewItem.Horizo​​ntalContentAlignment(在 ListViewItem 上使用带有 setter 的样式)以使单元格模板填充整个 GridViewCell。

也许有一个更简单的解决方案,但这应该可行。

注意:该解决方案需要Window.Resources中的 Horizo​​ntalContentAlignment =Stretch和 CellTemplate 中的TextAlignment=Right

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
    <Style TargetType="ListViewItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    </Style>
</Window.Resources>
<Grid>
    <ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="ID" Width="40">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Id}" TextAlignment="Right" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
                <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>
</Window>
于 2009-02-18T11:23:53.280 回答
39

如果内容的宽度发生变化,您将不得不使用这段代码来更新每一列:

private void ResizeGridViewColumn(GridViewColumn column)
{
    if (double.IsNaN(column.Width))
    {
        column.Width = column.ActualWidth;
    }

    column.Width = double.NaN;
}

每次该列的数据更新时,您都必须触发它。

于 2009-12-19T00:14:54.243 回答
18

如果您的列表视图也在重新调整大小,那么您可以使用行为模式来重新调整列的大小以适应整个 ListView 宽度。几乎与您使用 grid.column 定义相同

<ListView HorizontalAlignment="Stretch"
          Behaviours:GridViewColumnResize.Enabled="True">
        <ListViewItem></ListViewItem>
        <ListView.View>
            <GridView>
                <GridViewColumn  Header="Column *"
                                   Behaviours:GridViewColumnResize.Width="*" >
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox HorizontalAlignment="Stretch" Text="Example1" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>

请参阅以下链接以获取一些示例并链接到源代码 http://lazycowprojects.tumblr.com/post/7063214400/wpf-c-listview-column-width-auto

于 2011-06-30T02:36:16.613 回答
13

我创建了以下类,并在需要的地方在应用程序中使用GridView

/// <summary>
/// Represents a view mode that displays data items in columns for a System.Windows.Controls.ListView control with auto sized columns based on the column content     
/// </summary>
public class AutoSizedGridView : GridView
{        
    protected override void PrepareItem(ListViewItem item)
    {
        foreach (GridViewColumn column in Columns)
        {
            // Setting NaN for the column width automatically determines the required
            // width enough to hold the content completely.

            // If the width is NaN, first set it to ActualWidth temporarily.
            if (double.IsNaN(column.Width))
              column.Width = column.ActualWidth;

            // Finally, set the column with to NaN. This raises the property change
            // event and re computes the width.
            column.Width = double.NaN;              
        }            
        base.PrepareItem(item);
    }
}
于 2013-04-01T14:13:57.830 回答
7

因为我有一个 ItemContainerStyle 我不得不把 Horizo​​ntalContentAlignment 放在 ItemContainerStyle

    <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=FieldDef.DispDetail, Mode=OneWay}" Value="False">
                         <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Style.Triggers>
                <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
    ....
于 2011-08-01T16:03:20.277 回答
6

我喜欢 user1333423 的解决方案,只是它总是重新调整每一列的大小;我需要允许一些列固定宽度。因此,在此版本中,宽度设置为“自动”的列将自动调整大小,而设置为固定数量的列将不会自动调整大小。

public class AutoSizedGridView : GridView
{
    HashSet<int> _autoWidthColumns;

    protected override void PrepareItem(ListViewItem item)
    {
        if (_autoWidthColumns == null)
        {
            _autoWidthColumns = new HashSet<int>();

            foreach (var column in Columns)
            {
                if(double.IsNaN(column.Width))
                    _autoWidthColumns.Add(column.GetHashCode());
            }                
        }

        foreach (GridViewColumn column in Columns)
        {
            if (_autoWidthColumns.Contains(column.GetHashCode()))
            {
                if (double.IsNaN(column.Width))
                    column.Width = column.ActualWidth;

                column.Width = double.NaN;                    
            }          
        }

        base.PrepareItem(item);
    }        
}
于 2015-05-15T07:32:19.167 回答
2

我知道这为时已晚,但这是我的方法:

<GridViewColumn x:Name="GridHeaderLocalSize"  Width="100">      
<GridViewColumn.Header>
    <GridViewColumnHeader HorizontalContentAlignment="Right">
        <Grid Width="Auto" HorizontalAlignment="Right">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="Local size" TextAlignment="Right" Padding="0,0,5,0"/>
        </Grid>
    </GridViewColumnHeader>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
    <DataTemplate>
        <TextBlock Width="{Binding ElementName=GridHeaderLocalSize, Path=Width, FallbackValue=100}"  HorizontalAlignment="Right" TextAlignment="Right" Padding="0,0,5,0" Text="Text" >
        </TextBlock>
    </DataTemplate>
</GridViewColumn.CellTemplate>

主要思想是将cellTemplete元素的宽度绑定到ViewGridColumn的宽度。Width=100 是在第一次调整大小之前使用的默认宽度。后面没有任何代码。一切都在 xaml 中。

于 2015-05-25T07:39:26.257 回答
1

我在接受答案时遇到了麻烦(因为我错过了 Horizo​​ntalAlignment=Stretch 部分并调整了原始答案)。

这是另一种技术。它使用带有 SharedSizeGroup 的 Grid。

注意: ListView 上的Grid.IsSharedScope=true

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}" Grid.IsSharedSizeScope="True">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="ID" Width="40">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                             <Grid>
                                  <Grid.ColumnDefinitions>
                                       <ColumnDefinition Width="Auto" SharedSizeGroup="IdColumn"/>
                                  </Grid.ColumnDefinitions>
                                  <TextBlock HorizontalAlignment="Right" Text={Binding Path=Id}"/>
                             </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="Auto" />
                <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}" Width="Auto"/>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>
</Window>
于 2010-12-24T17:13:55.130 回答
1

我创建了一个用于更新列表的 GridView 列标题的函数,并在调整窗口大小或列表视图更新其布局时调用它。

public void correctColumnWidths()
{
    double remainingSpace = myList.ActualWidth;

    if (remainingSpace > 0)
    {
         for (int i = 0; i < (myList.View as GridView).Columns.Count; i++)
              if (i != 2)
                   remainingSpace -= (myList.View as GridView).Columns[i].ActualWidth;

          //Leave 15 px free for scrollbar
          remainingSpace -= 15;

          (myList.View as GridView).Columns[2].Width = remainingSpace;
    }
}
于 2014-07-31T13:01:40.677 回答
1

@RandomEngy 上面给出的解决方案有效,但似乎存在一个问题,即仅根据可见数据(因此,前 X 行)调整大小,而不一定是每列的最长(最宽行)值。

要解决上述问题,可以完成以下操作。

附加即使您的列表视图更改的集合,如下所示,

((INotifyCollectionChanged) MyListView.ItemsSource).CollectionChanged += CollectionChanged_Handler;

还声明一个私有 maxWidth 属性来存储您的视图遇到的最长内容。

private double maxWidth = 200;//Whatever your default width is.

现在处理程序如下,

private void CollectionChanged_Handler(object sender, NotifyCollectionChangedEventArgs args)
{
   var gridView = (GridView)MyListView.View;
   if(gridView != null)
   {
      foreach( var column in gridView.Columns)
      {
         if(column.ActualWidth > maxWidth)
         {
            if (double.IsNaN(column.Width))
            {
                   maxWidth = column.ActualWidth;
                   column.Width = maxWidth ;
            }
            column.Width = double.NaN;
         }       
       }   
}

也有可能一旦您启动对话框,寡妇已经填充了多行,而顶行不是最长的。仅当集合更改时才会触发上面的代码,但由于数据已经加载并且加载对话框时可见的行不是最宽的行,因此上面的代码将无法调整列的大小。为了解决此问题,请在 ListView_OnPreviewMouseLeftButton 事件上调用上述处理程序。如下所示,

private void MyListView_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
CollectionChanged_Handler(sender, null);
}

一旦有人滚动到视图的最宽行内容,上面的代码将刷新您的列宽。

于 2021-06-03T18:04:34.010 回答
0

这是你的代码

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}" Width="40"/>
            <GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}" Width="100" />
            <GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/>
        </GridView>
    </ListView.View>
</ListView>

试试这个

<ListView Name="lstCustomers" ItemsSource="{Binding Path=Collection}">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Id}" Width="Auto">
               <GridViewColumnHeader Content="ID" Width="Auto" />
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding FirstName}" Width="Auto">
              <GridViewColumnHeader Content="First Name" Width="Auto" />
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding LastName}" Width="Auto">
              <GridViewColumnHeader Content="Last Name" Width="Auto" />
            </GridViewColumn
        </GridView>
    </ListView.View>
</ListView>
于 2019-02-19T17:02:49.550 回答
0

好吧,我刚遇到这个问题,我用 IValueConverter 解决了它。

public class GridViewColumHeaderWidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (double)value / 8;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

注意: 8 是 GridViewColumns 的数量

现在在 Xaml 中:

<ListView x:Name="TheListView" ItemsSource="{Binding Customers}">
    <ListView.View>
        <GridView>
            <!--  Id  -->
            <GridViewColumn Width="{Binding ElementName=TheListView, Path=ActualWidth, Converter={StaticResource GridViewColumHeaderWidthConverter}}">
                <GridViewColumnHeader Content="Id" />
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding CustomerId}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <!--  Code  -->
            <GridViewColumn Width="{Binding ElementName=TheListView, Path=ActualWidth, Converter={StaticResource GridViewColumHeaderWidthConverter}}">
                <GridViewColumnHeader Content="Code" />
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding CustomerCode}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

不要忘记包含转换器文件。在这种情况下,我在 App.xaml 中定义了转换器

<Application.Resources>
    <converters:GridViewColumHeaderWidthConverter x:Key="GridViewColumHeaderWidthConverter" />
</Application.Resources>
于 2021-05-05T13:52:22.200 回答
0

可以通过禁用虚拟化并Width="Auto"GridViewColumn.

<ListView ItemsSource="{Binding ...}" VirtualizingStackPanel.IsVirtualizing="False">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Name}"
                            Header="Name"/>
        </GridView>
    </ListView.View>
</ListView>

默认情况下启用虚拟化,这意味着仅呈现可见行。这对性能有好处。缺点是仅使用当前可见的行来计算列宽(Width="Auto")。禁用虚拟化意味着即使某行目前不可见,也会呈现所有行。结果是自动宽度计算考虑了所有行的值。

于 2022-02-06T23:07:46.997 回答