WPF: Sütun / satır kenar boşluğu / dolgu ile ızgara?


137

WPF Izgarasındaki satırlar veya sütunlar için bir kenar boşluğu ve / veya dolgu belirtmek kolayca mümkün müdür?

Tabii ki alanlara ekstra sütunlar ekleyebilirim, ancak bu, dolgu / kenar boşlukları için bir iş gibi görünüyor ( çok daha basit XAML verecek ). Birisi bu işlevi eklemek için standart Grid'den türetilmiş mi?


4
Burada yararlı bir örnek bulabilirsiniz: codeproject.com/Articles/107468/WPF-Padded-Grid
peter70

2
Kinda bu Grid'in temel özellikleri bir parçası değil şaşkın ...
uceumern

Bugün itibariyle, 10 yıllık cevaplarla gösterilen gerçek, kolay bir şekilde mümkün değildir ve yapılması en iyisidir (her hücre kullanıldığında ek hataya eğilimli çalışmayı önlemek için) Izgarayı türetmektir (daha önce @ peter70 tarafından önerildiği gibi) ), hücre çocuğun Margin özelliğini kontrol edecek uygun hücre dolgusu bağımlılık özelliğini eklemek için. Bu uzun bir görev değil ve sonra tekrar kullanılabilir bir kontrolünüz var. Yan yorum ... Izgara gerçekten kötü tasarlanmış bir kontrol.
dakika

Yanıtlar:


10

Kendi GridWithMarginsınıfınızı yazabilir , devralınan ve kenar boşluklarını uygulama yöntemini Gridgeçersiz kılabilirsinizArrangeOverride


32
Halkların size neden başparmak verdiğini anlamıyorum, çünkü burada düşündüğünüz / tarif ettiğiniz kadar kolay olmaktan uzak. Sadece 30 dakika yapmaya çalışın ve cevabınızın uygulanamaz olduğunu hemen göreceksiniz. Ayrıca satır ve sütun aralığı düşünün
Eric Ouellet

89

RowDefinitionve ColumnDefinitiontür ContentElementve Marginkesinlikle bir FrameworkElementözelliktir. Yani sorunuza, "kolayca mümkün mü" cevabı en kesin hayır. Ve hayır, bu tür bir işlevsellik gösteren herhangi bir yerleşim paneli görmedim.

Önerdiğiniz gibi fazladan satır veya sütun ekleyebilirsiniz. Ancak, bir Gridöğenin kendisinde veya a içine girecek herhangi bir şeyde kenar boşlukları ayarlayabilirsiniz Grid, bu nedenle şimdilik en iyi geçici çözüm budur.


OP, RowDefinition veya ColumnDefinition üzerinde bir kenar boşluğu ayarlamaya çalışmıyor. FrameworkElement'ten türetilen ızgaranın görsel çocuklarında bir kenar boşluğu koymaya çalışıyor.
15ee8f99-57ff-4f92-890c-b56153

58

BorderHücre kontrolünün dışında bir kontrol kullanın ve bunun için dolguyu tanımlayın:

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


Kaynak:


2
@RichardEverett Geri Dönüş Makinesi'ni kontrol edin: bağlantı cevap olarak güncellendi.
CJBS

Bu cevabı en çok seviyorum. Orijinal soruya bir çözüm sağlar ve doğrudan ileri. Teşekkürler!
Tobias

Bu kolay ve pratik
aggsol

19

Bunun gibi bir şey kullanabilirsiniz:

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

Veya TemplateBindings'e ihtiyacınız yoksa:

<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
Teşekkürler JayGee, ancak bu çözüm standart Izgara kontrolü için değil DataGrid içindir.
Brad Leach

Dolgu alanını tıklamak artık satırı seçmiyor.
jor

9

Kendi çözümümü ekleyeceğimi düşündüm çünkü henüz kimse bundan bahsetmedi. Izgaraya dayalı bir UserControl tasarlamak yerine, ızgarada bulunan kontrolleri bir stil bildirimi ile hedefleyebilirsiniz. Her öğeye tanımlamak zorunda kalmadan tüm öğelere dolgu / kenar boşluğu eklemeye özen gösterir, bu da hantal ve emek yoğundur.Örneğin, Izgara'nız TextBlocks'tan başka bir şey içermiyorsa, bunu yapabilirsiniz:

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

Hangi "hücre dolgu" eşdeğeri gibi.


bu damlıyor mu? örneğin, bir ızgara satırında bir yığın paneliniz varsa, yığın panelinin metin bloğu alt öğeleri bu özelliği miras alır?
Maslow

Yakın çocukları geçip geçmediğinden emin değilsiniz, ancak basit bir testle öğrenebilirsiniz.
James M

2
@Maslow Cevap kesinlikle 'Evet', ancak ifadeniz biraz yanıltıcı. Hayır “miras” nin var Marginmülkiyet oluyor, herhangi bir işte Stylebir de ResourceDictionaryonun her eleman için geçerli olacak TargetTypeher yerde tüm kapsamındaki bu Sözlüğün sahibi elemanının. Yani Stylemülk değil, bu damlama.
Glenn Slayden

8

Bu çok zor değil. 2009'da soru sorulduğunda ne kadar zor olduğunu söyleyemem, ama o zaman öyleydi.

Bu çözümü kullanırken doğrudan bir ızgara alt öğesinde bir kenar boşluğu belirlerseniz, bu kenar boşluğunun tasarımcıda görüneceğini, ancak çalışma zamanında görünmeyeceğini unutmayın.

Bu özellik Izgara, StackPanel, WrapPanel, UniformGrid veya Panel'in herhangi bir alt nesnesine uygulanabilir. Acil çocukları etkiler. Çocukların kendi içeriklerinin düzenini yönetmek isteyecekleri varsayılmaktadır.

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

resim açıklamasını buraya girin

resim açıklamasını buraya girin

resim açıklamasını buraya girin


Cevabınızın neden reddedildiğini biliyor musunuz? OP'ın soruna bir çalışma çözüm gibi görünüyor
thesystem

4
@thesystem Sanırım biri bir şeyden rahatsız oldu. Önemli bir şey değil. Ama belki içinde özlediğim bir hata var. Olur.
15ee8f99-57ff-4f92-890c-b56153

dw var çünkü canlı önizleme görüntülenebilmesi için bir buildveya runönce gerekir? İyi ve basit olan. 1 Yukarı.
Miyav Kedi 2012

3

Son zamanlarda bazı yazılımlar geliştirirken bu problemle karşılaştım ve NEDEN sormalıyım? Bunu neden yaptılar ... cevap tam önümdeydi. Bir veri satırı bir nesnedir, bu nedenle nesne yönünü korursak, belirli bir satırın tasarımı ayrılmalıdır (satır görüntüsünü ileride daha sonra yeniden kullanmanız gerektiğini varsayalım). Bu yüzden çoğu veri ekranı için databound yığın panelleri ve özel kontroller kullanmaya başladım. Listeler ara sıra ortaya çıkmıştır, ancak çoğunlukla ızgara yalnızca birincil sayfa organizasyonu (Başlık, Menü Alanı, İçerik Alanı, Diğer Alanlar) için kullanılmıştır. Özel nesneleriniz, yığın panelindeki veya ızgaradaki her satır için herhangi bir boşluk gereksinimini kolayca yönetebilir (tek bir ızgara hücresi tüm satır nesnesini içerebilir.Ayrıca yönelimdeki değişikliklere düzgün tepki verme avantajı vardır,

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

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

veya

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

Veri bağlamanızı kullanıyorsanız, bu yaklaşımın en sevdiğim yararı ... Özel denetimleriniz DataContext'i de devralır.


Burada yapmaya çalıştığınız şey ListView, GridViewmodda WPF denetiminin ham bir sürümünü oluşturmaktır , ancak tüm “RowObjects” öğesinin aynı sütun genişliğini paylaşması için herhangi bir hüküm yoktur. Gerçekte, artık bir Izgara ile ilgisi yoktur.
Glenn Slayden

3

uwp içinde (Windows10FallCreatorsUpdate sürümü ve üstü)

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

Bu, için de geçerlidir Xamarin.Forms.
James M

3

Düzenlendi:

Herhangi bir kontrole marj vermek için kontrolü şu kenarlıkla sarabilirsiniz

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

OP sorunu ızgara etrafında bir kenar boşluğu değil, ızgara hücreleri etrafında bir kenar boşluğu (veya aslında satırlar ve sütunlar etrafında sorulduğu gibi, daha sonra " ekstra sütun / satır eklemek tam olarak kaçınmaya çalışıyorum " yorum ile çelişkili ) .
dakika

2

Şimdiyse ızgaralarımdan biriyle yaptım.

  • Önce aynı kenar boşluğunu ızgara içindeki her öğeye uygulayın. Bu mannualy, stilleri kullanarak veya ne istersen yapabilirsiniz. Diyelim ki 6 piksel yatay boşluk ve 2 piksel dikey boşluk istiyorsunuz. Sonra kılavuzun her alt "3px 1px" kenar boşlukları ekleyin.
  • Ardından ızgara çevresinde oluşturulan kenar boşluklarını kaldırın (ızgara içindeki denetimlerin sınırlarını ızgarayla aynı konuma hizalamak istiyorsanız). Bu ayarı ızgaraya "-3px -1px" kenar boşluğu yapın. Bu şekilde, ızgara dışındaki diğer kontroller, ızgara içindeki en dıştaki kontrollerle hizalanacaktır.

Izgara içindeki her öğeye aynı marjı uygulamak en kolay yol gibi görünüyor.
Envil

1

Bir olasılık, aradığınız dolgu / kenar boşluğu gibi davranmak için sabit genişlikli satırlar ve sütunlar eklemek olabilir.

Ayrıca, konteynerinizin boyutu ile kısıtlandığınızı ve bir ızgaranın, taşıyıcı eleman veya belirtilen genişlik ve yüksekliği kadar büyük olacağını düşünebilirsiniz. Genişlik veya yükseklik ayarlanmamış sütunları ve satırları kullanabilirsiniz. Bu şekilde, ızgara içindeki toplam alanı eşit olarak bölmek için varsayılan olarak kullanılırlar. O zaman sadece öğelerinizi ızgara içinde dikey ve yatay olarak merkezleyen bir malzeme olacaktır.

Başka bir yöntem, tüm ızgara öğelerini, sabit bir boyut ve kenar boşluğuna sahip tek bir satır ve sütun ızgarasıyla sabitlemek olabilir. Izgarada, gerçek öğelerinizi içeren sabit genişlik / yükseklik kutuları bulunur.


1
Teşekkürler Adam, ancak ekstra sütun / satır eklemek tam olarak kaçınmaya çalışıyorum şeydir. Sadece işaretlememi azaltmak istiyorum ve bir kenar boşluğu veya dolgu belirtmek bu konuda yardımcı olacaktır.
Brad Leach

Yalnızca fazladan sütunları ve satırları tanımlamanız gerekir, bunlar için işaret eklemeyin. Örneğin, 3 sütun için sütunlar arasına N genişliği eklemek isterseniz, 5 sütun tanımınız olur. Birincisi otomatik genişlik, diğeri sabit, sonra otomatik, sonra sabit, sonra otomatik olacaktır. Ardından, gerçek içerik öğelerine yalnızca 1, 3 ve 5 sütunlarını atayın. Ekstra sütun işaretlemesi hakkındaki görüşünüzü görüyorum, ancak yüzlerce öğeniz yoksa, bu benim için önemsiz görünüyor. senin çağrın olsa. Ayrıca, kenar boşlukları ayarlanmış yığın panelleri yığın panelini kullanmayı denediniz mi?
Adam Lenda

Benim durumum için bir "splitter / margin" sütun eklemek çok temiz ve kolay oldu. Teşekkürler!
jchristof

1

Son zamanlarda iki sütun ızgarasında benzer bir sorun yaşadım, sadece sağ sütundaki öğeler üzerinde bir marja ihtiyacım vardı. Her iki sütundaki tüm öğeler TextBlock türündeydi.

<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

Bir Izgaraya kenar boşluğu veya dolgu ekleyemeseniz de, uygulayabileceğiniz bir Çerçeve (veya benzer bir kap) gibi bir şey kullanabilirsiniz.

Bu şekilde (bir düğmeyi tıklatarak denetimi gösterir veya gizlerseniz), onunla etkileşime girebilecek her denetime kenar boşluğu eklemeniz gerekmez.

Bunu, kontrol gruplarını birimlere ayırmak, sonra bu birimlere stil uygulamak olarak düşünün.


0

Daha önce belirtildiği gibi bir GridWithMargins sınıfı oluşturun. İşte benim çalışma kodu örneği

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

Kullanımı:

<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
Atar System.ArgumentException: 'Genişlik negatif olmamalıdır.' actual.Width - = Math.Min (actual.Width, RowMargin.Left + RowMargin.Right); actual.Height - = Math.Min (actual.Height, RowMargin.Top + RowMargin.Bottom);
Jamie Mellway

Jamie'nin düzeltmesiyle çalışır, ama yine de olması gereken şeyi yapmaz. Satır yüksekliği ve sütun genişliği Otomatik olarak ayarlandığında, yanlış olanı farklı bir şekilde yapar.
15ee8f99-57ff-4f92-890c-b56153

0

Bu çözümü henüz görmedim şaşırdım.

Web'den gelirken, bootstrap gibi çerçeveler satırları / sütunları geri çekmek için negatif bir kenar boşluğu kullanır.

Biraz ayrıntılı olabilir (o kadar da kötü olmasa da), işe yarıyor ve öğeler eşit aralıklı ve boyutlandırılmış.

Aşağıdaki örnekte bir StackPanel , 3 düğmenin kenar boşluklarını kullanarak eşit aralıklarla yerleştirildiğini göstermek kök kullanıyorum. Diğer öğeleri kullanabilirsiniz, sadece iç x: Tür düğmesini düğmenizden öğenize değiştirin.

Fikir basit, öğelerin kenar boşluklarını iç ızgara miktarının yarısına kadar (negatif kenar boşlukları kullanarak) çekmek için dışarıdan bir ızgara kullanın, elemanları istediğiniz miktarda eşit aralıklarla yerleştirmek için iç ızgarayı kullanın.

Güncelleme: Bir kullanıcıdan bazı yorumlar işe yaramadığını söyledi, işte hızlı bir video: https://youtu.be/rPx2OdtSOYI

resim açıklamasını buraya girin

    <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
Benim hatam - Örtülü Düğme stilini fark etmedim. Negatif marjlarla ilgili dikkatim dağılmıştı.
15ee8f99-57ff-4f92-890c-b56153

-6

Bazen basit yöntem en iyisidir. Dizelerinizi boşluklarla doldurun. Sadece birkaç metin kutusu vb ise, bu en basit yöntemdir.

Ayrıca, sabit boyutlu boş sütunlar / satırlar da ekleyebilirsiniz. Son derece basit ve kolayca değiştirebilirsiniz.


Muhtemelen çok iyi bir yöntem olmadığı için. Boşlukları kullanmak "kolay çıkış yolu" olabilir, ama aslında daha çok bir saldırı. Kesin değil, farklı ölçeklendirmeye sahip monitörlerde farklı ve güvenilir olmayan bir şekilde görüntülenebilir (ve muhtemelen) ve yarattığınız alanın tam miktarı üzerinde kontrolünüz yoktur. Boş sütunlar / satırlar eklemek ızgaranızı
Mark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.