当内容更改时,带有 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,这应该是直截了当的。
尽管搜索了类似的情况,但我找不到与根据内容自动调整弹出内容大小相媲美的东西。
最终我错过了一些明显的东西,但是在创建之后,当内容发生变化时,我的弹出窗口顽固地拒绝重新计算其大小和内容布局。
更准确地说:我的弹出窗口托管一个内容动态变化的 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,这应该是直截了当的。