Есть ли XAML эквивалент области сетки CSS? - PullRequest
0 голосов
/ 05 мая 2020

Имеет ли WPF XAML эквивалент CSS grid-area? То есть способ создать определение значений Row, Column, RowSpan, ColumnSpan, присвоить этому определению идентификатор, а затем использовать эти значения через идентификатор?

Я представляю что-то вроде:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="auto" />
    <RowDefinition />
    <RowDefinition Height="auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="auto" />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Grid.AreaDefinitions>
    <AreaDefinition Row="0" Column="0" ColumnSpan="2" Name="Header" />
    <AreaDefinition Row="1" Column="0" Name="Navigation" />
    <AreaDefinition Row="1" Column="1" Name="Main" />
    <AreaDefinition Row="2" Column="0" ColumnSpan="2" Name="Footer" />
  </Grid.AreaDefinitions>

  <TextBlock Grid.Area="Header" Text="Header" />
  <TextBlock Grid.Area="Navigation" Text="Navigation" />
  <TextBlock Grid.Area="Main" Text="Main" />
  <TextBlock Grid.Area="Footer" Text="Footer" />
</grid>

Ответы [ 2 ]

1 голос
/ 06 мая 2020

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

public class AreaDefinition : DependencyObject
{
    public int Row
    {
        get { return (int)GetValue(RowProperty); }
        set { SetValue(RowProperty, value); }
    }

    public static readonly DependencyProperty RowProperty =
        DependencyProperty.Register("Row", typeof(int), typeof(AreaDefinition), new PropertyMetadata(0));

    public int Column
    {
        get { return (int)GetValue(ColumnProperty); }
        set { SetValue(ColumnProperty, value); }
    }

    public static readonly DependencyProperty ColumnProperty =
        DependencyProperty.Register("Column", typeof(int), typeof(AreaDefinition), new PropertyMetadata(0));

    public int RowSpan
    {
        get { return (int)GetValue(RowSpanProperty); }
        set { SetValue(RowSpanProperty, value); }
    }

    public static readonly DependencyProperty RowSpanProperty =
        DependencyProperty.Register("RowSpan", typeof(int), typeof(AreaDefinition), new PropertyMetadata(1));

    public int ColumnSpan
    {
        get { return (int)GetValue(ColumnSpanProperty); }
        set { SetValue(ColumnSpanProperty, value); }
    }

    public static readonly DependencyProperty ColumnSpanProperty =
        DependencyProperty.Register("ColumnSpan", typeof(int), typeof(AreaDefinition), new PropertyMetadata(1));

    public string Name
    {
        get { return (string)GetValue(NameProperty); }
        set { SetValue(NameProperty, value); }
    }

    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(AreaDefinition), new PropertyMetadata(String.Empty));
}

Вам также понадобится класс для хранения их коллекции, во многом так же, как Grid.Columns является коллекцией типа ColumnDefinitionCollection:

public class AreaDefinitionCollection : Collection<AreaDefinition>
{
}

Наконец, вам понадобится класс для ваших прикрепленных свойств, который я назову GridHelper. Этот класс должен будет предоставить две точки доступа, одну для ваших гридов (GridHelper.AreaDefinitions), а другую для дочерних гридов (GridHelper.Area). Обработчик изменений для GridHelper.AreaProperty - это то место, где происходят все маги c, он просто обновляет связанные Grid AP всякий раз, когда изменяется Area:

public static class GridHelper
{
    public static AreaDefinitionCollection GetAreaDefinitions(DependencyObject obj)
    {
        return (AreaDefinitionCollection)obj.GetValue(AreaDefinitionsProperty);
    }

    public static void SetAreaDefinitions(DependencyObject obj, AreaDefinitionCollection value)
    {
        obj.SetValue(AreaDefinitionsProperty, value);
    }

    public static readonly DependencyProperty AreaDefinitionsProperty =
        DependencyProperty.RegisterAttached("AreaDefinitions", typeof(AreaDefinitionCollection), typeof(Grid), new PropertyMetadata(new AreaDefinitionCollection()));

    public static string GetArea(DependencyObject obj)
    {
        return (string)obj.GetValue(AreaProperty);
    }

    public static void SetArea(DependencyObject obj, string value)
    {
        obj.SetValue(AreaProperty, value);
    }

    public static readonly DependencyProperty AreaProperty =
        DependencyProperty.RegisterAttached("Area", typeof(string), typeof(UIElement), new PropertyMetadata(String.Empty, OnAreaChanged));

    private static void OnAreaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UIElement child = d as UIElement;
        if (child == null)
            return;
        Grid grid = VisualTreeHelper.GetParent(child) as Grid;
        if (grid == null)
            return;
        AreaDefinitionCollection areas = GetAreaDefinitions(grid);
        if (areas == null)
            return;

        // the performance of this bit could be improved by giving AreaDefinitionCollection a hash table implementation, oh well.               
        var areaDefinition = areas.FirstOrDefault(a => a.Name == e.NewValue.ToString());
        if (areaDefinition == null)
            return;

        // update the grid elements
        Grid.SetRow(child, areaDefinition.Row);
        Grid.SetRowSpan(child, areaDefinition.RowSpan);
        Grid.SetColumn(child, areaDefinition.Column);
        Grid.SetColumnSpan(child, areaDefinition.ColumnSpan);
    }
}

С его помощью вы можете реализовать функциональность, которую вы После, с небольшими изменениями:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <g:GridHelper.AreaDefinitions>
        <g:AreaDefinition Row="0" Column="0" ColumnSpan="2" Name="Header" />
        <g:AreaDefinition Row="1" Column="0" Name="Navigation" />
        <g:AreaDefinition Row="1" Column="1" Name="Main" />
        <g:AreaDefinition Row="2" Column="0" ColumnSpan="2" Name="Footer" />
    </g:GridHelper.AreaDefinitions>

    <TextBlock g:GridHelper.Area="Header" Text="Header" />
    <TextBlock g:GridHelper.Area="Navigation" Text="Navigation" />
    <TextBlock g:GridHelper.Area="Main" Text="Main" />
    <TextBlock g:GridHelper.Area="Footer" Text="Footer" />
</Grid>

Если вам не нравится префикс пространства имен g:, вы можете избавиться от него, как указано в этой статье , добавив в файл AssemblyInfo.cs следующую строку:

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "YourGridHelperNamespace")]
0 голосов
/ 06 мая 2020

Ничего подобного нет, но есть функция, которую можно использовать аналогичным образом. Стили - это «удобный способ применения набора значений свойств к нескольким элементам». Если у вас есть несколько элементов, у которых все должны иметь одинаковые свойства, установленные на одно и то же значение, вы можете определить Style, например:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.Resources>
        <Style x:Key="AStyle" TargetType="TextBlock">
            <Setter Property="Grid.Row" Value="1"/>
            <Setter Property="Grid.Column" Value="1"/>
        </Style>
    </Grid.Resources>

    <TextBlock Style="{StaticResource AStyle}" Text="Header" />
</Grid>

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...