如何在WPF中自动调整GridViewColumn数据的大小并使其右对齐?


89

我怎么能够:

  • 右对齐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可以很好地工作,自动宽度也可以正常工作,但是当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>

1
您是否找到解决自动尺寸问题的解决方案?我正在经历同样的事情。
奥斯卡(Oskar)

2
@Oskar-列表的虚拟化会阻止自动解决方案。该列表仅知道当前可见的项目,并相应地设置大小。如果列表下方还有更多项目,则它不知道它们,因此无法解释它们。如果您正在使用数据绑定,那么《 ProgrammingWPF-Sells-Griffith》一书建议使用手动列宽。:(
Gishu 2010年

@Gishu谢谢,这实际上是有意义的..
奥斯卡

如果使用MVVM并且绑定值正在更改,请参阅@Rolf Wessels答案。
杰克·伯杰

Answers:


104

要使每个列自动调整大小,您可以在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>

@Kjetil-我可以将此设置应用于特定的列吗?
Gishu 2010年

15
+1代表:<Setter Property =“ Horizo​​ntalContentAlignment” Value =“ Stretch” />
Helge Klein 2010年

很棒,但是我有15列,我有什么办法不必对所有这些重复细​​胞模板吗?
Nitin Chaudhari 2012年

7
如果您忘记从GridViewColumn中删除DisplayMemberBinding,它也不起作用。模板将不会有任何作用。
floele 2013年

@Mohamed为什么不呢?
不是。

36

如果内容的宽度发生变化,则必须使用以下代码来更新每一列:

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

    column.Width = double.NaN;
}

您必须在每次更新该列的数据时将其触发。


1
您会将此附加到什么?
Armentage

1
更新网格数据后,在GridViewColumn上手动运行它。如果您有ViewModel,则可以订阅它的PropertyChanged事件,然后运行它。
RandomEngy

+1谢谢!这对我很有帮助!与此问题无关,但是无论如何:我实现了自定义的List / GridView,您可以在其中通过GUI在运行时动态添加/删除列。但是,当我删除并重新添加一列时,它不再出现。首先,我认为根本没有添加它(由于某种原因),但是随后(使用Snoop)我发现它实际上是添加的,但是它的ActualWidth为0(它是自动调整大小的,显然当列为删除)。现在,在将列重新添加到列中之后,我将使用您的代码将列设置为正确的宽度。非常感谢!
gehho 2010年

解决我的问题的简单方法!
Gqqnbig

+1完美!希望这被标记为答案。我在定义列的XAML中添加了x:Name =“ gvcMyColumnName”,以便可以在后面的代码中访问它。像冠军一样工作。
K0D4 2013年

19

如果您的列表视图也正在调整大小,则可以使用行为模式来调整列的大小以适合整个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


这个很酷。解决问题,并为您提供所需的所有n自动功能。
Designpattern 2011年

这就是我想要的。:D
杰克·伯杰

注意:似乎有一个错误。当垂直调整ListView的大小时,直到导致垂直滚动条出现的程度,列的宽度将不断增加,直到滚动条消失。
杰克·伯杰

1
这篇文章可以提供我以前的评论中描述的行为的见解。
杰克·伯杰

太酷了,我的意思是代码和站点:)。我认为如果我有更严格的要求,它将很有用。
Gqqnbig

12

我创建了以下类,并在整个应用程序中使用它代替了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);
    }
}

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" /> 
    ....

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

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中。


这启发了我这种解决方案来填充一列的宽度:<GridViewColumn Width =“ {Binding RelativeSource = {RelativeSource AncestorType = ListView},Path = ActualWidth}”>
J. Andersen,

1

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

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

注:Grid.IsSharedScope =真上ListView控件。

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

您具有GridViewColumnas的宽度,40并将列定义宽度设置为Auto?那没有道理。
BK 2014年

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

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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.