patrick
patrick

Reputation: 16999

How to UpdateLayout of StackPanel?

The problem is, if you click the button and expand the phone number, the stackpanel & border expand, which is great, but if you collapse it, the stackpanel & border do not collapse.

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

With the following code-behind:

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

Upvotes: 4

Views: 6744

Answers (2)

CodeNaked
CodeNaked

Reputation: 41403

The issue is that the Listbox is using virtualization. If you disable that then the issue goes away, like so:

<ListBox x:Name="myListBox" BorderBrush="Black" BorderThickness="1">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

Alternatively, you can leave the default ItemsPanel and set ScrollViewer.CanContentScroll="False" on the ListBox. Both disable virtualization though.

I believe this question is related.

Upvotes: 1

Fredrik Hedblad
Fredrik Hedblad

Reputation: 84684

Didn't dig to deep into this but it looks like you'll have to call InvalidateMeasure all the way up the chain to the ItemsPresenter (actually, the ItemsPanelTemplate). I'll update if I can up with something better

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

Upvotes: 3

Related Questions