如何更新 StackPanel 的布局?

4
问题在于,如果您点击按钮并展开电话号码,则堆栈面板和边框会展开,这很好,但如果您将其折叠,则堆栈面板和边框不会折叠。
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Background="White"
        >
    <StackPanel>
        <Border BorderBrush="Black" BorderThickness="1">
            <ListBox x:Name="myListBox">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Background="LightBlue" >
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="John Smith"/>
                                <Button Click="Button_Click" Width="25" Height="25"/>
                            </StackPanel>
                            <StackPanel x:Name="PhoneNumber" Visibility="Collapsed">
                                <TextBlock Text="12345"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Border>
    </StackPanel>
</Window>

以下是代码后台:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            myListBox.ItemsSource = new List<int>() { 1, 2 }; //add 2 elements; 
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;

            StackPanel sp1 = VisualTreeHelper.GetParent(btn) as StackPanel;
            StackPanel sp2 = VisualTreeHelper.GetParent(sp1) as StackPanel;

            StackPanel phone = sp2.FindName("PhoneNumber") as StackPanel;

            if (phone.Visibility == System.Windows.Visibility.Collapsed)
                phone.Visibility = System.Windows.Visibility.Visible; 
            else
                phone.Visibility = System.Windows.Visibility.Collapsed;

            myListBox.UpdateLayout(); //these don't collapse my space
            this.UpdateLayout(); //these don't collapse my space
        }
    }
}

1
@Meleak,它在那里,但是代码标记出了问题。 - patrick
@CharithJ,this.InvalidateVisual(); && myListBox.InvalidateVisual(); 都没有起作用,自动完成也没有找到 Invalidate()。 - patrick
2个回答

3

我没有深入研究过,但是看起来你需要一直调用InvalidateMeasureItemsPresenter(实际上是ItemsPanelTemplate)这个层级。如果我有更好的方法,我会更新的。

private void Button_Click(object sender, RoutedEventArgs e)
{
    Button btn = sender as Button;

    StackPanel sp1 = VisualTreeHelper.GetParent(btn) as StackPanel;
    StackPanel sp2 = VisualTreeHelper.GetParent(sp1) as StackPanel;

    StackPanel phone = sp2.FindName("PhoneNumber") as StackPanel;

    if (phone.Visibility == System.Windows.Visibility.Collapsed)
        phone.Visibility = System.Windows.Visibility.Visible; 
    else
        phone.Visibility = System.Windows.Visibility.Collapsed;

    DependencyObject dpObject = btn;
    while (dpObject != null)
    {
        if (dpObject is UIElement)
        {
            (dpObject as UIElement).InvalidateMeasure();
        }
        if (dpObject is ItemsPresenter)
            break;
        dpObject = VisualTreeHelper.GetParent(dpObject);
    }
}

1
问题在于Listbox正在使用虚拟化。如果禁用它,问题就会消失,像这样:
<ListBox x:Name="myListBox" BorderBrush="Black" BorderThickness="1">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

或者,您可以保留默认的ItemsPanel并在ListBox上设置ScrollViewer.CanContentScroll="False"。但是两者都会禁用虚拟化。

我认为这个问题是相关的。


我自己没有尝试过这个,但你知道为什么VirtualizingStackPanel在这里的行为与StackPanel不同吗? - Fredrik Hedblad
@Meleak - 我相信这与WPF中为虚拟化构建的优化有关。VirtualizingStackPanel中内置了更多用于缓存测量数据的代码。 - CodeNaked
2
是的,我同意。看起来像是一个bug。通过Reflector检查了一下,发现它有一个名为MeasureDirty的内部属性,可以防止InvalidateMeasure运行,而在这种情况下该标志没有被更新。 - Fredrik Hedblad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接