Frage

Ist es leicht möglich, einen Spielraum und / oder Polsterung für Zeilen oder Spalten in einem WPF-Grid angeben?

Ich könnte natürlich fügen Sie zusätzliche Spalten Raum Dinge, aber dies scheint wie ein Job für padding / Margen (es gibt viel simplier XAML). Hat jemand von den Standard-Grid abgeleitet diese Funktionalität hinzufügen?

War es hilfreich?

Lösung

Sie können Ihre eigene GridWithMargin Klasse, geerbt von Grid, schreiben und die ArrangeOverride Methode überschreiben, die Ränder

anzuwenden

Andere Tipps

RowDefinition und ColumnDefinition sind vom Typ ContentElement und Margin ist ausschließlich eine FrameworkElement Eigenschaft. Also auf Ihre Frage, „ist es leicht möglich“ die Antwort ist ein sehr klares Nein. Und nein, ich habe keinen Layout-Panels gesehen, dass diese Art von Funktionalität zu demonstrieren.

Sie können zusätzliche Zeilen oder Spalten hinzufügen, wie Sie vorgeschlagen. Aber Sie können auch festlegen, die Margen auf einem Grid Element selbst oder irgendetwas, das in einem Grid gehen würde, so dass das die beste Abhilfe für jetzt.

Verwenden einer Border Steuerung außerhalb der Zellkontrolle und definiert die Polsterung für das:

    <Grid>
        <Grid.Resources >
            <Style TargetType="Border" >
                <Setter Property="Padding" Value="5,5,5,5" />
            </Style>
        </Grid.Resources>

        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Border Grid.Row="0" Grid.Column="0">
            <YourGridControls/>
        </Border>
        <Border Grid.Row="1" Grid.Column="0">
            <YourGridControls/>
        </Border>

    </Grid>


Quelle:

Sie so etwas wie diese verwenden:

<Style TargetType="{x:Type DataGridCell}">
  <Setter Property="Padding" Value="4" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGridCell}">
        <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
          <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>

Oder wenn Sie nicht über die TemplateBindings brauchen:

<Style TargetType="{x:Type DataGridCell}">
   <Setter Property="Template">
      <Setter.Value>
          <ControlTemplate TargetType="{x:Type DataGridCell}">
              <Border Padding="4">
                  <ContentPresenter />
              </Border>
          </ControlTemplate>
      </Setter.Value>
  </Setter>
</Style>

dachte, ich würde meine eigene Lösung hinzugefügt werden, da noch niemand diese erwähnt. Statt einen Usercontrol auf Grid basierte entwerfen, können Sie Bedienelemente mit einem Stylesheet in Raster enthaltenen Ziel. Kümmert sich um das Hinzufügen padding / margin auf alle Elemente, ohne für jeden definieren zu müssen, was mühsam ist und arbeits intensive.For Beispiel, wenn Ihr Grid enthält nichts anderes als Textblocks, Sie können dies tun:

<Style TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="10"/>
</Style>

Welche wie das Äquivalent von "Zelle padding" ist.

Das ist nicht sehr schwierig. Ich kann nicht sagen, wie schwierig es im Jahr 2009 war, als die Frage gestellt wurde, aber das war damals.

Beachten Sie, dass, wenn Sie explizit eine Marge direkt auf einem Kind des Gitters festgelegt, wenn die Verwendung diese Lösung, dass Marge im Designer angezeigt werden, aber nicht zur Laufzeit.

Diese Eigenschaft kann auf Grid angewendet werden, Stackpanel, WrapPanel, Uniform oder einem anderen Abkömmling-Panel. Es wirkt sich sofort Kinder. Es wird vermutet, dass Kinder das Layout ihrer eigenen Inhalte verwalten möchten.

PanelExt.cs

public static class PanelExt
{
    public static Thickness? GetChildMargin(Panel obj)
    {
        return (Thickness?)obj.GetValue(ChildMarginProperty);
    }

    public static void SetChildMargin(Panel obj, Thickness? value)
    {
        obj.SetValue(ChildMarginProperty, value);
    }

    /// <summary>
    /// Apply a fixed margin to all direct children of the Panel, overriding all other margins.
    /// Panel descendants include Grid, StackPanel, WrapPanel, and UniformGrid
    /// </summary>
    public static readonly DependencyProperty ChildMarginProperty =
        DependencyProperty.RegisterAttached("ChildMargin", typeof(Thickness?), typeof(PanelExt),
            new PropertyMetadata(null, ChildMargin_PropertyChanged));

    private static void ChildMargin_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as Panel;

        target.Loaded += (s, e2) => ApplyChildMargin(target, (Thickness?)e.NewValue);

        ApplyChildMargin(target, (Thickness?)e.NewValue);
    }

    public static void ApplyChildMargin(Panel panel, Thickness? margin)
    {
        int count = VisualTreeHelper.GetChildrenCount(panel);

        object value = margin.HasValue ? margin.Value : DependencyProperty.UnsetValue;

        for (var i = 0; i < count; ++i)
        {
            var child = VisualTreeHelper.GetChild(panel, i) as FrameworkElement;

            if (child != null)
            {
                child.SetValue(FrameworkElement.MarginProperty, value);
            }
        }
    }
}

Demo:

MainWindow.xaml

<Grid
    local:PanelExt.ChildMargin="2"
    x:Name="MainGrid"
    >
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Rectangle Width="100" Height="40" Fill="Red" Grid.Row="0" Grid.Column="0" />
    <Rectangle Width="100" Height="40" Fill="Green" Grid.Row="1" Grid.Column="0" />
    <Rectangle Width="100" Height="40" Fill="Blue" Grid.Row="1" Grid.Column="1" />

    <Button Grid.Row="2" Grid.Column="0" Click="NoMarginClick">No Margin</Button>
    <Button Grid.Row="2" Grid.Column="1" Click="BigMarginClick">Big Margin</Button>
    <ComboBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void NoMarginClick(object sender, RoutedEventArgs e)
    {
        PanelExt.SetChildMargin(MainGrid, null);
    }
    private void BigMarginClick(object sender, RoutedEventArgs e)
    {
        PanelExt.SetChildMargin(MainGrid, new Thickness(20));
    }
}

ich in dieses Problem lief während einige Software vor kurzem entwickelt und es fiel mir auf fragen, warum? Warum sie dies getan haben ... war die Antwort genau dort vor mir. Eine Reihe von Daten ist ein Objekt, so dass, wenn wir die Objektorientierung halten, dann ist das Design für eine bestimmte Zeile soll getrennt werden (Sie annehmen müssen später die Zeilenanzeige wiederverwenden auf in der Zukunft). Also begann ich Databound Stapel Platten und benutzerdefinierte Steuerelemente für die meisten Datenanzeigen verwenden. Listen haben die gelegentliche Erscheinung, meist aber das Raster verwendet wurde, nur für die primäre Seite Organisation (Header, Menübereich, Inhaltsbereich, Andere Bereiche). Ihre benutzerdefinierte Objekte kann leicht mit jeder Abstandsanforderungen für jede Zeile in der Stapelplatte oder Gitter verwalten (eine einzelne Gitterzelle die gesamte Zeilenobjekt enthalten kann. Dies hat auch den zusätzlichen Vorteil, richtig zu Orientierungsänderungen reagieren, zeigen / kollabiert usw.

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>

  <custom:MyRowObject Style="YourStyleHereOrGeneralSetter" Grid.Row="0" />
  <custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</Grid>

oder

<StackPanel>
  <custom:MyRowObject Style="YourStyleHere" Grid.Row="0" />
  <custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</StackPanel>

Ihre Benutzerdefinierte Kontrollen wird auch erben die Datacontext wenn Ihr mit Datenbindung ... mein persönlicher Favorit Vorteil dieses Ansatzes.

ich habe es jetzt mit einem meines Gitter.

  • Erste gilt die gleiche Marge auf jedes Element innerhalb des Gitters. Sie können diese mannualy tun, Stile, oder was auch immer Sie mögen. Lassen Sie uns sagen Sie einen horizontalen Abstand von 6px und einen vertikalen Abstand von 2px wollen. Dann fügen Sie Ränder von „3px 1px“ für jedes Kind des Gitters.
  • Sie dann die Ränder um das Raster erstellt entfernen (wenn Sie die Grenzen der Kontrollen innerhalb des Gitters auf die gleiche Position des Gitters ausgerichtet werden soll). Verwenden Sie diese Einstellung eine Marge von „-3px -1px“ an das Netz. Auf diese Weise andere Kontrollen außerhalb des Gitters mit den outtermost Kontrollen innerhalb des Gitters ausgerichtet werden.

Eine Möglichkeit wäre, mit fester Breite Zeilen hinzufügen und Spalten wie die Polsterung / Marge zu handeln, die Sie suchen.

Sie auch interessieren könnten, dass Sie durch die Größe des Containers beschränkt sind, und dass ein Gitter wird so groß wie das Aufnahmeelement oder seine angegebenen Breite und Höhe wird. Sie könnten einfach Spalten und Zeilen ohne Breite oder Höhe Satz verwenden. So können sie standardmäßig gleichmäßig den gesamten Raum innerhalb des Gitters Zerschlagung. Dann wäre es nur sein, eine mater Ihre Elemente vertikal zentriert und horizontal innerhalb Sie Raster.

Ein weiteres Verfahren könnte sein, alle Gitterelemente in einer mit einreihigen & Stützenraster befestigt zu wickeln, die eine feste Größe und Spielraum hat. Dass Ihr Raster enthält feste Breite / Höhe-Boxen, die Ihre tatsächlichen Elemente enthalten.

in UWP (Windows10FallCreatorsUpdate Version und höher)

<Grid RowSpacing="3" ColumnSpacing="3">

Edited:

geben Marge auf jede Kontrolle Sie die Steuerung mit Grenze wie diese wickeln könnte

<!--...-->
    <Border Padding="10">
            <AnyControl>
<!--...-->

Auch wenn Sie nicht Marge oder padding zu einem Gitter hinzufügen, können Sie so etwas wie ein Rahmen (oder einem ähnlichen Behälter) verwenden könnte, dass man es anwenden kann.

Auf diese Weise (wenn Sie ein- oder ausblenden das Steuerelement auf eine Schaltfläche klicken sagen), werden Sie nicht brauchen Marge auf jedem Steuerelement hinzuzufügen, die mit ihm in Wechselwirkung treten können.

Denken Sie daran, wie die Gruppen von Kontrollen in Einheiten zu isolieren, dann diese Einheiten Anwendung Stil.

Wie bereits erwähnt wurde, bevor eine GridWithMargins Klasse erstellen. Hier ist mein Arbeitscodebeispiel

public class GridWithMargins : Grid
{
    public Thickness RowMargin { get; set; } = new Thickness(10, 10, 10, 10);
    protected override Size ArrangeOverride(Size arrangeSize)
    {
        var basesize = base.ArrangeOverride(arrangeSize);

        foreach (UIElement child in InternalChildren)
        {
            var pos = GetPosition(child);
            pos.X += RowMargin.Left;
            pos.Y += RowMargin.Top;

            var actual = child.RenderSize;
            actual.Width -= (RowMargin.Left + RowMargin.Right);
            actual.Height -= (RowMargin.Top + RowMargin.Bottom);
            var rec = new Rect(pos, actual);
            child.Arrange(rec);
        }
        return arrangeSize;
    }

    private Point GetPosition(Visual element)
    {
        var posTransForm = element.TransformToAncestor(this);
        var areaTransForm = posTransForm.Transform(new Point(0, 0));
        return areaTransForm;
    }
}

Verbrauch:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:GridWithMargins ShowGridLines="True">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
            <Rectangle Fill="Green" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
            <Rectangle Fill="Blue" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
        </local:GridWithMargins>
    </Grid>
</Window>

Ich bin überrascht, ich nicht sehen diese Lösung geschrieben noch.

aus dem Internet kommen, Frameworks wie Bootstrap eine negative Marge verwenden, um Zeilen zurück zu ziehen / Spalten.

Es könnte ein wenig umfangreich sein (wenn auch nicht so schlimm), es funktioniert und die Elemente gleichmäßig im Abstand und Größe.

In dem folgenden Beispiel I eine StackPanel Wurzel zu zeigen, verwenden, wie die 3-Tasten verwenden Ränder gleichmäßig beabstandet sind. Sie könnten auch andere Elemente verwenden, sondern nur die inneren x ändern:. Typ von Taste zu Ihrem Elemente

Die Idee ist einfach, ein Gitter an der Außenseite verwenden, um die Ränder der Elemente aus ihren Grenzen um die Hälfte der Höhe des inneren Gitters (mit negativen Rand) zu ziehen, verwenden, um den inneren Gitterraum gleichmäßig um die Elemente mit der Menge Sie wollen.

Update: Einiger Kommentar von einem Benutzer sagte, es nicht funktioniert, ist hier ein schnelles Video Demonstrieren: https://youtu.be/rPx2OdtSOYI

    <StackPanel>
        <Grid>
            <Grid.Resources>
                <Style TargetType="{x:Type Grid}">
                    <Setter Property="Margin" Value="-5 0"/>
                </Style>
            </Grid.Resources>

            <Grid>
                <Grid.Resources>
                    <Style TargetType="{x:Type Button}">
                        <Setter Property="Margin" Value="10 0"/>
                    </Style>
                </Grid.Resources>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Button Grid.Column="0" Content="Btn 1" />
                <Button Grid.Column="1" Content="Btn 2" />
                <Button Grid.Column="2" Content="Btn 3" />
            </Grid>

        </Grid>

        <TextBlock FontWeight="Bold" Margin="0 10">
            Test
        </TextBlock>
    </StackPanel>

Ich hatte ähnliches Problem vor kurzem in zwei Stützenraster, brauchte ich eine Marge auf Elemente in der rechten Spalte nur. Alle Elemente in den beiden Säulen waren vom Typ TextBlock-.

<Grid.Resources>
    <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource OurLabelStyle}">
        <Style.Triggers>
            <Trigger Property="Grid.Column" Value="1">
                <Setter Property="Margin" Value="20,0" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Grid.Resources>

Manchmal ist die einfache Methode die beste ist. Nur Pad Saiten mit Leerzeichen. Wenn es nur ein paar Textfelder usw. dies bei weitem der einfachste Methode ist.

Sie können auch einfach einfügen leere Spalten / Zeilen mit einer festen Größe. Extrem einfach und man kann leicht geändert werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top