web-dev-qa-db-ja.com

StackPanelの子要素をスペースで区切るにはどうすればよいですか?

StackPanelが与えられた場合:

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

子要素自体のサイズが異なっていても、それらの間に同じサイズのギャップがあるように、子要素の間隔を空ける最良の方法は何ですか?個々の子のそれぞれにプロパティを設定せずに実行できますか?

172
GraemeF

コンテナ内のスコープに適用されるマージンまたはパディングを使用します。

<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>

編集:2つのコンテナ間のマージンを再利用したい場合は、マージン値を外部スコープのリソースに変換することができます、例えば.

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

そして、内部スコープでこの値を参照します

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

別の素敵なアプローチはここにあります: http://blogs.Microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set- spacing-between-items-in-stackpanel.aspx

アタッチされた動作を作成する方法を示しているため、次のような構文が機能します。

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

これは、同じタイプではない場合でも、Marginをパネルの複数の子に設定する最も簡単で最速の方法です。 (つまり、ボタン、テキストボックス、コンボボックスなど)

81
Elad Katz

Elad Katz 'answer を改善しました。

  • LastItemMarginプロパティをMarginSetterに追加して、最後のアイテムを特別に処理します
  • 垂直および水平リストのアイテム間にスペースを追加し、リストの末尾の余白を削除する、垂直および水平プロパティを使用して間隔添付プロパティを追加します。

Gistのソースコード

例:

<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>
13
angularsen

本当にやりたいことは、すべての子要素をラップすることです。この場合、アイテムコントロールを使用する必要があります。ひどい添付プロパティに頼るのではなく、スタイルを設定するすべてのプロパティに対して数百万のプロパティが必要になります。

<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

8
bradgonesurfing

セルゲイの答えに+1。そして、それをすべてのStackPanelに適用したい場合、これを行うことができます:

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

しかし、注意してください:App.xaml(またはApplication.Resourcesにマージされる別の辞書)でこのようなスタイルを定義する場合、それcanコントロールのデフォルトスタイルをオーバーライドします。スタックパネルのようなほとんど見栄えの悪いコントロールでは問題になりませんが、テキストボックスなどでは この問題 に出くわすことがありますが、幸いなことに回避策があります。

6
Andre Luus

Sergeyの提案に従って、Thicknessオブジェクトだけでなく、Style(Marginを含むさまざまなプロパティセッターを使用)全体を定義して再利用できます。

<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>

ここでのトリックは、外部(おそらく外部XAMLファイルからマージされた)リソースディクショナリのスタイルを継承する暗黙のスタイルにスタイル継承を使用することに注意してください。

サイドノート:

最初は、暗黙的なスタイルを使用して、コントロールのStyleプロパティをその外側のStyleリソースに設定しようとしました(たとえば、キー "MyStyle"で定義)。

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

https://connect.Microsoft.com/VisualStudio/feedback/details/753211/xaml-editorで説明されているように、Visual Studio 2010はCATASTROPHIC FAILUREエラー(HRESULT:0x8000FFFF(E_UNEXPECTED))で直ちにシャットダウンしました-window-fails-with-catastrophic-failure-when-a-style-tries-to-set-style-property#

3
George Birbilis

Grid.ColumnSpacingGrid.RowSpacingStackPanel.Spacing はUWPプレビューになりました。

これらのプロパティは現在、Windows 10 Fall Creators Update Insider SDKでのみ使用できますが、最終段階に到達するはずです!

3
Pedro Lamas

私のアプローチはStackPanelを継承しています。

使用法:

<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>

必要なのは、次の短いクラスです。

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();
        }
    }
}
2
James M

UniformGridはSilverlightで利用できない場合がありますが、誰かがWPFから移植しています。 http://www.jeff.wilcox.name/2009/01/uniform-grid/

2
Jean Azzopardi

アイテム間のスペースをデフォルトよりも小さくするために、MarginではなくPaddingを設定する必要がある場合があります

0
Serov Danil