lux*_*xun 10 c# wpf xaml devexpress-wpf
我正在使用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>
Run Code Online (Sandbox Code Playgroud)
和viewmodel:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
和树节点:
public sealed class TreeNode
{
public int ParentId {get; set;}
public int NodeId {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
我的解决方案运行良好,但我想知道是否有更好的方法来做到这一点.例如,我可以在XAML中执行哪些操作等同于调用名称,而不是在视图模型中绑定到此ParentIdFieldName和NodeIdFieldName?
我意识到这可以被描述为DevExpress控制的问题.但是我对我以前用来解决这个问题的方法是否有所改进感兴趣.有没有办法可以直接在XAML中以更简单的方式做到这一点?
如果我提供的代码没有编译,我会提前道歉.我已经相当大地减少了我正在使用的东西,以提供一个例子.
Sha*_*raj 14
您可以创建自定义标记扩展.
例如:
[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;
}
}
Run Code Online (Sandbox Code Playgroud)
样品用法:
出于某种原因,我的设计师不能很好地使用 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);
}
}
Run Code Online (Sandbox Code Playgroud)
这样我可以这样做:
<TextBlock Text="{local:NameOf {Binding Property1.Property2}}" />
Run Code Online (Sandbox Code Playgroud)
这显然不是替代品,因为我们可能没有要绑定的实例化对象。我想我可以有 2 个构造函数,一个接受绑定,另一个接受成员字符串。