有一些设计师喜欢改改改,界面的整体布局总是变更,如给 Grid 加一列删一行等,每次这样的更改的时候,都需要小心修改 Grid 里面的元素设置的行列序号。我认为在 Grid 简单的时候,当然大多数时候都应该让 Grid 不那么复杂,那么序号的可读性不错。如果 Grid 行列数量比较多,那么此时行列的序号的可读性将会降低,本文来告诉大家一个简单的方法,可以给 Grid 的行列添加名称绑定,让元素绑定到行列可以不使用序号,而是使用名称
在开始之前让大家看一下效果,我有一个 Grid 的定义如下
<Grid>
<Grid.RowDefinitions>
<RowDefinition local:GridExtensions.Name="R0" />
<RowDefinition local:GridExtensions.Name="R1" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition local:GridExtensions.Name="C1" />
</Grid.ColumnDefinitions>
</Grid>
可以看到我在 Grid 上都附加了属性 GridExtensions.Name 属性,这就是本文的核心,通过附加属性实现让 Grid 的行列名称绑定。给 Grid 的行列一个命名,就可以让元素绑定命名而不是序号
<TextBlock local:GridExtensions.RowName="R1" local:GridExtensions.ColumnName="C1" Text="12" />
添加一个 TextBlock 绑定行名为 R1
的行布局,绑定列是 C1
上,在 VisualStudio 设计器上可以看到效果如下
通过此方法就可以在给 Grid 加行列或删除行列的时候,减少修改一些元素的行列布局。因为元素绑定的是行列的名而不是序号,因此顺序修改的时候不会影响原有的界面代码
当前这个功能已合入到 HC 控件中,请通过 NuGet 安装 HandyControl 库
如不使用库,自己实现也简单,请看下面代码
public class GridExtensions
{
public static readonly DependencyProperty NameProperty = DependencyProperty.RegisterAttached(
"Name", typeof(string), typeof(GridExtensions), new PropertyMetadata(default(string)));
public static void SetName(DependencyObject element, string value)
{
element.SetValue(NameProperty, value);
}
public static string GetName(DependencyObject element)
{
return (string) element.GetValue(NameProperty);
}
public static readonly DependencyProperty RowNameProperty = DependencyProperty.RegisterAttached(
"RowName", typeof(string), typeof(GridExtensions),
new PropertyMetadata(default(string), RowName_PropertyChanged));
private static void RowName_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FrameworkElement frameworkElement)
{
if (e.NewValue is string rowName)
{
if (string.IsNullOrEmpty(rowName))
{
return;
}
if (frameworkElement.Parent is Grid grid)
{
for (var i = 0; i < grid.RowDefinitions.Count; i++)
{
var gridRowDefinition = grid.RowDefinitions[i];
var gridRowName = GetName(gridRowDefinition);
if (!string.IsNullOrEmpty(gridRowName) &&
gridRowName.Equals(rowName, StringComparison.Ordinal))
{
Grid.SetRow(frameworkElement, i);
return;
}
}
}
else
{
throw new ArgumentException("只有在Grid容器内才能设置 RowName 附加属性");
}
}
}
}
public static void SetRowName(DependencyObject element, string value)
{
element.SetValue(RowNameProperty, value);
}
public static string GetRowName(DependencyObject element)
{
return (string) element.GetValue(RowNameProperty);
}
public static readonly DependencyProperty ColumnNameProperty = DependencyProperty.RegisterAttached(
"ColumnName", typeof(string), typeof(GridExtensions),
new PropertyMetadata(default(string), ColumnName_PropertyChanged));
private static void ColumnName_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FrameworkElement frameworkElement)
{
if (e.NewValue is string columnName)
{
if (string.IsNullOrEmpty(columnName))
{
return;
}
if (frameworkElement.Parent is Grid grid)
{
for (var i = 0; i < grid.ColumnDefinitions.Count; i++)
{
var gridColumnDefinition = grid.ColumnDefinitions[i];
var gridColumnName = GetName(gridColumnDefinition);
if (!string.IsNullOrEmpty(gridColumnName) &&
gridColumnName.Equals(columnName, StringComparison.Ordinal))
{
Grid.SetColumn(frameworkElement, i);
return;
}
}
}
else
{
throw new ArgumentException("只有在Grid容器内才能设置 ColumnName 附加属性");
}
}
}
}
public static void SetColumnName(DependencyObject element, string value)
{
element.SetValue(ColumnNameProperty, value);
}
public static string GetColumnName(DependencyObject element)
{
return (string) element.GetValue(ColumnNameProperty);
}
}
本文所有代码放在 github 和 gitee 欢迎小伙伴访问
更多请看 Alias for Grid‘s RowDefinition and ColumnDefinition · Issue #2844 · dotnet/wpf
本文会经常更新,请阅读原文: https://blog.lindexi.com/post/WPF-%E7%BB%99-Grid-%E7%9A%84%E8%BE%85%E5%8A%A9%E6%96%B9%E6%B3%95-%E6%B7%BB%E5%8A%A0%E8%A1%8C%E5%88%97%E5%90%8D%E7%A7%B0%E7%BB%91%E5%AE%9A.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
如果你想持续阅读我的最新博客,请点击 RSS 订阅,推荐使用RSS Stalker订阅博客,或者收藏我的博客导航
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。
无盈利,不卖课,做纯粹的技术博客
以下是广告时间
推荐关注 Edi.Wang 的公众号
欢迎进入 Eleven 老师组建的 .NET 社区
以上广告全是友情推广,无盈利