网格和stackpanel之间的WPF组合
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网格和stackpanel之间的WPF组合相关的知识,希望对你有一定的参考价值。
我目前正在尝试查找/实现WPF控件,它是Grid
和StackPanel
的组合。这意味着,我喜欢有两个包含多个项目的列。一个项目是另一个控件(例如单个Label
,TextBox
,在面板中带有标签,......)。
如果某个项目已折叠,则应使用下一个项目填充空白区域,这意味着我总是尽可能减少控件中使用的空间(单个项目之间没有间隙)。
我附上两张图片应该是什么样的。
初始:
项目4已折叠(请注意后续项目的移位):
有没有人有想法或经验如何做这样的事情?
您可以使用使用StackPanel或DockPanel作为ItemTemplate的ListView。这是我使用Grid和DockPannel在列表中显示可观察对象集合的示例(简化):
<ListView x:Name="lbxDroppedDatas" SelectionMode="Single" AllowDrop="True" BorderThickness="0" Padding="0" Margin="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionChanged="lbxDroppedDatas_SelectionChanged" PreviewKeyDown="lbxDroppedDatas_PreviewKeyDown" PreviewMouseRightButtonDown="lbxDroppedDatas_PreviewMouseRightButtonDown" >
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel Grid.Row="0" Width="{Binding Path=ActualWidth, ElementName=Container}" Height="40" Margin="1" LastChildFill="True">
<CheckBox DockPanel.Dock="Left" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
<Label Content="{Binding Name}" Foreground="{Binding LineBrush}" FontWeight="Bold" FontSize="12" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0" MouseEnter="Label_MouseEnter" MouseLeave="Label_MouseLeave"/>
<TextBox DockPanel.Dock="Right" Width="60" MaxLength="14" Text="{Binding CurrentValue, StringFormat=N}" Margin="0,0,33,0" Background="Transparent" Foreground="{Binding LineBrush}" BorderBrush="{Binding LineBrush}" BorderThickness="1" VerticalAlignment="Center" HorizontalAlignment="Right" IsEnabled="False"/>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" VerticalAlignment="Stretch" Margin="0"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
您可以将列表元素的可见性绑定到折叠或可见属性。
我将通过以下方式解决此问题:
- 首先创建一个包含两个堆栈面板的网格(网格位于UserControl或任何其他占位符中):
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <StackPanel x:Name="LeftPanel" x:FieldModifier="private" Orientation="Vertical" /> <StackPanel x:Name="RightPanel" x:FieldModifier="private" Grid.Column="1" Orientation="Vertical" /> </Grid>
- 控制你的项目,创建一个项目列表,最好是在UserControl的代码中:
private List<FrameworkElement> m_items = new List<FrameworkElement>();
- 对于您不希望看到的项目,请将
Visibility
设置为Hidden
或Collapsed
。 - 您需要一些方法来选择可见项目并将它们交替放置在左侧和右侧面板上。我想出了一些快速方法,您需要在每次更改列表时调用(添加或删除项目,更改项目的可见性):
public void SortItems() { this.LeftPanel.Children.RemoveRange(0, this.LeftPanel.Children.Count); this.RightPanel.Children.RemoveRange(0, this.RightPanel.Children.Count); this.m_items.Where(i => i.Visibility == Visibility.Visible).ToList().ForEach((i) => { (this.LeftPanel.Children.Count == this.RightPanel.Children.Count ? this.LeftPanel : this.RightPanel).Children.Add(i); } ); }
该方法只是删除堆栈面板的所有子项,然后遍历项目列表,只选择那些Visible
,如果两个面板中的项目数量相同,则向左侧面板添加一个,否则添加到右侧面板。
如果您需要一些其他方式来选择应该添加以下项目的面板(例如ActualHeight
),只需更改选择面板的条件。
如果要使此方法更加优雅,可以添加一些将自动调用SortItems
的事件或依赖项属性。无论如何,这是一个良好的开端。
非常感谢您提供所有不同的解决方案。最后,我根据Sinatr的建议解决了这个问题。所以我创建了自己的面板并覆盖了ArrangeOverride:
protected override Size ArrangeOverride(Size finalSize)
{
List<UIElement> visibleItems = new List<UIElement>();
double xColumn1 = 0;
double xColumn2 = (finalSize.Width / 2) + (WIDTH_COLUMN_SEPERATOR / 2);
double y = 0;
double columnWidth = (finalSize.Width - WIDTH_COLUMN_SEPERATOR) / 2;
for (int i = 0; i < InternalChildren.Count; i++)
{
UIElement child = InternalChildren[i];
if (child.Visibility != Visibility.Collapsed)
{
visibleItems.Add(child);
}
}
for (int i = 0; i < visibleItems.Count; i++)
{
if (i >= (visibleItems.Count - 1))
{
visibleItems[i].Arrange(new Rect(xColumn1, y, columnWidth, visibleItems[i].DesiredSize.Height));
}
else
{
UIElement leftItem = visibleItems[i];
UIElement rightItem = visibleItems[i + 1];
double rowHeight = leftItem.DesiredSize.Height > rightItem.DesiredSize.Height ? leftItem.DesiredSize.Height : rightItem.DesiredSize.Height;
leftItem.Arrange(new Rect(xColumn1, y, columnWidth, rowHeight));
rightItem.Arrange(new Rect(xColumn2, y, columnWidth, rowHeight));
y += rowHeight;
i++;
}
}
return finalSize;
}
我还为Items创建了自己的UserControl:
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label x:Name="captionLabel" Grid.Row="0" Content="{Binding Caption}"/>
<ContentPresenter x:Name="inputMask" Grid.Row="1" Content="{Binding InputMask, ElementName=userControlBRAIN2AttributePanelItem}" />
</Grid>
所以我得到以下结果(来自我的测试应用程序):
折叠项目3:
我很惊讶没有人建议使用qazxsw poi。
你所要做的就是声明一个UniformGrid
,将UniformGrid
设置为2并添加你的物品。折叠的项目应将其Columns
设置为Visibility
(duh)。
这是一个例子:
Collapsed
会产生以下结果:
<UniformGrid Columns="2"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock Text="Item 1 " />
<TextBlock Text="Item 2 " />
<TextBlock Text="Item 3 " />
<TextBlock Text="Item 4 " />
</UniformGrid>
当第二个的Visibility
设置为TextBlock
时,这就是它的样子:
Collapsed
以上是关于网格和stackpanel之间的WPF组合的主要内容,如果未能解决你的问题,请参考以下文章
StackPanel 中的网格:为啥 auto 和 * 行为异常?
C# WPF 如何在向 Stackpanel 添加许多 UI 元素时保持应用程序响应