WPF: Сетка с полем столбец /строка /отступы

Можно ли легко указать поле и /или отступ для строк или столбцов в сетке WPF?

Конечно, я мог бы добавить дополнительные столбцы для разметки, но это похоже на работу с отступами /полями (это даст намного более простой XAML). Кто-то извлек из стандартной Grid эту функциональность?

113 голосов | спросил Brad Leach 24 AM00000040000002931 2009, 04:28:29

13 ответов


0

RowDefinition и ColumnDefinition имеют тип ContentElement, а Margin строго Свойство FrameworkElement. Итак, на ваш вопрос, «это легко возможно» , ответ является наиболее определенным «нет». И нет, я не видел ни одного макета панелей, демонстрирующих такую ​​функциональность.

Вы можете добавить дополнительные строки или столбцы, как вы предложили. Но вы также можете установить поля для самого элемента Grid или всего, что будет внутри Grid, так что пока это ваш лучший обходной путь.

ответил Charlie 24 AM00000080000005931 2009, 08:23:59
0

Используйте элемент управления 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>


Источник:

ответил samad 14 FriEurope/Moscow2012-12-14T10:16:23+04:00Europe/Moscow12bEurope/MoscowFri, 14 Dec 2012 10:16:23 +0400 2012, 10:16:23
0

Вы можете использовать что-то вроде этого:

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

Или, если вам не нужны привязки шаблона:

<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 14 PMpThu, 14 Apr 2011 13:10:54 +040010Thursday 2011, 13:10:54
0

Думаю, я бы добавил свое собственное решение, потому что никто еще не упомянул об этом. Вместо того, чтобы создавать UserControl на основе Grid, вы можете настроить элементы управления, содержащиеся в grid, с помощью объявления стиля. Позаботится о добавлении отступов /полей ко всем элементам без необходимости определения для каждого, что является громоздким и трудоемким. Например, если ваша сетка содержит только TextBlocks, вы можете сделать это:

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

Что похоже на «заполнение ячеек».

ответил James M 16 FebruaryEurope/MoscowbTue, 16 Feb 2016 03:33:14 +0300000000amTue, 16 Feb 2016 03:33:14 +030016 2016, 03:33:14
0

Недавно я столкнулся с этой проблемой при разработке программного обеспечения, и мне пришло в голову спросить ПОЧЕМУ? Почему они сделали это ... ответ был прямо передо мной. Строка данных является объектом, поэтому, если мы сохраняем ориентацию объекта, то дизайн отдельной строки должен быть отделен (предположим, что вам понадобится повторно использовать отображение строки в будущем). Поэтому я начал использовать панели стека с привязкой к данным и настраиваемые элементы управления для большинства дисплеев данных. Списки появлялись время от времени, но в основном сетка использовалась только для первичной организации страницы (заголовок, область меню, область содержимого, другие области). Ваши пользовательские объекты могут легко управлять любыми требованиями к расстоянию для каждой строки в панели стека или сетке (одна ячейка сетки может содержать весь объект строки. Это также дает дополнительное преимущество правильной реакции на изменения ориентации, развертывания /свертывания и т. Д.

<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, если вы используете привязку данных ... мое личное любимое преимущество этого подхода.

ответил Matt Meikle 14 FebruaryEurope/MoscowbSat, 14 Feb 2015 19:21:00 +0300000000pmSat, 14 Feb 2015 19:21:00 +030015 2015, 19:21:00
0

Я сделал это прямо сейчас с одной из моих решеток.

  • Сначала примените одинаковое поле для каждого элемента в сетке. Вы можете делать это вручную, используя стили или что угодно. Допустим, вы хотите горизонтальный интервал 6px и вертикальный интервал 2px. Затем вы добавляете поля «3px 1px» к каждому дочернему элементу сетки.
  • Затем удалите поля, созданные вокруг сетки (если вы хотите выровнять границы элементов управления внутри сетки в том же положении сетки). Сделайте это, установив поле "-3px -1px" для сетки. Таким образом, другие элементы управления вне сетки будут выровнены с крайними элементами управления внутри сетки.
ответил isierra 25 J000000Wednesday12 2012, 15:58:43
0

Одной из возможностей может быть добавление строк и столбцов фиксированной ширины, которые будут выполнять функцию требуемого отступа /поля.

Вы также можете подумать, что вы ограничены размером вашего контейнера и что сетка станет такой же большой, как содержащий элемент или его указанная ширина и высота. Вы можете просто использовать столбцы и строки без заданной ширины или высоты. Таким образом, они по умолчанию равномерно разбивают общее пространство в сетке. Тогда это будет просто вопрос центрирования ваших элементов по вертикали и горизонтали в вашей сетке.

Другой метод может заключаться в том, чтобы обернуть все элементы сетки в фиксированный с одной строкой & сетка столбцов, которая имеет фиксированный размер и поле. Что ваша сетка содержит фиксированные поля ширины /высоты, которые содержат ваши фактические элементы.

ответил Adam Lenda 23 MarpmWed, 23 Mar 2011 20:36:14 +03002011-03-23T20:36:14+03:0008 2011, 20:36:14
0

в uwp (версия Windows10FallCreatorsUpdate и выше)

<Grid RowSpacing="3" ColumnSpacing="3">
ответил Kursat Turkay 5 TueEurope/Moscow2017-12-05T23:10:30+03:00Europe/Moscow12bEurope/MoscowTue, 05 Dec 2017 23:10:30 +0300 2017, 23:10:30
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>
ответил Paul Baxter 21 FebruaryEurope/MoscowbTue, 21 Feb 2017 23:30:47 +0300000000pmTue, 21 Feb 2017 23:30:47 +030017 2017, 23:30:47
0

Хотя вы не можете добавить поле или отступ в Grid, вы можете использовать что-то вроде фрейма (или аналогичного контейнера), к которому вы можете применить его.

Таким образом (если вы показываете или скрываете элемент управления при нажатии кнопки, скажем), вам не нужно добавлять поля для каждого элемента управления, который может с ним взаимодействовать.

Думайте об этом как об изоляции групп элементов управления в единицах, а затем применении стиля к этим единицам.

ответил ed13 4 PM00000090000000831 2015, 21:42:08
0

Я удивлен, что еще не видел этого решения.

Исходя из Интернета, фреймворки, такие как начальная загрузка, будут использовать отрицательное поле для возврата строк /столбцов.

Это может быть немного многословно (хотя и не так уж плохо), оно работает, и элементы равномерно распределены и измерены.

В приведенном ниже примере я использую корень StackPanel, чтобы продемонстрировать, как 3 кнопки равномерно распределены с помощью полей. Вы можете использовать другие элементы, просто измените внутренний x: Type с кнопки на ваш элемент.

Идея проста: использовать сетку снаружи, чтобы вытащить поля элементов за их пределы на половину внутренней сетки (используя отрицательные поля), использовать внутреннюю сетку, чтобы равномерно распределить элементы по количеству ты хочешь.

Update: В некоторых комментариях пользователя говорится, что это не работает, вот краткое видео, демонстрирующее: 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>
ответил AntonB 16 PM00000090000001731 2018, 21:20:17
0

Это не очень сложно. Не могу сказать, насколько сложно было в 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)
    {
        PanelExt.SetChildMargin(MainGrid, null);
    }
    private void BigMarginClick(object sender, RoutedEventArgs e)
    {
        PanelExt.SetChildMargin(MainGrid, new Thickness(20));
    }
}

 введите описание изображения здесь

 введите описание изображения здесь

 введите описание изображения здесь

ответил Ed Plunkett 26 +03002018-10-26T23:27:55+03:00312018bEurope/MoscowFri, 26 Oct 2018 23:27:55 +0300 2018, 23:27:55
0

Иногда простой метод самый лучший. Просто дополните свои строки пробелами. Если это всего лишь несколько текстовых полей и т. Д., То это, безусловно, самый простой метод.

Вы также можете просто вставить пустые столбцы /строки с фиксированным размером. Чрезвычайно просто, и вы можете легко изменить его.

ответил rolls 5 FebruaryEurope/MoscowbSun, 05 Feb 2017 04:56:19 +0300000000amSun, 05 Feb 2017 04:56:19 +030017 2017, 04:56:19

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132