ฉันจะเว้นวรรคองค์ประกอบย่อยของ StackPanel ได้อย่างไร


187

รับ StackPanel:

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

อะไรคือวิธีที่ดีที่สุดในการจัดวางองค์ประกอบของเด็กเพื่อให้มีช่องว่างขนาดเท่ากันระหว่างทั้งสองแม้ว่าองค์ประกอบของเด็กจะมีขนาดต่างกัน สามารถทำได้โดยไม่ตั้งค่าคุณสมบัติสำหรับเด็กแต่ละคนหรือไม่


การเพิ่มช่องว่างในแต่ละรายการน่าจะเป็นตัวเลือกที่ดีที่สุด
zar

คำตอบ:


278

ใช้มาร์จิ้นหรือแพ็ดดิงที่ใช้กับขอบเขตภายในคอนเทนเนอร์:

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

แก้ไข: ในกรณีที่คุณต้องการใช้มาร์จิ้นระหว่างสองคอนเทนเนอร์อีกครั้งคุณสามารถแปลงค่ามาร์จิ้นเป็นทรัพยากรในขอบเขตภายนอกได้

<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
กำหนดขอบเขตรูปแบบเป็นที่น่ากลัววิธีการที่จะทำอย่างนั้น - ขอบคุณสำหรับเคล็ดลับ!
Ana Betts

2
ถ้าฉันต้องการใช้กับโครงการทั้งหมด
grv_9098

10
บางคนสามารถอธิบายได้ว่าเหตุใดจึงใช้งานได้เฉพาะเมื่อคุณกำหนดประเภทอย่างชัดเจน (เช่นกล่องข้อความ) ถ้าฉันลองทำสิ่งนี้โดยใช้ FrameworkElement เพื่อให้เด็กทุกคนเว้นระยะห่างกันจะไม่มีผลกระทบใด ๆ
Jack Ukleja

4
สิ่งนี้ใช้งานไม่ได้หากคุณกำหนดสไตล์ไว้Buttonแล้ว
ทำเครื่องหมายอินแกรม

1
ในฐานะที่เป็นบันทึกด้านข้างถ้าคุณต้องการทำสิ่งนี้กับLabelคุณต้องใช้PaddingแทนMargin
Anthony Nichols

84

วิธีการที่ดีอีกวิธีหนึ่งสามารถดูได้ที่นี่: http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-the-easiest-way-to-set-spacing-between- items-in-stackpanel.aspx ลิงก์ใช้งานไม่ได้ -> เป็น webarchiveลิงค์ของลิงค์นี้

มันแสดงวิธีการสร้างพฤติกรรมที่แนบมาดังนั้นไวยากรณ์เช่นนี้จะทำงาน:

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

นี่เป็นวิธีที่ง่ายที่สุดและเร็วที่สุดในการตั้งค่าระยะขอบให้กับเด็ก ๆ หลายคนของแผงแม้ว่าพวกเขาจะไม่ได้เป็นประเภทเดียวกัน (เช่นปุ่ม, กล่องข้อความ, คอมโบบ็อกซ์ ฯลฯ )


5
นี่เป็นวิธีที่น่าสนใจทีเดียว มันทำให้มีข้อสันนิษฐานมากมายเกี่ยวกับวิธีที่คุณต้องการพื้นที่สิ่งต่าง ๆ และยังให้โอกาสคุณปรับระยะขอบบนรายการแรก / สุดท้ายโดยอัตโนมัติ
Armentage

2
+1 เพื่อความคล่องตัว นอกจากนี้เพื่อปรับปรุงในการโพสต์บล็อกเพิ่มif (fe.ReadLocalValue(FrameworkElement.MarginProperty) == DependencyProperty.UnsetValue)ก่อนจริงการตั้งค่าระยะขอบของเด็กจะช่วยให้ระบุระยะขอบด้วยตนเองสำหรับองค์ประกอบบางอย่าง
Xerillio

โปรดทราบว่าสิ่งนี้ไม่ทำงานหากมีการเพิ่ม / ลบรายการลูกแบบไดนามิกเช่นใน ItemsControl ที่ผูกไว้กับคอลเลกชันที่เปลี่ยนแปลง
Drew Noakes

1
ในกรณีที่ใช้งานไม่ได้: สร้างโครงการมิฉะนั้นจะไม่แสดงหน้าเว็บ
ต่อสู้

2
ลิงก์เสีย!
เดฟ

13

ฉันปรับปรุงคำตอบ Elad แคทซ์'

  • เพิ่มคุณสมบัติ LastItemMargin ไปยัง MarginSetter เพื่อจัดการรายการสุดท้ายเป็นพิเศษ
  • เพิ่มคุณสมบัติระยะห่างที่แนบมาพร้อมกับคุณสมบัติแนวตั้งและแนวนอนที่เพิ่มระยะห่างระหว่างรายการในรายการแนวตั้งและแนวนอนและกำจัดระยะขอบต่อท้ายที่ส่วนท้ายของรายการ

รหัสที่มาในกระทู้

ตัวอย่าง:

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

เช่นเดียวกับคำตอบของ Elad สิ่งนี้จะไม่ทำงานหากไอเท็มลูกถูกเพิ่ม / ลบแบบไดนามิกเช่นอยู่ในItemsControlคอลเลกชันที่เปลี่ยนไป มันจะถือว่าไอเท็มคงที่ตั้งแต่Loadเหตุการณ์ไฟของผู้ปกครอง
Drew Noakes

ส่วนสำคัญของคุณให้ 404
Drew Noakes

อัพเดทลิงค์ไปยังส่วนสำคัญ
angularsen

9

สิ่งที่คุณต้องการจะทำคือห่อองค์ประกอบลูกทั้งหมด ในกรณีนี้คุณควรใช้การควบคุมไอเท็มและไม่ควรใช้คุณสมบัติที่ติดกับสิ่งที่น่ากลัวซึ่งคุณจะได้รับเป็นล้านในทุก ๆ คุณสมบัติที่คุณต้องการ

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

ป้อนคำอธิบายรูปภาพที่นี่


เคล็ดลับที่ดี แต่ผลงานที่ดีกว่านี้กับสไตล์ TargetType เป็น "FrameworkElement" (มิฉะนั้นจะไม่ทำงานสำหรับภาพตัวอย่าง)
Puffin

1
ฉันชอบความคิดนี้ การเพิ่มเพียงครั้งเดียว: การลบจำนวนระยะห่างจากระยะขอบของ StackPanel ( Margin="0 0 -5 0") จะนับระยะห่างหลังรายการสุดท้ายในรายการ
label17

ปัญหานี้คือสไตล์ที่คุณตั้งไว้จะแทนที่สไตล์อื่น ๆ ที่คุณอาจมีอยู่ในรายการ หากต้องการเอาชนะสิ่งนี้โปรดดูคำถาม / คำตอบที่ยอมรับได้ที่นี่
waxingsatirical

6

+1 สำหรับคำตอบของ Sergey และถ้าคุณต้องการใช้สิ่งนั้นกับ 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 ของคุณ (หรือพจนานุกรมอื่นที่รวมอยู่ใน Application.Resources) มันสามารถแทนที่ลักษณะเริ่มต้นของการควบคุมได้ สำหรับตัวควบคุมที่ไม่มีลักษณะส่วนใหญ่อย่างเช่นพาเนลพาเนลมันไม่ใช่ปัญหา แต่สำหรับกล่องข้อความและอื่น ๆ คุณอาจสะดุดกับปัญหานี้ซึ่งโชคดีที่มีวิธีแก้ไขปัญหาบางอย่าง


<Style.Resources> คุณแน่ใจหรือไม่ว่า coz เมื่อฉันลองทำสิ่งนี้มันแสดงข้อผิดพลาด
grv_9098

ขอโทษฉันจำไม่ได้ ฉันจะลองเองดู ฉันจะกลับไปหาคุณ.
Andre Luus

ใช่มันใช้งานได้ ทำแบบเดียวกันกับการตั้งค่า TextWeight = "Bold" บน TextBlocks ทั้งหมดใน StackPanel ความแตกต่างเพียงอย่างเดียวคือฉันกำหนดสไตล์อย่างชัดเจนบน StackPanel
Andre Luus

ขอบคุณสำหรับความกังวลของคุณ แต่ฉันยังคงมีข้อสงสัยฉันรู้ว่ามันเรียกว่าสไตล์ขอบเขต ฉันเดาว่ามันจะเป็น <StackPanel.Resources> ไม่ใช่ <Style.Resources> มันจะดีกว่านี้ถ้าคุณสามารถวางชิ้นส่วนรหัสของคุณ ...
grv_9098

3

การติดตามข้อเสนอแนะของ Sergey คุณสามารถกำหนดและนำสไตล์ทั้งหมดมาใช้ใหม่ (พร้อมตัวตั้งค่าคุณสมบัติต่าง ๆ รวมถึงส่วนต่าง) แทนวัตถุความหนา:

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

โปรดทราบว่าเคล็ดลับที่นี่คือการใช้ Style Inheritance สำหรับสไตล์โดยนัยซึ่งสืบทอดมาจากสไตล์ในพจนานุกรมทรัพยากรด้านนอก (อาจผสานจากไฟล์ XAML ภายนอก)

sidenote:

ในตอนแรกฉันพยายามใช้สไตล์โดยปริยายเพื่อตั้งค่าคุณสมบัติสไตล์ของตัวควบคุมให้เป็นทรัพยากรสไตล์ภายนอก (พูดตามที่กำหนดด้วยคีย์ "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 เมื่อใช้-ภัยพิบัติล้มเหลวเมื่อ-a-สไตล์พยายามต่อการตั้งค่ารูปแบบสถานที่ให้บริการ #


3

Grid.ColumnSpacing , Grid.RowSpacing , StackPanel.Spacingตอนนี้มีการแสดงตัวอย่าง UWP ทั้งหมดจะช่วยให้ดีขึ้น acomplish สิ่งที่ขอที่นี่

ปัจจุบันคุณสมบัติเหล่านี้มีให้บริการเฉพาะกับ SDK ผู้สร้าง Fall Update Update Windows 10 เท่านั้น แต่ควรทำให้เป็นบิตสุดท้าย!



2

วิธีการของฉันสืบทอด 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();
        }
    }
}

0

บางครั้งคุณต้องตั้งค่าการแพ็ดดิ้งไม่ใช่มาร์จิ้นเพื่อสร้างช่องว่างระหว่างรายการที่เล็กกว่าค่าเริ่มต้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.