WPF:列/行マージン/パディングがあるグリッド?


137

WPFグリッドの行または列のマージンやパディングを簡単に指定できますか?

もちろん、スペースを空けるために余分な列を追加することもできますが、これはパディング/マージンの仕事のようです(XAMLが大幅に簡素化されます)。この機能を追加するために誰かが標準グリッドから派生しましたか?


4
ここで見つけることができる1つの便利な例:codeproject.com/Articles/107468/WPF-Padded-Grid
peter70

2
これはグリッドのベースライン機能の一部ではないことに
少し戸惑いました

今日のところ、10年の回答で示されているように、真実は簡単には不可能であり、(セルが使用されるたびにエラーが発生しやすい追加の作業を回避する)最善の方法は、グリッド導出することです(@ peter70によって以前に提案されたとおり)。 )セルの子のマージンプロパティを制御する適切なセルパディング依存プロパティを追加します。これは長い作業ではなく、再利用可能なコントロールを手に入れました。余談...グリッドは実際には不十分に設計されたコントロールです。

回答:


10

GridWithMarginから継承した独自のクラスを作成しGridArrangeOverrideメソッドをオーバーライドしてマージンを適用できます


31
ここで考える/説明するほど簡単ではないので、なぜ人々があなたを高く評価するのか理解できません。30分やってみると、答えが当てはまらないことがすぐにわかります。行と列のスパンについても考えてみましょう
Eric Ouellet、

89

RowDefinitionおよびColumnDefinitionタイプContentElementであり、Margin厳密にFrameworkElementプロパティです。したがって、あなたの質問に対して、「それは簡単に可能ですか」という答えが最も明確です。いいえ、この種の機能を示すレイアウトパネルは見たことがありません。

必要に応じて、行や列を追加できます。ただし、Grid要素自体、または内に入るものにマージンを設定することもできるGridので、これが今のところ最善の回避策です。


OPはRowDefinitionまたはColumnDefinitionにマージンを設定しようとしません。彼は、FrameworkElementから派生したグリッドの視覚的な子にマージンを設定しようとしています。
15ee8f99-57ff-4f92-890c-b56153

57

使用するBorder電池制御外の制御をし、そのためにパディングを定義します。

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


ソース:


2
@RichardEverett Check the Way Back Machine:リンクが回答で更新されました。
CJBS 2017年

私はこの答えが一番好きです。それは元の質問に対する解決策を提供し、それは簡単です。ありがとう!
トビアス

これは簡単で実用的です
aggsol '10

19

あなたはこのようなものを使うことができます:

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

または、TemplateBindingsが必要ない場合:

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

28
JayGeeに感謝しますが、このソリューションはDataGrid用であり、標準のGridコントロール用ではありません。
ブラッドリーチ

パディングスペースをクリックしても、行は選択されなくなります。
JOR

9

まだ誰もこれについて言及していないので、私は自分の解決策を追加すると思いました。グリッドに基づいてユーザーコントロールを設計する代わりに、スタイル宣言を使用してグリッドに含まれるコントロールをターゲットにすることができます。各要素を定義する必要なく、すべての要素にパディング/マージンを追加するので、面倒で手間がかかります。たとえば、グリッドにTextBlockしか含まれていない場合は、次のようにできます。

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

これは「セルパディング」に相当します。


これは滴り落ちますか?たとえば、グリッド行にスタックパネルがある場合、スタックパネルのテキストブロックの子はこのプロパティを継承しますか?
マズロー2017年

それがすぐ近くの子供たちをだましているかどうかはわかりませんが、簡単なテストで見つけることができます。
James M

2
@Maslow答えは完全に「はい」ですが、あなたの言い回しは少し誤解を招きます。Margin進行中のプロパティの「継承」はありません。それStyleは、aのいずれかが、そのディクショナリの所有者要素の全スコープ内のあらゆる場所のResourceDictionaryすべての要素に適用されるということです。つまり、プロパティではなく、トリクルです。TargetTypeStyle
Glenn Slayden 2017

8

これはそれほど難しいことではありません。質問があった2009年はどれほど難しかったかはわかりませんが、当時はそうでした。

このソリューションを使用するときにグリッドの子に直接マージンを明示的に設定した場合、そのマージンはデザイナーには表示されますが、実行時には表示されないことに注意してください。

このプロパティは、Grid、StackPanel、WrapPanel、UniformGrid、またはPanelの他の子孫に適用できます。それは直接の子供に影響を与えます。子どもたちは自分のコンテンツのレイアウトを管理したいと思うでしょう。

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);
            }
        }
    }
}

デモ:

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)
    {
        //  In real life, if we wanted to change PanelExt.ChildMargin at runtime, we 
        //  would prefer to bind it to something, probably a dependency property of 
        //  the view. But this will do for a demonstration. 
        PanelExt.SetChildMargin(MainGrid, null);
    }
    private void BigMarginClick(object sender, RoutedEventArgs e)
    {
        PanelExt.SetChildMargin(MainGrid, new Thickness(20));
    }
}

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください


あなたの答えが反対票を投じられた理由を知っていますか?OPの問題に対する有効な解決策のようです
システムの

4
@システム私は誰かが何かに腹を立てたと思います。大したことではない。しかし、私が見逃したバグがあるかもしれません。それが起こります。
15ee8f99-57ff-4f92-890c-b56153

それが必要と「原因DWなっbuildたりrun、ライブプレビューの前に表示することができますか?良いシンプルなもの。1アップ。
ニャー猫2012年

3

最近いくつかのソフトウェアを開発しているときにこの問題に遭遇しましたが、なぜ私に質問したのですか?なぜ彼らはこれをしたのですか...答えは私の目の前にありました。データの行はオブジェクトであるため、オブジェクトの方向を維持する場合、特定の行のデザインを分離する必要があります(将来、行の表示を再利用する必要があると仮定します)。そのため、ほとんどのデータ表示にデータバインドされたスタックパネルとカスタムコントロールを使い始めました。リストは時々表示されますが、ほとんどのグリッドはプライマリページの編成(ヘッダー、メニューエリア、コンテンツエリア、その他のエリア)にのみ使用されています。カスタムオブジェクトは、スタックパネルまたはグリッド内の各行の間隔要件を簡単に管理できます(単一のグリッドセルに行オブジェクト全体を含めることができます。これには、方向の変化に適切に反応するという追加の利点もあります。

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

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

または

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

データバインディングを使用している場合、カスタムコントロールもDataContextを継承します...このアプローチの私の個人的なお気に入りの利点。


ここで試みたのは、WPF ListViewコントロールの粗バージョンをGridViewモードで作成することですが、すべての「RowObjects」が同じ列幅を共有するようにするための規定はありません。実際には、グリッドとはほとんど関係がありません。
Glenn Slayden 2017


3

編集:

コントロールにマージンを与えるために、このようにコントロールをボーダーでラップすることができます

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

OPの問題は、グリッドの周りにマージンがあることではなく、グリッドセルの周りにマージンがあることです(または実際に行と列の周りに尋ねられたように、後で「追加の列/行を追加することは、まさに私が避けようとしていた」コメント矛盾しています)。 。

2

私はグリッドの1つで今それを行いました。

  • 最初に、グリッド内のすべての要素に同じマージンを適用します。スタイルを使ったり、好きな方法でこれを手動で行うことができます。6pxの水平方向の間隔と2pxの垂直方向の間隔が必要だとしましょう。次に、グリッドのすべての子に「3px 1px」のマージンを追加します。
  • 次に、グリッドの周囲に作成されたマージンを削除します(グリッド内のコントロールの境界をグリッドの同じ位置に揃えたい場合)。グリッドに対して「-3px -1px」のマージンを設定してください。このようにして、グリッドの外側にある他のコントロールは、グリッドの内側にある最も外側のコントロールと揃えられます。

グリッド内のすべての要素に同じマージンを適用するのが最も簡単な方法のようです。
邪悪な

1

1つの可能性は、固定幅の行と列を追加して、探しているパディング/マージンとして機能させることです。

コンテナーのサイズによって制約されていること、およびグリッドが含まれている要素またはその指定された幅と高さと同じ大きさになることも考慮する必要があります。幅や高さを設定せずに、列と行を使用できます。これにより、デフォルトでグリッド内のスペース全体が均等に分割されます。そうすれば、要素をグリッド内で垂直方向と水平方向に中央揃えにするだけのことになります。

別の方法として、すべてのグリッド要素を、サイズとマージンが固定された単一の行と列のグリッドで固定する方法があります。グリッドに実際の要素を含む固定幅/高さボックスが含まれていること。


1
Adamに感謝します。ただし、追加の列/行を追加することは、まさに私が避けようとしていたことです。私は単にマークアップを減らしたいので、マージンまたはパディングを指定できるようにすると、これが役立ちます。
ブラッドリーチ

追加の列と行を定義するだけで、マークアップを追加する必要はありません。たとえば、3列の列の間にNの幅を追加する場合は、5つの列を定義します。最初は自動幅、次は固定、次に自動、次に固定、次に自動になります。次に、列1、3、および5のみを実際のコンテンツ要素に割り当てます。追加の列マークアップに関するあなたの要点はわかりますが、何百もの要素がない限り、それは私にとっては些細なことのようです。あなたの呼び出しも。また、マージンを設定したスタックパネルのスタックパネルを使用してみましたか?
Adam Lenda、

私の場合、「スプリッター/マージン」列を追加することは、最もクリーンで簡単でした。ありがとう!
jchristof

1

最近、2列グリッドで同様の問題が発生しました。右列の要素のみにマージンが必要でした。両方の列のすべての要素のタイプは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>

0

グリッドにマージンやパディングを追加することはできませんが、適用できるフレーム(または同様のコンテナー)のようなものを使用できます。

このように(ボタンをクリックしてコントロールを表示または非表示にする場合)、操作するすべてのコントロールにマージンを追加する必要はありません。

コントロールのグループをユニットに分離し、それらのユニットにスタイルを適用すると考えてください。


0

前に述べたように、GridWithMarginsクラスを作成します。これが私の作業コードの例です

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

使用法:

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

1
System.ArgumentExceptionをスローします:「幅は負でない必要があります。」actual.Width-= Math.Min(actual.Width、RowMargin.Left + RowMargin.Right); actual.Height-= Math.Min(actual.Height、RowMargin.Top + RowMargin.Bottom);
ジェイミーメルウェイ2017

ジェイミーの修正により、それは実行されますが、それでもそれがすべきことをしません。行の高さと列の幅を自動に設定すると、別の方法で間違った動作をします。
15ee8f99-57ff-4f92-890c-b56153

0

このソリューションがまだ投稿されていないことに驚いています。

ウェブから来ると、ブートストラップのようなフレームワークは負のマージンを使用して行/列を引き戻します。

それは少し冗長かもしれませんが(それほど悪くはありません)、機能し、要素は等間隔でサイズ設定されます。

以下の例では、StackPanelルートを使用して、マージンを使用して3つのボタンがどのように等間隔に配置されるかを示します。他の要素を使用することもできます。内側のx:Typeをボタンから要素に変更するだけです。

アイデアは単純です。外側のグリッドを使用して、要素のマージンを内側のグリッドの半分の量だけ(外側のマージンを使用して)境界から引き出し、内側のグリッドを使用して、必要な量の要素を均等に配置します。

更新: ユーザーからのコメントの一部は機能しないとのことです。ここでは、デモンストレーションの簡単なビデオを示しています: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>

1
私の間違い-暗黙のButtonスタイルに気づきませんでした。私はマイナスのマージンについて少し気を取られました。
15ee8f99-57ff-4f92-890c-b56153

-6

シンプルな方法が最善の場合もあります。文字列にスペースを埋め込むだけです。数個のテキストボックスなどの場合、これは非常に簡単な方法です。

固定サイズの空白の列/行を挿入することもできます。非常にシンプルで、簡単に変更できます。


おそらくそれはあまり良い方法ではありません。スペースを使用することは「簡単な方法」かもしれませんが、実際にはハックのようなものです。正確ではありません。異なるスケーリングのモニターでは、レンダリングが異なる可能性があり、おそらく信頼性が低く、作成するスペースの正確な量を制御できません。空の列/行を挿入すると、グリッドが台無しになります...
Mark
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.