网格和堆栈面板之间的WPF组合

时间:2018-12-18 10:34:03

标签: c# wpf grid stackpanel

我当前正在尝试查找/实现WPF控件,该控件是GridStackPanel的组合。就是说,我喜欢两列包含几个项目。一个项目是另一个控件(例如,单个LabelTextBox在面板中带有标签,...)。

如果一个项目被折叠,则下一个项目应填充空白区域,这意味着我在控件中使用的空间总是尽可能地少(单个项目之间没有间隙)。

我附加了两个图像,看起来应该是这样。

初始: Initial

Item4已折叠(注意后续项目的转移): One item collapsed

有人有想法或经验如何做这样的事情吗?

4 个答案:

答案 0 :(得分:0)

您可以使用将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>

您可以将列表元素的可见性绑定到折叠或可见的属性。

答案 1 :(得分:0)

我将通过以下方式解决此问题:

  • 首先创建具有两个堆栈面板的网格(该网格位于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设置为HiddenCollapsed

  • 您需要一些方法来选择可见项并将其交替放置在左右面板上。我想出了一些快速方法,每次列表更改(添加或删除项目,项目的可见性更改)时,您都需要调用该方法:

    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。无论如何,这是一个好的开始。

答案 2 :(得分:0)

非常感谢您提供所有不同的解决方案。最后,我用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;
    }

我还为商品创建了自己的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>

所以我得到以下结果(从我的测试应用程序中得到):

enter image description here

项目3折叠:

enter image description here

答案 3 :(得分:0)

令我惊讶的是,没有人建议使用UniformGrid

您要做的就是声明UniformGrid,将Columns设置为2并添加您的项目。折叠的项目应将其Visibility设置为Collapsed(duh)。

这是一个例子:

<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的{​​{1}}设置为TextBlock时,如下所示: