防止列表框显示部分列表框项
Prevent Listbox from display partial Listboxitem
我有一个显示信息的非交互式 UI。信息保存在带有自定义 listboxitem 控件的 Listbox 控件中。
每个列表框项目的大小可以变化,window 可以根据用户需要调整大小。
我想阻止在应用程序中部分显示的列表框项目显示,这将始终是最后一行。但是,如果我调整 UI 的大小,'last row' 将会改变。
我一直在试验 this SO answer 但没有任何运气。
protected override Size ArrangeOverride(Size finalSize)
{
// Arrange in a stack
double curX = 0;
double curY = 0;
foreach (UIElement child in InternalChildren)
{
double nextY = curY + child.DesiredSize.Height;
if (nextY > finalSize.Height) // Don't display partial items
child.Arrange(new Rect());
else
child.Arrange(new Rect(curX, curY, child.DesiredSize.Width, child.DesiredSize.Height));
curY = nextY;
}
return finalSize;
}
"InternalChildren" 我假设是我的列表框,但列表框不可枚举。我不确定如何使用这个例子。
怎样才能达到预期的效果?
主控
<UserControl x:Class="Cis.CustomControls.CisDeparturesPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:customControls="clr-namespace:Cis.CustomControls"
mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate">
<ListBoxItem Padding="0" >
<customControls:CisDeparturesRow />
</ListBoxItem>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="44"/>
<RowDefinition Height="229*"/>
<RowDefinition Height="279*" />
</Grid.RowDefinitions>
<ListBox Grid.Row="2" HorizontalContentAlignment="Stretch" Name="ListBoxDepart" Background="Black" Margin="1,0,-1,0" BorderThickness="0" ItemsSource="{Binding Path=StationMovementList}" ItemTemplate="{StaticResource DataTemplate}" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden" Grid.RowSpan="2">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</UserControl>
ListBoxItem 自定义控件
<UserControl x:Class="Cis.CustomControls.CisDeparturesRow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="80" d:DesignWidth="800" Background="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}, Path=Background}" HorizontalContentAlignment="Stretch" Margin="0,0,0,0" Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}, Path=ActualWidth}">
<UserControl.Resources>
<!-- snip --->
</UserControl.Resources>
<Grid x:Name="ArrivalRowGrid">
<Grid.RowDefinitions>
<RowDefinition Height="47*"/>
<RowDefinition Height="33*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="141"/>
<ColumnDefinition Width="117"/>
<ColumnDefinition Width="241"/>
</Grid.ColumnDefinitions>
<TextBlock Name="TxtDestinationName" MouseDown="TxtDestinationName_OnMouseDown" Style="{StaticResource MainRowStyle}" TextWrapping="Wrap" Text="{Binding Path=DestinationName,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="10,0"/>
<TextBlock Name="TxtPlatNum" TextWrapping="Wrap" Style="{StaticResource MainRowStyle}" Text="{Binding Path=Platform,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="11,0,8,0"
Grid.Row="0" Grid.Column="1"/>
<TextBlock Name="TxtArrTime" TextWrapping="Wrap" Style="{StaticResource MainRowStyle}" TextAlignment="Right" Text="{Binding Path=ExpectedDepartureTime,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="10,0,21,8"
Grid.Row="0" Grid.Column="3" />
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" x:Name="TxtCallingAt" TextWrapping="Wrap" Style="{StaticResource SubRowStyle}" TextAlignment="Left" Text="{Binding Path=CallingAt,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="10,0,21,0" />
</Grid>
</UserControl>
您 link 提出的 SO 问题包含 ArrangeOverride
用于自定义 Panel
的方法,而不是 ListBox
本身。
WPF ListBox
控件的模板,展开后看起来像这样(当然是简化版):
<Border>
<ScrollViewer>
<SomePanel>
<ListBoxItem>your item</ListBoxItem>
<ListBoxItem>your item</ListBoxItem>
<ListBoxItem>your item</ListBoxItem>
<ListBoxItem>etc</ListBoxItem>
</SomePanel>
</ScrollViewer>
</Border>
其中 SomePanel
是从 Panel
派生的 class 的一个实例。列表框的默认值是 VirtualizingStackPanel
但可以这样替换:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
your panel type here
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
您在问题中说这是针对 "non-interactive UI" 的。这有几种不同的解释,但对我来说意味着您可以将 ListBox
替换为 ItemsControl
,因为您不需要列表框的选择功能。然后创建一个自定义面板(派生自 Panel
的 class),添加 linked SO 问题中的 ArrangeOverride
方法,并替换 ItemControl
' s 面板与您的自定义面板。
我有一个显示信息的非交互式 UI。信息保存在带有自定义 listboxitem 控件的 Listbox 控件中。
每个列表框项目的大小可以变化,window 可以根据用户需要调整大小。
我想阻止在应用程序中部分显示的列表框项目显示,这将始终是最后一行。但是,如果我调整 UI 的大小,'last row' 将会改变。
我一直在试验 this SO answer 但没有任何运气。
protected override Size ArrangeOverride(Size finalSize)
{
// Arrange in a stack
double curX = 0;
double curY = 0;
foreach (UIElement child in InternalChildren)
{
double nextY = curY + child.DesiredSize.Height;
if (nextY > finalSize.Height) // Don't display partial items
child.Arrange(new Rect());
else
child.Arrange(new Rect(curX, curY, child.DesiredSize.Width, child.DesiredSize.Height));
curY = nextY;
}
return finalSize;
}
"InternalChildren" 我假设是我的列表框,但列表框不可枚举。我不确定如何使用这个例子。
怎样才能达到预期的效果?
主控
<UserControl x:Class="Cis.CustomControls.CisDeparturesPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:customControls="clr-namespace:Cis.CustomControls"
mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate x:Key="DataTemplate">
<ListBoxItem Padding="0" >
<customControls:CisDeparturesRow />
</ListBoxItem>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="44"/>
<RowDefinition Height="229*"/>
<RowDefinition Height="279*" />
</Grid.RowDefinitions>
<ListBox Grid.Row="2" HorizontalContentAlignment="Stretch" Name="ListBoxDepart" Background="Black" Margin="1,0,-1,0" BorderThickness="0" ItemsSource="{Binding Path=StationMovementList}" ItemTemplate="{StaticResource DataTemplate}" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden" Grid.RowSpan="2">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</UserControl>
ListBoxItem 自定义控件
<UserControl x:Class="Cis.CustomControls.CisDeparturesRow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="80" d:DesignWidth="800" Background="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}, Path=Background}" HorizontalContentAlignment="Stretch" Margin="0,0,0,0" Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}, Path=ActualWidth}">
<UserControl.Resources>
<!-- snip --->
</UserControl.Resources>
<Grid x:Name="ArrivalRowGrid">
<Grid.RowDefinitions>
<RowDefinition Height="47*"/>
<RowDefinition Height="33*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="141"/>
<ColumnDefinition Width="117"/>
<ColumnDefinition Width="241"/>
</Grid.ColumnDefinitions>
<TextBlock Name="TxtDestinationName" MouseDown="TxtDestinationName_OnMouseDown" Style="{StaticResource MainRowStyle}" TextWrapping="Wrap" Text="{Binding Path=DestinationName,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="10,0"/>
<TextBlock Name="TxtPlatNum" TextWrapping="Wrap" Style="{StaticResource MainRowStyle}" Text="{Binding Path=Platform,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="11,0,8,0"
Grid.Row="0" Grid.Column="1"/>
<TextBlock Name="TxtArrTime" TextWrapping="Wrap" Style="{StaticResource MainRowStyle}" TextAlignment="Right" Text="{Binding Path=ExpectedDepartureTime,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="10,0,21,8"
Grid.Row="0" Grid.Column="3" />
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" x:Name="TxtCallingAt" TextWrapping="Wrap" Style="{StaticResource SubRowStyle}" TextAlignment="Left" Text="{Binding Path=CallingAt,NotifyOnTargetUpdated=True, Mode=OneWay}" Margin="10,0,21,0" />
</Grid>
</UserControl>
您 link 提出的 SO 问题包含 ArrangeOverride
用于自定义 Panel
的方法,而不是 ListBox
本身。
WPF ListBox
控件的模板,展开后看起来像这样(当然是简化版):
<Border>
<ScrollViewer>
<SomePanel>
<ListBoxItem>your item</ListBoxItem>
<ListBoxItem>your item</ListBoxItem>
<ListBoxItem>your item</ListBoxItem>
<ListBoxItem>etc</ListBoxItem>
</SomePanel>
</ScrollViewer>
</Border>
其中 SomePanel
是从 Panel
派生的 class 的一个实例。列表框的默认值是 VirtualizingStackPanel
但可以这样替换:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
your panel type here
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
您在问题中说这是针对 "non-interactive UI" 的。这有几种不同的解释,但对我来说意味着您可以将 ListBox
替换为 ItemsControl
,因为您不需要列表框的选择功能。然后创建一个自定义面板(派生自 Panel
的 class),添加 linked SO 问题中的 ArrangeOverride
方法,并替换 ItemControl
' s 面板与您的自定义面板。