繁体   English   中英

如何创建可重用的WPF网格布局

[英]How to create reusable WPF grid layout

我有一个带有标签控件和页数的窗口 - 标签项。 每个选项卡项具有相同的网格布局 - 6行和4列。 现在,每个选项卡项都包含具有行和列定义的网格,因此几乎一半的XAML是网格的定义。

如何在一个位置定义此网格并在我的应用程序中重用该定义? 模板? 用户控制?

除了6x4,我还有两个重复的网格尺寸:8x4和6x6。

编辑:
忘记提及:网格中的控件对于每个选项卡都是不同的。 我只想在某些资源中定义一次网格,以便我可以在不同的标签页上重复使用它们。 现在XAML看起来像这样:

    <TabControl>
        <TabItem Header="Property">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition /> 
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <!-- some controls here -->
            </Grid>
        </TabItem>
        <TabItem Header="Style">
            <Grid >
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />                        
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />                        
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <!-- some controls here -->
            </Grid>
        </TabItem>

       ... and this repeats for several more tab items

    </TabControl>

对于表单上的每个选项卡项,将重复此网格定义。 令我很恼火的是,XAML的一半是网格定义。

有没有办法在一个地方定义这个网格,然后重用该定义?

我认为最好的方法是使用ItemsControlItemsPanelTemplate ,因为你需要一个容器来存放多个项目:

<FrameworkElement.Resources>
    <Style x:Key="GridItemsStyle"
           TargetType="ItemsControl">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</FrameworkElement.Resources>
<TabControl>
    <TabItem>
        <ItemsControl Style="{StaticResource GridItemsStyle}">
            <TextBlock Grid.Row="1" Text="R1" />
            <TextBlock Grid.Column="1"
                       Text="C1" />
        </ItemsControl>
    </TabItem>
    <TabItem>
        <ItemsControl Style="{StaticResource GridItemsStyle}">
            <TextBlock Grid.Row="2"
                       Text="R2" />
            <TextBlock Grid.Column="2"
                       Text="C2" />
        </ItemsControl>
    </TabItem>
</TabControl>

或者你可以继承Grid ...

using System.Windows.Controls;
public class AlreadySetupGrid:Grid
{
    public AlreadySetupGrid()
    {
        for (int i = 0; i < 4; i++)
        {
            ColumnDefinitions.Add(new ColumnDefinition());
        }
        for (int i = 0; i < 6; i++)
        {
            RowDefinitions.Add(new RowDefinition());
        }
    }
}

然后使用它而不是普通的Grid。

我有类似的东西。 问题是你怎么不把你的数据放入网格?

当你一遍又一遍地使用相同的布局时,我猜你正在为每个单元格添加类似的东西。

我为每个Tab创建了一个自定义ItemsControl来放入Data,然后为显示网格的ItemsControl创建了一个样式。

<Style x:Key="GridItemsStyle"
       TargetType="ItemsControl">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>

                    <ContentPresenter Content="{Binding ElementName=Cell00}" Grid.Row="0" Grid.Column="0" />

                    <ContentPresenter Content="{Binding ElementName=Cell01}" Grid.Row="0" Grid.Column="1" />

                    <ContentPresenter Content="{Binding ElementName=Cell10}" Grid.Row="1" Grid.Column="0" />


                    <!-- ...And so on -->

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

在窗口

<TabControl>
<TabItem>
    <local:tab1 Style="{StaticResource GridItemsStyle}" />
</TabItem>
<TabItem>
    <local:tab2 Style="{StaticResource GridItemsStyle}" />
</TabItem>

然后每个CustomControl继承自ItemsControl

<ItemsControl x:Class="your_app.tab1"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="clr-namespace:your_app">

 <ContentControl x:Name="Cell00">

     <!-- Some stuff here -->

 </ContentControl>
 <ContentControl x:Name="Cell01">

     <!-- Some stuff here -->

 </ContentControl>
 <ContentControl x:Name="Cell10">

     <!-- Some stuff here -->

 </ContentControl>

这与Aelij正在做的非常类似,除了我设置ContentPresenter并将其绑定到一个名称并将itemsControl放入它自己的东西(你可以混合两个解决方案)。

它仍然是很多代码,但我会说你自己保存所有的行和列定义,你也只需要在一个地方更改网格,如果你必须稍微修改它。

通常会为进入选项卡的数据编写DataTemplate。 DataTemplate将包含Grid。

如何在一个位置定义此网格并在我的应用程序中重用该定义? 模板? 用户控制?

如果我是你,我会创建一个UserControl或自定义Control与重复的代码,然后只需消耗从当前的代码控制。

另一种方法是使用DataTemplateControlTemplate

TabItem创建ControlTemplate也很有用。

你可以这样做,但它需要一些工作:

1)创建一个集合和附加属性,如下所示:

public class ColumnDefinitions : Collection<ColumnDefinition>
{
    public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached(
        "Source",
        typeof(ColumnDefinitions),
        typeof(ColumnDefinitions),
        new PropertyMetadata(
            default(ColumnDefinitions), 
            OnColumnDefinitionsChanged));

    public static void SetSource(Grid element, ColumnDefinitions value)
    {
        element.SetValue(SourceProperty, value);
    }

    [AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(Grid))]
    public static ColumnDefinitions GetSource(Grid element)
    {
        return (ColumnDefinitions)element.GetValue(SourceProperty);
    }

    private static void OnColumnDefinitionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var grid = (Grid)d;
        grid.ColumnDefinitions.Clear();
        var columnDefinitions = (ColumnDefinitions)e.NewValue;
        if (columnDefinitions == null)
        {
            return;
        }

        foreach (var columnDefinition in columnDefinitions)
        {
            grid.ColumnDefinitions.Add(columnDefinition);
        }
    }
}

2)然后你可以使用它作为资源和网格样式,如下所示:注意必须使用x:Shared="False" 如果没有相同的定义将被添加到导致WPF抛出的许多网格中。

<UserControl.Resources>
    <demo:ColumnDefinitions x:Key="SomeColumnDefinitions" x:Shared="False">
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </demo:ColumnDefinitions>

    <Style x:Key="SomeGridStyle" TargetType="{x:Type Grid}">
        <Setter Property="demo:ColumnDefinitions.Source" Value="{StaticResource SomeColumnDefinitions}"></Setter>
    </Style>
</UserControl.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition  Height="5"/>
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid Style="{StaticResource SomeGridStyle}">
        <Rectangle Grid.Row="0"
                   Grid.Column="0"
                   Width="120"
                   Fill="Blue" />
        <Rectangle Grid.Row="0"
                   Grid.Column="1"
                   Fill="Yellow" />
    </Grid>

    <Grid Grid.Row="2" demo:ColumnDefinitions.Source="{StaticResource SomeColumnDefinitions}">
        <Rectangle Grid.Row="0"
                   Grid.Column="0"
                   Width="120"
                   Fill="Blue" />
        <Rectangle Grid.Row="0"
                   Grid.Column="1"
                   Fill="Yellow" />
    </Grid>
</Grid>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM