wpf 如何将 StackPanel 的子元素隔开?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/932510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:29:50  来源:igfitidea点击:

How do I space out the child elements of a StackPanel?

wpfsilverlightxamlstackpanel

提问by GraemeF

Given a StackPanel:

给定一个 StackPanel:

<StackPanel>
  <TextBox Height="30">Apple</TextBox>
  <TextBox Height="80">Banana</TextBox>
  <TextBox Height="120">Cherry</TextBox>
</StackPanel>

What's the best way to space out the child elements so that there are equally-sized gaps between them, even though the child elements themselves are of different sizes? Can it be done without setting properties on each of the individual children?

即使子元素本身的大小不同,将子元素隔开以使它们之间具有相同大小的间隙的最佳方法是什么?可以在不为每个单独的孩子设置属性的情况下完成吗?

回答by Sergey Aldoukhov

Use Margin or Padding, applied to the scope within the container:

使用 Margin 或 Padding,应用于容器内的范围:

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="0,10,0,0"/>
        </Style>
    </StackPanel.Resources> 
    <TextBox Text="Apple"/>
    <TextBox Text="Banana"/>
    <TextBox Text="Cherry"/>
</StackPanel>

EDIT: In case you would want to re-use the margin between two containers, you can convert the margin value to a resource in an outer scope, f.e.

编辑:如果您想重新使用两个容器之间的边距,您可以将边距值转换为外部范围内的资源,fe

<Window.Resources>
    <Thickness x:Key="tbMargin">0,10,0,0</Thickness>
</Window.Resources>

and then refer to this value in the inner scope

然后在内部作用域中引用这个值

<StackPanel.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="Margin" Value="{StaticResource tbMargin}"/>
    </Style>
</StackPanel.Resources>

回答by Elad Katz

Another nice approach can be seen here: http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between-items-in-stackpanel.aspxLink is broken -> this is webarchiveof this link.

另一个不错的方法可以在这里看到:http: //blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between- items-in-stackpanel.aspx链接已损坏 ->这是此链接的网络存档

It shows how to create an attached behavior, so that syntax like this would work:

它展示了如何创建附加行为,以便这样的语法可以工作:

<StackPanel local:MarginSetter.Margin="5">
   <TextBox Text="hello" />
   <Button Content="hello" />
   <Button Content="hello" />
</StackPanel>

This is the easiest & fastest way to set Margin to several children of a panel, even if they are not of the same type. (I.e. Buttons, TextBoxes, ComboBoxes, etc.)

这是将 Margin 设置为面板的多个子项的最简单和最快的方法,即使它们的类型不同。(即按钮、文本框、组合框等)

回答by angularsen

I improved on Elad Katz' answer.

我改进了Elad Katz 的回答

  • Add LastItemMargin property to MarginSetter to specially handle the last item
  • Add Spacing attached property with Vertical and Horizontal properties that adds spacing between items in vertical and horizontal lists and eliminates any trailing margin at the end of the list
  • 将 LastItemMargin 属性添加到 MarginSetter 以专门处理最后一项
  • 使用 Vertical 和 Horizo​​ntal 属性添加 Spacing 附加属性,可在垂直和水平列表中的项目之间添加间距并消除列表末尾的任何尾随边距

Source code in gist.

gist 中的源代码

Example:

例子:

<StackPanel Orientation="Horizontal" foo:Spacing.Horizontal="5">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

<StackPanel Orientation="Vertical" foo:Spacing.Vertical="5">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

<!-- Same as vertical example above -->
<StackPanel Orientation="Vertical" foo:MarginSetter.Margin="0 0 0 5" foo:MarginSetter.LastItemMargin="0">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

回答by bradgonesurfing

The thing you really want to do is wrap all child elements. In this case you should use an items control and not resort to horrible attached properties which you will end up having a million of for every property you wish to style.

您真正想做的是包装所有子元素。在这种情况下,您应该使用项目控件,而不是求助于可怕的附加属性,对于您希望设置样式的每个属性,您最终都会拥有一百万个附加属性。

<ItemsControl>

    <!-- target the wrapper parent of the child with a style -->
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="Control">
            <Setter Property="Margin" Value="0 0 5 0"></Setter>
        </Style>
    </ItemsControl.ItemContainerStyle>

    <!-- use a stack panel as the main container -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- put in your children -->
    <ItemsControl.Items>
        <Label>Auto Zoom Reset?</Label>
        <CheckBox x:Name="AutoResetZoom"/>
        <Button x:Name="ProceedButton" Click="ProceedButton_OnClick">Next</Button>
        <ComboBox SelectedItem="{Binding LogLevel }" ItemsSource="{Binding LogLevels}" />
    </ItemsControl.Items>
</ItemsControl>

enter image description here

在此处输入图片说明

回答by Andre Luus

+1 for Sergey's answer. And if you want to apply that to all your StackPanels you can do this:

+1 谢尔盖的回答。如果你想把它应用到你所有的 StackPanels,你可以这样做:

<Style TargetType="{x:Type StackPanel}">
    <Style.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="{StaticResource tbMargin}"/>
        </Style>
    </Style.Resources>
</Style>

But beware:if you define a style like this in your App.xaml (or another dictionary that is merged into the Application.Resources) it canoverride the default style of the control. For mostly lookless controls like the stackpanel it isn't a problem, but for textboxes etc you may stumble upon this problem, which luckily has some workarounds.

但请注意:如果您在 App.xaml(或合并到 Application.Resources 的另一个字典)中定义这样的样式,它可以覆盖控件的默认样式。对于大多数看起来像堆栈面板这样的控件来说,这不是问题,但对于文本框等,您可能会偶然发现这个问题,幸运的是有一些解决方法。

回答by George Birbilis

Following up on Sergey's suggestion, you can define and reuse a whole Style (with various property setters, including Margin) instead of just a Thickness object:

按照 Sergey 的建议,您可以定义和重用整个 Style(带有各种属性设置器,包括 Margin),而不仅仅是一个 Thickness 对象:

<Style x:Key="MyStyle" TargetType="SomeItemType">
  <Setter Property="Margin" Value="0,5,0,5" />
  ...
</Style>

...

...

  <StackPanel>
    <StackPanel.Resources>
      <Style TargetType="SomeItemType" BasedOn="{StaticResource MyStyle}" />
    </StackPanel.Resources>
  ...
  </StackPanel>

Note that the trick here is the use of Style Inheritance for the implicit style, inheriting from the style in some outer (probably merged from external XAML file) resource dictionary.

请注意,这里的技巧是将样式继承用于隐式样式,继承自某些外部(可能从外部 XAML 文件合并)资源字典中的样式。

Sidenote:

边注:

At first, I naively tried to use the implicit style to set the Style property of the control to that outer Style resource (say defined with the key "MyStyle"):

起初,我天真地尝试使用隐式样式将控件的 Style 属性设置为该外部 Style 资源(例如使用键“MyStyle”定义):

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="SomeItemType">
      <Setter Property="Style" Value={StaticResource MyStyle}" />
    </Style>
  </StackPanel.Resources>
</StackPanel>

which caused Visual Studio 2010 to shut down immediately with CATASTROPHIC FAILURE error (HRESULT: 0x8000FFFF (E_UNEXPECTED)), as described at https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastrophic-failure-when-a-style-tries-to-set-style-property#

这导致 Visual Studio 2010 立即关闭并出现 CATASTROPHIC FAILURE 错误(HRESULT: 0x8000FFFF (E_UNEXPECTED)),如https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails 所述-with-catastrophic-failure-when-a-style-tries-to-set-style-property#

回答by Pedro Lamas

Grid.ColumnSpacing, Grid.RowSpacing, StackPanel.Spacingare now on UWP preview, all will allow to better acomplish what is requested here.

Grid.ColumnSpacingGrid.RowSpacingStackPanel.Spacing现在在 UWP 预览版中,所有这些都将允许更好地完成这里所要求的内容。

These properties are currently only available with the Windows 10 Fall Creators Update Insider SDK, but should make it to the final bits!

这些属性目前仅适用于 Windows 10 Fall Creators Update Insider SDK,但应该会用到最后!

回答by James M

My approach inherits StackPanel.

我的方法继承了 StackPanel。

Usage:

用法:

<Controls:ItemSpacer Grid.Row="2" Orientation="Horizontal" Height="30" CellPadding="15,0">
    <Label>Test 1</Label>
    <Label>Test 2</Label>
    <Label>Test 3</Label>
</Controls:ItemSpacer>

All that's needed is the following short class:

所需要的只是以下简短的课程:

using System.Windows;
using System.Windows.Controls;
using System;

namespace Controls
{
    public class ItemSpacer : StackPanel
    {
        public static DependencyProperty CellPaddingProperty = DependencyProperty.Register("CellPadding", typeof(Thickness), typeof(ItemSpacer), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnCellPaddingChanged));
        public Thickness CellPadding
        {
            get
            {
                return (Thickness)GetValue(CellPaddingProperty);
            }
            set
            {
                SetValue(CellPaddingProperty, value);
            }
        }
        private static void OnCellPaddingChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
        {
            ((ItemSpacer)Object).SetPadding();
        }

        private void SetPadding()
        {
            foreach (UIElement Element in Children)
            {
                (Element as FrameworkElement).Margin = this.CellPadding;
            }
        }

        public ItemSpacer()
        {
            this.LayoutUpdated += PART_Host_LayoutUpdated;
        }

        private void PART_Host_LayoutUpdated(object sender, System.EventArgs e)
        {
            this.SetPadding();
        }
    }
}

回答by Jean Azzopardi

The UniformGrid might not be available in Silverlight, but someone has ported it from WPF. http://www.jeff.wilcox.name/2009/01/uniform-grid/

UniformGrid 在 Silverlight 中可能不可用,但有人已经从 WPF 中移植了它。http://www.jeff.wilcox.name/2009/01/uniform-grid/

回答by Danil

sometimes you need to set Padding, not Margin to make space between items smaller than default

有时您需要设置 Padding 而不是 Margin 以使项目之间的空间小于默认值