You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中使用UserControl时GridViewColumn自动调整列宽失效问题

WPF ListView GridViewColumn 自动列宽失效问题(自定义UserControl场景)

我有一个使用GridViewColumns的WPF ListView,核心代码如下:

<ListView Name="LvArticles"  Grid.Column="0" Grid.Row="3"  MinWidth="800" ItemsSource="{Binding SearchResults}" SelectedItem="{Binding SearchResultsSelectedItem}" IsSynchronizedWithCurrentItem="True" Margin="3">
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Distance" DisplayMemberBinding="{Binding Distance}"></GridViewColumn>
                <GridViewColumn Header="Ident" DisplayMemberBinding="{Binding Article.Ident}"></GridViewColumn>
                <GridViewColumn Header="Beschreibung">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type models:ArticleSearchResult}">
                            <helpers:FormattedTextControl Text="{Binding Article.DescriptionLong2}" HighlightText="{Binding OriginalMpn}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"  />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <!--<GridViewColumn Header="Beschreibung" DisplayMemberBinding="{Binding Article.DescriptionLong2}"></GridViewColumn>-->
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

为了调试,我保留了两个用于显示Article.DescriptionLong2的GridViewColumn(其中一个已注释)。每当结果集变化时,我用以下代码自动调整列宽:

c.Width = 0; // 重置宽度
c.Width = double.NaN; // 自动适配内容宽度

使用DisplayMemberBinding时这段代码工作正常,但换成自定义UserControl后,列宽只适配表头宽度,完全忽略内容宽度,仿佛内容宽度为0。自定义UserControl的代码如下:

<UserControl x:Class="GrafBomBuilder.Helpers.FormattedTextControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" >
    <Grid Name="Stack" HorizontalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="{Binding Part1}" />
        <TextBlock Grid.Column="1" Text="{Binding Part2}" Foreground="Red" />
        <TextBlock Grid.Column="2" Text="{Binding Part3}" />
    </Grid>    
</UserControl>

问题分析与解决

你的猜测是正确的:GridView自动计算列宽时,无法正确识别自定义UserControl的实际内容宽度,需要让控件正确报告自身的测量尺寸,同时调整布局逻辑。

1. 修正UserControl的布局逻辑

自定义UserControl的布局设置导致它无法正确反映内容宽度:

  • 原布局中Grid的中间列用了Width="*",会让Grid拉伸至父容器宽度,而非根据子TextBlock的内容自适应
  • UserControl和内部Grid的HorizontalAlignment="Stretch"会强制控件占满列宽,导致GridView无法获取真实的内容宽度

修改后的UserControl代码:

<UserControl x:Class="GrafBomBuilder.Helpers.FormattedTextControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d"
             HorizontalAlignment="Left"> <!-- 让控件根据内容自适应宽度 -->
    <Grid Name="Stack" HorizontalAlignment="Left"> <!-- 避免Grid拉伸,根据子元素宽度自适应 -->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/> <!-- 改为Auto,适配TextBlock内容宽度 -->
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="{Binding Part1}" />
        <TextBlock Grid.Column="1" Text="{Binding Part2}" Foreground="Red" />
        <TextBlock Grid.Column="2" Text="{Binding Part3}" />
    </Grid>    
</UserControl>

2. 确保布局完成后再调整列宽

在设置自动列宽前,需要强制ListView完成布局更新,让所有行的自定义控件都完成测量:

c.Width = 0;
LvArticles.UpdateLayout(); // 强制更新布局,确保控件完成尺寸测量
c.Width = double.NaN;

3. 额外注意事项

  • 如果数据绑定存在延迟,可通过Dispatcher.BeginInvoke延迟执行列宽调整,确保数据已经更新到UI:
    Application.Current.Dispatcher.BeginInvoke(() =>
    {
        c.Width = 0;
        LvArticles.UpdateLayout();
        c.Width = double.NaN;
    });
    
  • 不要给UserControl或内部子元素设置固定宽度,确保所有元素都根据内容自适应,这样控件的DesiredSize才能正确反映实际内容宽度。

内容的提问来源于stack exchange,提问作者Tom L.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:12:32