如何使用RowDefinition名称设置Grid Row?

时间:2013-08-31 02:50:19

标签: wpf grid

我正在使用RowDefinitionsColumnDefinition组织我的网格,但是当我想在实际任何RowDefinition之前添加新的RowDefinition时,我需要重新组织网格。所有控件的行

我看到RowDefinitionColumnDefinitionName属性,所以我认为可以定义带有RowDefinition名称的Grid.Row吗?如果可能,怎么做

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Name="RowDictTitle" Height="27"/>
        <RowDefinition Name="RowSearchWord" Height="27"/>
        <RowDefinition/>
        <RowDefinition Height="50"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>

    <!--Row 1-->
    <TextBlock Text="Word:" VerticalAlignment="Center" Margin="10,0,0,0" Grid.Row="1"/>
    <TextBox Name="Search" Grid.ColumnSpan="2" Margin="50,2,10,2"/>

    <!--Row 2-->
    <ListBox Name="Words" Grid.Row="2" Margin="10"/>
</Grid>

我想在下方制作

<TextBlock Text="Word" Grid.Row="RowSearchWord"/>

3 个答案:

答案 0 :(得分:6)

免责声明:这个答案是this meta post提到的约束中的一种自我广告。它宣传了一个免费的开源项目,我(在撰写本文时)并没有赚到任何钱。唯一的好处就是知道我写这篇描述的控件的时间没有浪费,如果它有助于这个SO问题的未来访问者。

我有完全相同的想法。这就是为什么,不久前,我写了一个使用命名列和行的自定义网格类。

我把它放在麻省理工学院许可下的Codeplex上:Name-Based Grid project

使用该控件,您可以按如下方式重写Xaml源代码:

<nbg:NameBasedGrid>
    <nbg:NameBasedGrid.RowDefinitions>
        <nbg:ColumnOrRow Name="RowDictTitle" Height="27"/>
        <nbg:ColumnOrRow Name="RowSearchWord" Height="27"/>
        <nbg:ColumnOrRow Name="List"/>
        <nbg:ColumnOrRow Height="50"/>
    </nbg:NameBasedGrid.RowDefinitions>
    <nbg:NameBasedGrid.ColumnDefinitions>
        <nbg:ColumnOrRow Width="1*" Name="Left"/>
        <nbg:ColumnOrRow Width="2*" Name="Right"/>
    </nbg:NameBasedGrid.ColumnDefinitions>

    <!--Row 1-->
    <TextBlock Text="Word:" VerticalAlignment="Center" Margin="10,0,0,0" nbg:NameBasedGrid.Column="Left" nbg:NameBasedGrid.Row="RowSearchWord"/>
    <TextBox Name="Search" nbg:NameBasedGrid.Column="Left" nbg:NameBasedGrid.Row="RowDictTitle" nbg:NameBasedGrid.ExtendToColumn="Right" Margin="50,2,10,2"/>

    <!--Row 2-->
    <ListBox Name="Words" nbg:NameBasedGrid.Column="Left" nbg:NameBasedGrid.Row="List" Margin="10"/>
</nbg:NameBasedGrid>

优势:您可以按名称引用列和行(包括列和行跨度!) - 不再计算列或行,在布局时不再更新列或行跨度变化。

缺点:您需要明确说明所有列和行的名称,因为NameBasedGrid中根本不支持数字引用。

答案 1 :(得分:1)

不错的想法,但由于Grid.Row附加属性是一个整数,这是不可能的。

请参阅http://msdn.microsoft.com/en-us/library/system.windows.controls.grid.row.aspx

但是,可以创建一个获取网格行名称的辅助对象,找到行对象并返回其行索引。

答案 2 :(得分:0)

我一直在找同样的事情。无法找到我正在寻找的东西所以我想出了我自己的解决方案使用附加属性。

我创建了一个专门的网格,其中包含RowName和ColumnName的附加属性。 (在本例中我只实现了RowName)

using System.Windows;
using System.Windows.Controls;

namespace GridNamedRows.CustomControl
{
    public class MyGrid: Grid
    {
        public static readonly DependencyProperty RowNameProperty =
                DependencyProperty.RegisterAttached(
                      "RowName",
                      typeof(string),
                      typeof(MyGrid),
                      new FrameworkPropertyMetadata(
                              "",
                              FrameworkPropertyMetadataOptions.AffectsParentArrange,
                              new PropertyChangedCallback(RowNameChanged)),
                      new ValidateValueCallback(IsStringNotNull));

        private static bool IsStringNotNull(object value)
        {
            return (value as string) != null;
        }

        private static void RowNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue == null) 
            { 
                return; 
            }
            if (!(d is UIElement)) return;
            Grid parent = ((FrameworkElement)d).Parent as Grid;
            if (parent == null) return;
            //Find rowname
            for (int i = 0; i < parent.RowDefinitions.Count; i++)
            {
                if (parent.RowDefinitions[i].Name == e.NewValue.ToString())
                {
                    Grid.SetRow((UIElement)d, i);
                    break;
                }
            }
        }

        public static string GetRowName(DependencyObject target)
        {
            return (string)target.GetValue(RowNameProperty);
        }

        public static void SetRowName(DependencyObject target, string value)
        {
            target.SetValue(RowNameProperty, value);
        }
    }
}

它可以像这样在xaml中使用。

<Window xmlns:CustomControl="clr-namespace:GridNamedRows.CustomControl"  x:Class="GridNamedRows.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <CustomControl:MyGrid>
        <Grid.RowDefinitions>
            <RowDefinition Name="firstRow"/>
            <RowDefinition Name="secondRow"/>
            <RowDefinition Name="thirdRow"/>
        </Grid.RowDefinitions>
        <TextBox Text="one" CustomControl:MyGrid.RowName="secondRow"/>
        <TextBox Text="two" Grid.Row="2"/>
        <TextBox Text="three" CustomControl:MyGrid.RowName="firstRow"/>
    </CustomControl:MyGrid>
</Window>

它在设计器中无法正确显示,但在运行时有效。