从WPF中删除其他垂直空格

时间:2011-08-10 14:55:11

标签: c# wpf xaml

    <Border CornerRadius="2,2,2,2" BorderThickness="1" BorderBrush="LightSkyBlue" Margin="5,2,2,2" x:Name="PersonBorder" Visibility="Collapsed">
            <StackPanel Orientation="Vertical">

 <ListBox Name="personListBoxTest" 
          BorderThickness="0"
          ScrollViewer.HorizontalScrollBarVisibility="Hidden"
          ScrollViewer.VerticalScrollBarVisibility="Auto"
          HorizontalContentAlignment="Stretch"
          Background="LemonChiffon"
          >
    <ListBox.ItemTemplate >
        <DataTemplate>
            <StackPanel>
                <StackPanel Orientation="Horizontal" Background="Pink">
                    <StackPanel Orientation="Horizontal" Visibility="{Binding ElementName=Involvement, Path=Text, Converter={StaticResource cIsVisibleOrCollapsed}}" Margin="0,0,5,0">
                        <TextBlock Text="Involvement:"/>
                        <TextBlock Margin="5,0,0,0" Text="{Binding Path=NameInvolvementType}" Foreground="Blue" x:Name="Involvement"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock  Text="Name:"/>
                        <TextBlock Margin="3,0,0,0" Text="{Binding Path=FirstName}" Foreground="Blue" />
                        <TextBlock Margin="3,0,0,0" Text="{Binding Path=MiddleName}" Foreground="Blue" />
                        <TextBlock Margin="3,0,0,0" Text="{Binding Path=LastName}" Foreground="Blue" />
                        <TextBlock Margin="3,0,0,0" Text="{Binding Path=NameSuffix}" Foreground="Blue" />
                        <TextBlock Margin="5,0,0,0" Text="DOB:"/>
                        <TextBlock Margin="3,0,0,0" Text="{Binding Path=BirthDate, StringFormat=MM/dd/yyyy}" Foreground="Blue" />
                    </StackPanel>
                </StackPanel>
                <StackPanel  Visibility="{Binding ElementName=myEventAddress,Path=Visibility, Converter={StaticResource cVisibilityMirror}}" Orientation="Horizontal" >
                    <TextBlock Text="Address:" />
                    <EventDet:EventAddress Margin="5,0,0,0" x:Name="myEventAddress" Foreground="Blue" CityTextBlockOrientation="Horizontal" />
                </StackPanel>

                <StackPanel Visibility="{Binding ElementName=Phone1, Path=Text, Converter={StaticResource cIsVisibleOrCollapsed}}" Orientation="Horizontal">
                    <TextBlock Text="Home:" />
                    <TextBlock Margin="5,0,0,0" Text="{Binding Path=Phone1}" Foreground="Blue" x:Name="Phone1"/>
                </StackPanel>
                <StackPanel Visibility="{Binding ElementName=Phone2, Path=Text, Converter={StaticResource cIsVisibleOrCollapsed}}" Orientation="Horizontal">
                    <TextBlock Text="Mobile:" />
                    <TextBlock Margin="5,0,0,0" Text="{Binding Path=Phone2}" Foreground="Blue" x:Name="Phone2"/>
                </StackPanel>
                <StackPanel Visibility="{Binding ElementName=Phone3, Path=Text, Converter={StaticResource cIsVisibleOrCollapsed}}" Orientation="Horizontal">
                    <TextBlock Text="Work:" />
                    <TextBlock Margin="5,0,0,0" Text="{Binding Path=Phone3}" Foreground="Blue" x:Name="Phone3"/>
                </StackPanel>


                <StackPanel x:Name="PersonAlertSP" Visibility="Collapsed" Background="WhiteSmoke">
                    <TextBlock Text="Alerts:" />
                    <ListBox ItemsSource="{Binding Path=PersonAlertList}" x:Name="PersonAlertListBox"  BorderThickness="1" >
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Path=AlertType}" Margin="0,0,5,0" Foreground="Blue" Width="150"/>
                                    <TextBlock Text="{Binding Path=Description}" Margin="0,0,5,0" Foreground="Blue"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>


            </StackPanel>

        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

</StackPanel>
</Border>
代码背后的代码:

//this is a little unweidly, but its test code until this works
MobileWPF.singleton.EventDetailsTabControl.myEventDetailControl.personListBoxTest.ItemsSource =
    dc.SessionEvent.SessionPersons.ToList();

这是一个包含6个项目的结果图像,所有数据都是无意义的测试数据:

screenshot

编辑2:

稍微玩了一下后,我想这就是发生的事情......首先,ListBox贪婪并占用最大量的垂直空间,然后完成一些IValueConverter计算,并且一些元素被折叠。但是,完成此操作后,ListBox高度不会更新。

编辑3:

我尝试将PersonListBoxTest转换为ItemsControl,而不是ListBox,只有代码和<ItemsControl.ItemTemplate >声明的差异......现在它按预期工作,没有额外的空格。

因此,ItemsControl以某种方式尊重我的一些元素通过IValueConverters折叠的事实,而ListBox则没有。我在使用ListBox中的VirtualizingStackPanel属性,在测试ItemsControl之前将IsVirtualizing设置为true和false(无更改)。

我会向任何能够解释为什么它如何发挥作用的人提出要点 感谢大家的回答,你永远不知道会有什么不同。

以下是正在使用的IValueConverter示例,它们大致相同。

[ValueConversion(typeof(object), typeof(System.Windows.Visibility))]
public class NullToVisibleOrCollapsed : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return System.Windows.Visibility.Collapsed;

        if (value is Image)
        {
            if (((Image)value).Source == null) return System.Windows.Visibility.Collapsed;
            return System.Windows.Visibility.Visible;
        }

        if (value is string)
        {
            string myString = (string)value;
            if (string.IsNullOrEmpty(myString) == true)
                return System.Windows.Visibility.Collapsed;
        }

        if (value is int)
        {
            int myInt = (int)value;
            if (myInt == 0)
                return System.Windows.Visibility.Collapsed;
        }

        return System.Windows.Visibility.Visible;
    }

6 个答案:

答案 0 :(得分:2)

发生这种情况的原因是因为ListBox会覆盖默认的ItemsPanelTemplate设置以使用VirtualizingStackPanel。这样做是因为VirtualizingStackPanel支持UI虚拟化,这意味着只评估和创建可见控件,这可以提高大型数据集的性能。

在UI虚拟化期间,控件会检查子元素的可见性,然后测量它及其后代。这种评估顺序是您看到额外空间的关键原因。您正在使用子元素的绑定值来设置父元素的可见性。

<StackPanel 
    ...
    Visibility="{Binding 
                    ElementName=Phone1,
                    Path=Text,
                    Converter={StaticResource cIsVisibleOrCollapsed}}">
    <TextBlock
        x:Name="Phone1"
        Text="{Binding Path=Phone1}" />
</StackPanel>

当框架评估StackPanel时,Visibility尚未设置,因此默认为Visible。如果您将Visibility绑定更改为使用与子属性相同的绑定路径,则可以解决此问题。

<StackPanel 
    ...
    Visibility="{Binding Phone1, 
                    Converter={StaticResource cIsVisibleOrCollapsed}}">
    <TextBlock
        x:Name="Phone1"
        Text="{Binding Path=Phone1}" />
</StackPanel>

您还可以指定FallbackValue Collapsed,它告诉引擎在无法解析绑定的情况下使用Visibility.Collapsed。但是,我会谨慎地这样做,因为这似乎会搞砸UI测量,这可能会产生其他不良影响。

最后,普通的ItemsControl模板不需要预先测量,因为它不支持UI虚拟化。换句话说,生成控件然后隐藏,并相应地调整大小。

答案 1 :(得分:1)

默认情况下,控件将展开以填充其容器将为其提供的所有空间。这就是你所看到的,并且它是预期的,因为你没有告诉它做任何其他事情(即你没有在ListBox上设置任何对齐属性)。

如果您希望ListBox仅占用显示其项目所需的高度,则将其VerticalAlignment属性设置为默认值Stretch以外的其他属性。例如:

<ListBox Name="personListBoxTest" 
         VerticalAlignment="Top"
         ...

如果您愿意,也可以使用BottomCenter - 对您的布局最有意义。

假设您使用Top,那么如果列表框只有足够的项目来填充ListBox的父级给出的空间的一半,那么整个ListBox将占用那么多空间,而父级的其余部分将是空的。但是如果有这么多ListBox项目(或者父项变得如此之小)以至于项目都不适合,ListBox将填充所有空间并显示滚动条,就像你想要它一样。

答案 2 :(得分:0)

ListBox换成Grid并将其设置为VerticalAlignment="Top"

听起来你的ListBox控件位于另一个元素中,例如GridDockPanel,默认情况下会延伸它的子节点以填充所有可用空间。

<Grid>
    <ListBox VerticalAlignment="Top" ... />
</Grid>

答案 3 :(得分:0)

如果我正确理解您的问题,您可以使用Height="Auto"作为列表框(或其他控件),如果您想根据列表框更新窗口高度,可以将窗口高度绑定到列表框使用以下代码:

Height="{Binding ActualHeight, ElementName=personListBoxTest}"

我希望它对你有用。

答案 4 :(得分:0)

...也许

<StackPanel LastChildFill="False">

答案 5 :(得分:0)

您需要使包含ListBox的容器的高度为AUTO

ListBox1位于一行高度AUTO

ListBox2的行高为*

这将允许你在列表框中具有正确的高度作为容器中值的大小,直到容纳它的容器的最大高度......有点令人困惑,但希望它有意义。< / p>

希望有所帮助!

请参阅此示例代码

<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">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <ListBox Grid.Column="0" Grid.Row="0" Background="blue">
        <ListBoxItem>I'm an item in listbox1</ListBoxItem>
        <ListBoxItem>I'm an item in listbox1</ListBoxItem>
        <ListBoxItem>I'm an item in listbox1</ListBoxItem>
        <ListBoxItem>I'm an item in listbox1</ListBoxItem>
        <ListBoxItem>I'm an item in listbox1</ListBoxItem>
        <ListBoxItem>I'm an item in listbox1</ListBoxItem>
    </ListBox>

    <ListBox Grid.Column="1" Grid.RowSpan="2" Grid.Row="0"  Background="red">
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
        <ListBoxItem>I'm an item in listbox2</ListBoxItem>
    </ListBox>
</Grid>