[英]Is there a XAML equivalent to nameof?
我正在使用 DevExpress 的 WPF 树列表视图,我遇到了一个我认为与重命名用作项目源的对象的属性有关的更普遍的问题。 在树列表视图中,需要指定 ParentFieldName 和 KeyFieldName(用于确定树的结构)。 这些字段是字符串。
这导致了重构代码的问题。 例如,重命名我用作 ItemSource 的对象的属性将破坏树视图,因为 ParentFieldName 和 KeyFieldName 不再与属性名称同步。 我通过在我的视图模型“ParentFieldName”和“KeyFieldName”中创建属性来解决这个问题,它们使用nameof将属性名称呈现给视图。
这是控件的简化版本:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<ViewModel />
</UserControl.DataContext>
<dxg:TreeListControl AutoGenerateColumns="AddNew"
EnableSmartColumnsGeneration="True" ItemsSource="{Binding Results}"
SelectionMode="Row">
<dxg:TreeListControl.View>
<dxg:TreeListView
ParentFieldName="{Binding ParentIdFieldName}" KeyFieldName="{Binding NodeIdFieldName}"
ShowHorizontalLines="False" ShowVerticalLines="False"
ShowNodeImages="True"/>
</dxg:TreeListControl.View>
</dxg:TreeListControl>
</UserControl>
和视图模型:
using DevExpress.Mvvm;
public sealed class ViewModel : ViewModelBase
{
public string ParentIdFieldName => nameof(TreeNode.ParentId);
public string NodeIdFieldName => nameof(TreeNode.NodeId);
public ObservableCollection<TreeNode> Results
{
get => GetProperty(() => Results);
set => SetProperty(() => Results, value);
}
}
和树节点:
public sealed class TreeNode
{
public int ParentId {get; set;}
public int NodeId {get; set;}
}
我的解决方案效果很好,但我想知道是否有更好的方法来做到这一点。 例如,我可以在 XAML 中做一些与 nameof 调用等效的事情,而不是绑定到视图模型中的这个 ParentIdFieldName 和 NodeIdFieldName 吗?
我意识到这可以被描述为 DevExpress 控制的问题。 但是,我对我用来解决这个问题的方法是否可以改进感兴趣。 有没有一种方法可以直接在 XAML 中以更简单的方式执行此操作?
如果我提供的代码不能编译,我提前道歉。 为了提供一个例子,我已经相当多地减少了我正在使用的东西。
您可以创建自定义标记扩展。
例如:
[ContentProperty(nameof(Member))]
public class NameOfExtension : MarkupExtension
{
public Type Type { get; set; }
public string Member { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
throw new ArgumentNullException(nameof(serviceProvider));
if (Type == null || string.IsNullOrEmpty(Member) || Member.Contains("."))
throw new ArgumentException("Syntax for x:NameOf is Type={x:Type [className]} Member=[propertyName]");
var pinfo = Type.GetRuntimeProperties().FirstOrDefault(pi => pi.Name == Member);
var finfo = Type.GetRuntimeFields().FirstOrDefault(fi => fi.Name == Member);
if (pinfo == null && finfo == null)
throw new ArgumentException($"No property or field found for {Member} in {Type}");
return Member;
}
}
示例用法:
出于某种原因,我的设计师不能很好地使用 G.Sharada 的解决方案,尽管它在运行时效果很好。
我走了一条稍微不同的路线:
public class NameOfExtension : MarkupExtension
{
private readonly PropertyPath _propertyPath;
public NameOfExtension(Binding binding)
{
_propertyPath = binding.Path;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var indexOfLastVariableName = _propertyPath.Path.LastIndexOf('.');
return _propertyPath.Path.Substring(indexOfLastVariableName + 1);
}
}
这样我可以这样做:
<TextBlock Text="{local:NameOf {Binding Property1.Property2}}" />
这显然不是替代品,因为我们可能没有要绑定的实例化对象。 我想我可以有 2 个构造函数,一个接受绑定,另一个接受成员字符串。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.