WPF: Kotak dengan margin kolom / baris / padding?

142

Apakah mudah untuk menentukan margin dan / atau padding untuk baris atau kolom di WPF Grid?

Saya tentu saja dapat menambahkan kolom ekstra untuk mengatur ruang, tetapi ini sepertinya pekerjaan untuk padding / margin (ini akan memberikan XAML yang jauh lebih sederhana). Apakah seseorang berasal dari Grid standar untuk menambahkan fungsi ini?

Brad Leach
sumber
4
Salah satu contoh yang berguna Anda dapat menemukan di sini: codeproject.com/Articles/107468/WPF-Padded-Grid
peter70
3
Agak bingung bahwa ini bukan bagian dari fitur dasar Grid ...
uceumern
Sampai hari ini, ditunjukkan oleh 10 tahun jawaban, kenyataannya adalah tidak mungkin dengan mudah, dan yang terbaik untuk dilakukan (untuk menghindari pekerjaan rawan kesalahan tambahan setiap kali sel digunakan) adalah dengan mendapatkan Grid (seperti yang disarankan sebelumnya oleh @ peter70 ) untuk menambahkan properti ketergantungan bantalan sel yang sesuai yang akan mengontrol properti Margin dari anak sel. Ini bukan tugas yang panjang, lalu Anda memiliki kontrol yang dapat digunakan kembali. Komentar samping ... Grid benar-benar kontrol yang dirancang dengan buruk.
menit

Jawaban:

6

Anda dapat menulis GridWithMarginkelas Anda sendiri , mewarisi dari Grid, dan mengganti ArrangeOverridemetode untuk menerapkan margin

Thomas Levesque
sumber
42
Saya tidak mengerti mengapa orang mengacungkan jempol karena itu jauh dari semudah yang Anda pikirkan / gambarkan di sini. Coba lakukan 30 menit dan Anda akan segera melihat bahwa jawaban Anda tidak dapat diterapkan. Juga pikirkan tentang rentang baris dan kolom
Eric Ouellet
91

RowDefinitiondan ColumnDefinitionbertipe ContentElement, dan Marginbenar-benar merupakan FrameworkElementproperti. Jadi untuk pertanyaan Anda, "apakah itu mungkin mudah" , jawabannya pasti tidak. Dan tidak, saya belum melihat panel tata letak yang mendemonstrasikan fungsi semacam ini.

Anda dapat menambahkan baris atau kolom tambahan seperti yang Anda sarankan. Tapi Anda juga bisa mengatur margin pada Gridelemen itu sendiri, atau apapun yang akan masuk ke dalam a Grid, jadi itu solusi terbaik Anda untuk saat ini.

Charlie
sumber
OP tidak mencoba menyetel margin pada RowDefinition atau ColumnDefinition. Dia mencoba untuk menetapkan margin pada anak-anak visual dari grid, yang berasal dari FrameworkElement.
15ee8f99-57ff-4f92-890c-b56153
61

Gunakan Borderkontrol di luar kontrol sel dan tentukan padding untuk itu:

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


Sumber:

samad
sumber
2
@RichardEverett Periksa Jalan Kembali Mesin: tautan diperbarui dalam jawaban.
CJBS
Saya paling suka jawaban ini. Ini memberikan solusi untuk pertanyaan awal dan langsung ke depan. Terima kasih!
Tobias
Ini mudah dan praktis
aggsol
19

Anda bisa menggunakan sesuatu seperti ini:

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

Atau jika Anda tidak membutuhkan 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>
JayGee
sumber
28
Terima kasih JayGee, namun solusi ini untuk DataGrid - bukan kontrol Grid standar.
Brad Leach
Mengklik ruang padding tidak lagi memilih baris tersebut.
jor
9

Pikir saya akan menambahkan solusi saya sendiri karena belum ada yang menyebutkan ini. Alih-alih mendesain UserControl berdasarkan Grid, Anda dapat menargetkan kontrol yang terdapat dalam grid dengan deklarasi gaya. Menjaga penambahan padding / margin ke semua elemen tanpa harus menentukan masing-masing, yang rumit dan padat karya. Misalnya, jika Grid Anda tidak berisi apa pun selain TextBlocks, Anda dapat melakukan ini:

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

Yang mirip dengan "bantalan sel".

James M
sumber
apakah ini menetes? misalnya jika Anda memiliki stackpanel dalam baris kisi, apakah anak textblock stackpanel mewarisi properti ini?
Maslow
Tidak yakin apakah itu menetes melewati anak-anak langsung, tetapi Anda dapat mengetahuinya dengan tes sederhana.
James M
2
@Maslow Jawabannya mutlak 'Ya,' tapi kata-kata Anda sedikit menyesatkan. Tidak ada "pewarisan" dari Marginproperti yang terjadi, bahwa setiap Styledi ResourceDictionaryakan berlaku untuk setiap elemennya di TargetTypemana saja dalam seluruh cakupan elemen pemilik kamus itu. Jadi Styleyang menetes, bukan propertinya.
Glenn Slayden
4

di uwp (versi Windows10FallCreatorsUpdate dan yang lebih baru)

<Grid RowSpacing="3" ColumnSpacing="3">
alex
sumber
Ini juga berlaku dengan Xamarin.Forms.
James M
UWP! = WPF ... Mengapa komentar harus sepanjang 15 karakter (pertanyaan retoris).
Richard Moore
3

Saya mengalami masalah ini saat mengembangkan beberapa perangkat lunak baru-baru ini dan terpikir oleh saya untuk bertanya MENGAPA? Mengapa mereka melakukan ini ... jawabannya ada di depan saya. Baris data adalah sebuah objek, jadi jika kita mempertahankan orientasi objek, maka desain untuk baris tertentu harus dipisahkan (misalkan Anda perlu menggunakan kembali tampilan baris nanti di masa mendatang). Jadi saya mulai menggunakan panel tumpukan data dan kontrol kustom untuk sebagian besar tampilan data. Daftar terkadang muncul tetapi sebagian besar kisi telah digunakan hanya untuk organisasi halaman utama (Header, Area Menu, Area Konten, Area Lain). Objek khusus Anda dapat dengan mudah mengelola persyaratan jarak apa pun untuk setiap baris dalam panel tumpukan atau kisi (satu sel kisi dapat berisi seluruh objek baris. Ini juga memiliki manfaat tambahan untuk bereaksi dengan benar terhadap perubahan orientasi,

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

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

atau

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

Kontrol Kustom Anda juga akan mewarisi DataContext jika Anda menggunakan data binding ... manfaat favorit pribadi saya dari pendekatan ini.

Matt Meikle
sumber
Apa yang Anda coba lakukan di sini adalah membuat versi kasar dari ListViewkontrol WPF dalam GridViewmode, tetapi tanpa ketentuan untuk membuat semua "RowObjects" berbagi lebar kolom yang sama. Pada kenyataannya, itu tidak lagi ada hubungannya dengan Grid.
Glenn Slayden
3

Diedit:

Untuk memberikan margin ke kontrol apa pun Anda bisa membungkus kontrol dengan batas seperti ini

<!--...-->
    <Border Padding="10">
            <AnyControl>
<!--...-->
Juan Pablo
sumber
Masalah OP bukanlah memiliki margin di sekitar grid, tetapi margin di sekitar sel grid (atau seperti yang sebenarnya ditanyakan di sekitar baris dan kolom, kemudian bertentangan dengan " menambahkan kolom / baris ekstra persis seperti yang saya coba hindari ") .
menit
2

Saya melakukannya sekarang dengan salah satu grid saya.

  • Pertama, terapkan margin yang sama ke setiap elemen di dalam kisi. Anda bisa melakukan ini secara manual, menggunakan gaya, atau apapun yang Anda suka. Katakanlah Anda menginginkan jarak horizontal 6px dan jarak vertikal 2px. Kemudian Anda menambahkan margin "3px 1px" untuk setiap anak grid.
  • Kemudian hapus margin yang dibuat di sekitar kisi (jika Anda ingin meratakan batas kontrol di dalam kisi ke posisi kisi yang sama). Lakukan pengaturan ini dengan margin "-3px -1px" ke grid. Dengan begitu, kontrol lain di luar kisi akan disejajarkan dengan kontrol terluar di dalam kisi.
isierra
sumber
Menerapkan margin yang sama ke setiap elemen di dalam kisi tampaknya menjadi cara termudah.
Envil
1

Salah satu kemungkinannya adalah menambahkan baris dan kolom dengan lebar tetap untuk bertindak sebagai bantalan / margin yang Anda cari.

Anda juga dapat mempertimbangkan bahwa Anda dibatasi oleh ukuran penampung Anda, dan bahwa kisi akan menjadi sebesar elemen penampung atau lebar dan tinggi yang ditentukan. Anda cukup menggunakan kolom dan baris tanpa set lebar atau tinggi. Dengan cara itu mereka secara default membagi ruang total dalam grid secara merata. Maka itu hanya akan menjadi mater pemusatan elemen Anda secara vertikal dan horizontal di dalam grid Anda.

Metode lain mungkin untuk membungkus semua elemen grid tetap dengan grid baris & kolom tunggal yang memiliki ukuran dan margin tetap. Bahwa grid Anda berisi kotak lebar / tinggi tetap yang berisi elemen Anda yang sebenarnya.

Adam Lenda
sumber
1
Terima kasih Adam, namun menambahkan kolom / baris ekstra persis seperti yang saya coba hindari. Saya hanya ingin mengurangi markup saya dan dapat menentukan margin atau padding akan membantu dalam hal ini.
Brad Leach
Anda hanya perlu menentukan kolom dan baris ekstra, tidak menambahkan mark up untuk mereka. Misalnya, jika Anda ingin menambahkan lebar N antar kolom untuk 3 kolom, Anda akan memiliki 5 definisi kolom. Yang pertama akan menjadi lebar otomatis, dan selanjutnya diperbaiki, lalu otomatis, lalu diperbaiki, lalu otomatis. Kemudian hanya tetapkan kolom 1, 3 dan 5 ke elemen konten yang sebenarnya. Saya mengerti maksud Anda tentang markup kolom tambahan, tetapi kecuali Anda memiliki ratusan elemen, itu tampak sepele bagi saya. panggilan Anda sekalipun. Selain itu, sudahkah Anda mencoba menggunakan panel tumpukan panel tumpukan dengan margin yang ditetapkan?
Adam Lenda
Untuk kasus saya, menambahkan kolom "pemisah / margin" adalah yang paling bersih dan termudah. Terima kasih!
jchristof
1

Saya mengalami masalah serupa baru-baru ini di kisi dua kolom, saya hanya membutuhkan margin pada elemen di kolom kanan. Semua elemen di kedua kolom berjenis 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>
Miloš Auder
sumber
0

Meskipun Anda tidak dapat menambahkan margin atau padding ke Grid, Anda dapat menggunakan sesuatu seperti Frame (atau wadah serupa), yang dapat Anda terapkan.

Dengan begitu (jika Anda menampilkan atau menyembunyikan kontrol pada kata klik tombol), Anda tidak perlu menambahkan margin pada setiap kontrol yang mungkin berinteraksi dengannya.

Anggap saja sebagai mengisolasi grup kontrol ke dalam beberapa unit, lalu menerapkan gaya ke unit tersebut.

ed13
sumber
0

Seperti yang dinyatakan sebelumnya, buat kelas GridWithMargins. Berikut adalah contoh kode kerja saya

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

Pemakaian:

<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>
Paul Baxter
sumber
1
Melempar System.ArgumentException: 'Width must non-negative.' aktual.Width - = Math.Min (aktual.Width, RowMargin.Left + RowMargin.Right); aktual.Height - = Math.Min (aktual.Height, RowMargin.Top + RowMargin.Bottom);
Jamie Mellway
Dengan perbaikan Jamie, itu berjalan, tetapi masih tidak melakukan apa yang seharusnya. Dengan tinggi baris dan lebar kolom diatur ke Otomatis, ini melakukan hal yang salah dengan cara yang berbeda.
15ee8f99-57ff-4f92-890c-b56153
0

Saya terkejut saya belum melihat solusi ini diposting.

Berasal dari web, kerangka kerja seperti bootstrap akan menggunakan margin negatif untuk menarik kembali baris / kolom.

Ini mungkin sedikit bertele-tele (meskipun tidak terlalu buruk), itu berfungsi dan elemen-elemennya diberi jarak dan ukuran yang merata.

Dalam contoh di bawah ini saya menggunakan StackPanelroot untuk mendemonstrasikan bagaimana 3 tombol ditempatkan secara merata menggunakan margin. Anda bisa menggunakan elemen lain, cukup ubah inner x: Type from button ke elemen Anda.

Idenya sederhana, gunakan kisi di luar untuk menarik margin elemen keluar dari batasnya dengan setengah jumlah kisi dalam (menggunakan margin negatif), gunakan kisi dalam untuk meratakan jarak elemen dengan jumlah yang Anda inginkan.

Pembaruan: Beberapa komentar dari pengguna mengatakan itu tidak berfungsi, berikut adalah video singkat yang menunjukkan: https://youtu.be/rPx2OdtSOYI

masukkan deskripsi gambar di sini

    <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>
AntonB
sumber
1
Kesalahan saya - Saya tidak memperhatikan gaya Tombol implisit. Saya teralihkan oleh sedikit tentang margin negatif.
15ee8f99-57ff-4f92-890c-b56153
-7

Terkadang metode sederhana adalah yang terbaik. Cukup isi string Anda dengan spasi. Jika hanya beberapa kotak teks dll, ini adalah metode yang paling sederhana.

Anda juga dapat memasukkan kolom / baris kosong dengan ukuran tetap. Sangat sederhana dan Anda dapat dengan mudah mengubahnya.

Gulungan
sumber
Mungkin karena itu bukan metode yang sangat bagus. Menggunakan spasi mungkin merupakan "jalan keluar yang mudah", tetapi sebenarnya ini lebih merupakan peretasan. Ini tidak tepat, mungkin (dan mungkin akan) dirender secara berbeda dan tidak dapat diandalkan pada monitor dengan penskalaan berbeda dan Anda tidak memiliki kendali atas jumlah ruang yang Anda buat. Memasukkan kolom / baris kosong akan mengacaukan grid Anda ...
Tandai