当内容更改时,带有 ListView 和 GridView 的 WPF Popup 不调整大小

WPF Popup with ListView and GridView not resizing when content has changed

尽管搜索了类似的情况,但我找不到与根据内容自动调整弹出内容大小相媲美的东西。

最终我错过了一些明显的东西,但是在创建之后,当内容发生变化时,我的弹出窗口顽固地拒绝重新计算其大小和内容布局。

更准确地说:我的弹出窗口托管一个内容动态变化的 ListView。

现在,当首次创建弹出窗口时,它的宽度将适应 ListView 的所需大小,以便所有列表视图元素(在 GridView 内)。

现在ListView中的元素更新时,最长元素的宽度发生变化。预期的行为是列表视图和弹出窗口将更改大小(宽度)以匹配新的列表元素。

不幸的是,弹出窗口及其内容拒绝更改,因此内容被裁剪了。

我已经尝试使弹出窗口的排列和尺寸无效,并调用了 ListView 的 Popup and/or 的 UpdateLayout,到目前为止没有成功...GridView 元素我不能 access/manage 它.. .

有没有办法强制重新计算 Popup 或 ListView 的总体布局?

<Popup x:Name           = "hintPopup"
       Placement        = "Bottom"
       PlacementTarget  = "{Binding ElementName=textBox}"
       MinWidth         = "{Binding ElementName=textBox, Path=ActualWidth}"
       IsOpen           = "{Binding ShowPopup, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
       Margin           = "0,20,0,0">

    <!-- Reference a converter to convert Bool Values to Visibility -->
    <Popup.Resources>
        <conv:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
    </Popup.Resources>

    <!-- Move popup with anchor -->
    <b:Interaction.Behaviors>
        <behav:PopupAutoRepositionBehavior />
    </b:Interaction.Behaviors>

    <Border BorderBrush     = "Gray" 
            BorderThickness = "1"
            Background      = "LightGray"
            Padding         = "1">

        <StackPanel Orientation="Vertical">

            <!-- Title Starts With -->
            <TextBlock Text         = "{x:Static res:Strings.vokDataGridEdit_Popup_TitleStartsWith}"
                       Visibility   = "{Binding ShowHintsStartsWith, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=collapsed}"
                       FontWeight   = "Bold"
                       Foreground   = "Black"
                       Margin       = "0, 5, 0, 2"/>

            <!-- Hints -->
            <ListView ItemsSource   = "{Binding ItemHintsStartsWith, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
                      Visibility    = "{Binding ShowHintsStartsWith, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=collapsed}"
                      Margin        = "5, 1, 1, 1">

                <!-- Prevent selection -->
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="Focusable" Value="false"/>
                    </Style>
                </ListView.ItemContainerStyle>

                <!-- Hide Headers -->
                <ListView.Resources>
                    <Style TargetType="GridViewColumnHeader">
                        <Setter Property="Visibility" Value="Collapsed" />
                    </Style>
                </ListView.Resources>

                <ListView.View>
                    <GridView AllowsColumnReorder="False">

                        <GridViewColumn DisplayMemberBinding    = "{Binding Path=valueCurrent}" 
                                        Header                  = "Current"
                                        Width                   = "auto" />

                        <GridViewColumn DisplayMemberBinding    = "{Binding Path=valueTranslated}" 
                                        Header                  = "Translated"
                                        Width                   = "auto" />

                    </GridView>
                </ListView.View>

            </ListView>

            <!-- Title Similar -->
            <TextBlock Text         = "{x:Static res:Strings.vokDataGridEdit_Popup_Similar}"
                       Visibility   = "{Binding ShowHintsSimilar, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=collapsed}"
                       FontWeight   = "Bold"
                       Foreground   = "Black"
                       Margin       = "0, 5, 0, 2"/>

            <!-- Hints -->
            <ListView ItemsSource   = "{Binding ItemHintsSimilar, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
                      Visibility    = "{Binding ShowHintsSimilar, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=collapsed}"
                      Margin        = "5, 1, 1, 1">

                <!-- Prevent selection -->
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="Focusable" Value="false"/>
                    </Style>
                </ListView.ItemContainerStyle>

                <!-- Hide Headers -->
                <ListView.Resources>
                    <Style TargetType="GridViewColumnHeader">
                        <Setter Property="Visibility" Value="Collapsed" />
                    </Style>
                </ListView.Resources>

                <ListView.View>
                    <GridView AllowsColumnReorder="False">

                        <GridViewColumn DisplayMemberBinding    = "{Binding Path=valueCurrent}" 
                                        Header                  = "Current"
                                        Width                   = "auto" />

                        <GridViewColumn DisplayMemberBinding    = "{Binding Path=valueTranslated}" 
                                        Header                  = "Translated"
                                        Width                   = "auto" />

                    </GridView>
                </ListView.View>

            </ListView>

        </StackPanel>

    </Border>

</Popup>

好的,最后我在项目中处理另一个 GridView 启用的 ListView 时找到了解决方案。实际上 GridView 导致了这个问题,因为当绑定集合中的元素发生变化时它不会自动调整列的大小。

因此,我实现了一个 Behavior,只要 ListView 绑定到的集合发生变化,它就会触发调整大小事件:

/// <summary>
/// Adds auto resizing to a ListView GridViews columns
/// </summary>
public class GridViewColumnAutoResizeBehavior : BehaviorBase<ListView>
{
    /// <summary>
    /// Setup the behavior
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();

        // Associate handler
        if (this.AssociatedObject?.Items is INotifyCollectionChanged notifyingCollection)
        {
            notifyingCollection.CollectionChanged += this.OnCollectionChanged;
        }
    }

    /// <summary>
    /// Handler to force resizing the columns
    /// </summary>
    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
    {
        if (this.AssociatedObject.View is GridView gridView)
        {
            // Resize automatic columns
            foreach (GridViewColumn gridViewColumn in gridView.Columns.Where(column => double.IsNaN(column.Width)))
            {
                gridViewColumn.Width = gridViewColumn.ActualWidth;
                gridViewColumn.Width = double.NaN;
            }
        }
    }

    /// <summary>
    /// Clean-up the behavior
    /// </summary>
    protected override void OnCleanup()
    {
        // Clean-up handler
        if (this.AssociatedObject?.Items is INotifyCollectionChanged notifyingCollection)
        {
            notifyingCollection.CollectionChanged -= this.OnCollectionChanged;
        }

        base.OnCleanup();
    }
}

请务必使用实现 INotifyCollectionChanged 的集合来附加行为。

该代码使用了自动分离行为,因此您需要适应您正在使用的基础 class,这应该是直截了当的。