2009-05-31 88 views
146

給出一個StackPanel:如何分隔出StackPanel的子元素?

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

什麼是最好的方式,空間了子元素,使它們之間存在着大小相等的差距,即使子元素本身的大小不同?可以在沒有爲每個孩子設置屬性的情況下完成嗎?

回答

228

使用保證金或填充,適用於容器內的範圍:

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

編輯:如果你想重新使用兩個容器之間的餘量,可以邊距值轉換爲外部範圍內的資源,fe

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

的範圍的風格是*真棒*的方式來做到這一點 - 謝謝你的提示! – 2009-05-31 18:41:34

+1

如果我想將其用於整個項目,該怎麼辦? – 2012-11-28 13:09:50

+4

有人可以解釋爲什麼這隻適用於你明確定義類型(例如TextBox)?如果我使用FrameworkElement嘗試此操作,以便所有的孩子都有空間,那麼它就沒有任何作用。 – Schneider 2014-01-28 18:48:20

4

+1對謝爾蓋的回答。如果你想要的是適用於所有StackPanels你可以這樣做:

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

但要注意:如果您在App.xaml中定義這樣的風格(或者被合併到應用程序的另一個字典.Resources)可以覆蓋控件的默認樣式。對於大多數不尋常的控制,如堆疊面板,這不是一個問題,但對於文本框等,你可能偶然發現this problem,幸運的是有一些解決方法。

69

另外一個不錯的方法可以在這裏看到: 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> 

這是最簡單的&最快的方法將保證金設置爲面板的幾個孩子,即使他們不屬於同一類型。 (例如:按鈕,文本框,組合框等)

3

對謝爾蓋的建議之後,你就可以,而不只是一個厚度對象定義和重用的整體風格(帶有各種屬性setter,包括保證金):

<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文件合併)資源字典風格繼承。

旁註:

起初,我天真地試圖用隱式樣式設置控制到外部樣式資源的樣式屬性(比如用鑰匙「myStyle的」定義)

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

造成的Visual Studio 2010來立即關閉,並出現災難性故障錯誤(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#

0

描述有時你需要設置填充,沒有保證金做項目比默認

9

我對Elad Katz' answer改善小之間的空間。

  • LastItemMargin屬性添加到MarginSetter特別處理的最後一個項目
  • 添加間距與垂直和水平的屬性附加屬性,增加了項目之間的間距在垂直和水平列表,並在列表的最後消除了任何後頁邊空白

Source code in 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> 
5

你真的想要做的事情是包裝所有的子元素。在這種情況下,你應該使用物品控制,而不是訴諸可怕的附加屬性,你將最終擁有一百萬的你想要風格的每個屬性。

<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

0

我的方法繼承的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(); 
     } 
    } 
}