如何创建静态可绑定属性说明对象
本文关键字:绑定 属性 说明 对象 静态 何创建 创建 | 更新日期: 2023-09-27 18:35:21
为了确保 WPF 中的绑定面向现有属性,我使用了静态属性-名称-属性。
现在,我不想将有关我的属性的更多信息封装到静态属性描述对象(名称、类型、Id 等)中,但不必为名称提供一个路径可绑定属性,而不必为所有其他信息提供一个属性。
问题是 WPF 抱怨属性的类型错误,不是字符串,而是属性信息。
我试图以某种方式绕过这个限制。例如,我尝试将我的 PropertyInfo 隐式转换为字符串,覆盖 ToString 并将 TypeConverter 从 PropertyInfo 添加到字符串和从 PropertyInformation 添加到字符串。什么都没用。
而且我也不能直接绑定到 Name-属性。
<TextBlock Text="{Binding Path={x:Static l:Test.TitleProperty}}" />
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TypeDescriptor.AddAttributes(typeof(string),
new TypeConverterAttribute(typeof(StringFromPropertyConverter)));
DataContext = new Test { Title = "hello" };
}
}
public class Test
{
public static readonly PropertyInfo TitleProperty =
new PropertyInfo { Name = "Title" };
public string Title { get; set; }
}
[TypeConverter(typeof(PropertyToStringConverter))]
public class PropertyInfo
{
public string Name { get; set; }
public static implicit operator string(PropertyInfo p) { return p.Name; }
public override string ToString()
{
return Name;
}
}
public class PropertyToStringConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context,
Type destinationType)
{
if (destinationType == typeof(string)) return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value,
Type destinationType)
{
return ((PropertyInfo)value).Name;
}
}
public class StringFromPropertyConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
if (sourceType == typeof(PropertyInfo)) return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value)
{
return ((PropertyInfo)value).Name;
}
}
有什么建议吗?
需要有一个 TypeConverter 才能将 PropertyInfo 转换为 System.Windows.PropertyPath,而不是字符串。此外,您可能需要考虑重用 .NETs System.Reflection.PropertyInfo 用于此目的。
我以前见过这种方法,其主要原因是避免属性更改通知中的"神奇字符串"。因此,您也可以查看如何使用System.Linq.Expressions完成获取PropertyInfo的过程,如下所示:
public static class ReflectionHelper
{
public static PropertyInfo GetPropertyInfo<T>(Expression<Func<T, object>> getter)
{
return (PropertyInfo)((MemberExpression)getter.Body).Member;
}
}
并像这样使用它:
public class Test
{
public static readonly PropertyInfo TitleProperty = ReflectionHelper.GetPropertyInfo<Test>(x => x.Title);
public string Title { get; set; }
}
编辑:新答案
是的,你是对的。即使您定义TypeConverter以将PropertyInfo转换为System.Windows.PropertyPath,它也不起作用。我认为这是因为ConverterType属性应该放在System.Windows.PropertyPath类上。但由于它是一个你不拥有的类,你不能在它上面放置属性。使用类型描述符添加属性将不起作用,因为 XAML 不使用类型描述符基础结构。
您可以使用标记扩展完成转换。下面是一个完整的代码(它使用 System.Reflection 命名空间中的 PropertyInfo):
反射助手.cs
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace WpfApplication
{
public static class ReflectionHelper
{
public static PropertyInfo GetPropertyInfo<T>(Expression<Func<T, object>> getter)
{
return (PropertyInfo)((MemberExpression)getter.Body).Member;
}
}
}
测试.cs
using System.Reflection;
namespace WpfApplication
{
public class Test
{
public static readonly PropertyInfo TitleProperty = ReflectionHelper.GetPropertyInfo<Test>(x => x.Title);
public string Title { get; set; }
}
}
属性信息路径扩展.cs
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;
namespace WpfApplication
{
public class PropertyInfoPathExtension : MarkupExtension
{
private readonly PropertyInfo propertyInfo;
public PropertyInfoPathExtension(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
throw new ArgumentNullException("propertyInfo");
this.propertyInfo = propertyInfo;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return new PropertyPath(propertyInfo);
}
}
}
MainWindow.xaml
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Test Title="hello"/>
</Window.DataContext>
<TextBlock Text="{Binding Path={local:PropertyInfoPath {x:Static local:Test.TitleProperty}}}"/>
</Window>
那么,你的语法正确吗?
不久前,我不得不绑定到一个静态类。绑定到静态的语法不同。我在这里记录了它。
WPF 绑定到静态类的属性
但本质上语法是这样的:
{x:Static s:MyStaticClass.StaticValue1}