it-swarm.com.de

Wie platziere ich die untergeordneten Elemente eines StackPanels heraus?

Gegeben ein StackPanel:

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

Wie lassen sich die untergeordneten Elemente am besten so platzieren, dass zwischen ihnen gleich große Lücken bestehen, obwohl die untergeordneten Elemente selbst unterschiedlich groß sind? Kann dies durchgeführt werden, ohne Eigenschaften für jedes einzelne untergeordnete Element festzulegen?

172
GraemeF

Verwenden Sie Margin oder Padding für den Bereich innerhalb des Containers:

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

BEARBEITEN: Wenn Sie den Rand zwischen zwei Containern wiederverwenden möchten, können Sie den Randwert in eine Ressource in einem äußeren Bereich konvertieren, z.

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

und beziehen Sie sich dann auf diesen Wert im inneren Bereich

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

Ein weiterer Ansatz von Nice ist hier zu sehen: http://blogs.Microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set- Abstand-zwischen-Elementen-in-Stackpanel.aspx

Es wird gezeigt, wie ein angefügtes Verhalten erstellt wird, sodass die folgende Syntax funktioniert:

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

Dies ist die einfachste und schnellste Möglichkeit, Margin auf mehrere untergeordnete Elemente eines Panels festzulegen, auch wenn diese nicht vom selben Typ sind. (D. H. Schaltflächen, Textfelder, Kombinationsfelder usw.)

81
Elad Katz

Ich habe mich verbessert auf Elad Katz 'Antwort .

  • Fügen Sie MarginSetter die LastItemMargin-Eigenschaft hinzu, um das letzte Element speziell zu behandeln
  • Fügen Sie die angehängte Eigenschaft "Abstand" mit den Eigenschaften "Vertikal" und "Horizontal" hinzu, um den Abstand zwischen Elementen in vertikalen und horizontalen Listen zu erhöhen und den nachgestellten Rand am Ende der Liste zu beseitigen

Quellcode in Gist .

Beispiel:

<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

Das, was Sie wirklich tun möchten, ist, alle untergeordneten Elemente umzubrechen. In diesem Fall sollten Sie ein Element-Steuerelement verwenden und nicht auf schreckliche Eigenschaften zurückgreifen, von denen Sie am Ende eine Million für jede Eigenschaft haben, die Sie stylen möchten.

<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 für die Antwort von Sergey. Und wenn Sie das auf alle Ihre StackPanels anwenden möchten, können Sie dies tun:

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

Aber Vorsicht: Wenn Sie einen Stil wie diesen in Ihrer App.xaml definieren (oder in einem anderen Wörterbuch, das in die Application.Resources eingefügt wird), can Überschreibt den Standardstil des Steuerelements. Bei den meisten Steuerelementen wie dem Stackpanel ist dies kein Problem, aber bei Textboxen usw. kann es vorkommen, dass Sie auf dieses Problem stoßen, das zum Glück einige Problemumgehungen aufweist.

6
Andre Luus

Dem Vorschlag von Sergey folgend, können Sie anstelle eines Thickness-Objekts einen ganzen Style (mit verschiedenen Eigenschaftssetzern, einschließlich Margin) definieren und wiederverwenden:

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

Beachten Sie, dass der Trick hier die Verwendung der Stilvererbung für den impliziten Stil ist, die vom Stil in einem äußeren (wahrscheinlich aus einer externen XAML-Datei zusammengeführten) Ressourcenwörterbuch erbt.

Randnotiz:

Zuerst habe ich naiv versucht, den impliziten Stil zu verwenden, um die Style-Eigenschaft des Steuerelements auf diese äußere Style-Ressource festzulegen (etwa definiert mit dem Schlüssel "MyStyle"):

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

dadurch wurde Visual Studio 2010 sofort mit dem CATASTROPHIC FAILURE-Fehler (HRESULT: 0x8000FFFF (E_UNEXPECTED)) beendet, wie unter https://connect.Microsoft.com/VisualStudio/feedback/details/753211/xaml-editor beschrieben -Fenster-schlägt-mit-katastrophalem-Fehler-fehl,-wenn-ein-Stil-versucht-Stil-Eigenschaft zu setzen #

3
George Birbilis

Grid.ColumnSpacing , Grid.RowSpacing , StackPanel.Spacing sind jetzt in der UWP-Vorschau.

Diese Eigenschaften sind derzeit nur mit dem Windows 10 Fall Creators Update Insider SDK verfügbar, sollten es aber bis zum letzten Bit schaffen!

3
Pedro Lamas

Mein Ansatz erbt StackPanel.

Verwendung:

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

Alles, was benötigt wird, ist die folgende kurze Klasse:

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

Das UniformGrid ist möglicherweise nicht in Silverlight verfügbar, aber jemand hat es aus WPF portiert. http://www.jeff.wilcox.name/2009/01/uniform-grid/

2
Jean Azzopardi

manchmal müssen Sie den Abstand und nicht den Rand festlegen, um den Abstand zwischen den Elementen zu verringern

0
Serov Danil