簡體   English   中英

如何創建靜態可綁定屬性描述對象

[英]How to create static bindable property description object

為了確保WPF中的綁定以現有屬性為目標,我使用靜態property-name-properties。

現在,我不需要將有關我的屬性的更多信息封裝到靜態屬性描述對象(名稱,類型,Id等)中,而不必為名稱包含一個可與路徑綁定的屬性,而不必為所有其他信息包含一個屬性。

問題在於WPF抱怨屬性的類型錯誤,不是String而是PropertyInfo。

我試圖以某種方式解決此限制。 例如,我嘗試使PropertyInfo隱式地可轉換為字符串,覆蓋ToString,並將TypeConverter從PropertyInfo添加到字符串,以及從PropertyInfo添加到字符串。 沒用。

而且我也不能直接綁定到Name-property。

<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;
    }
}

有什么建議么?

您的PropertyInfo需要具有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不使用TypeDescriptor基礎結構,因此無法使用TypeDescriptor添加屬性。

您可以使用MarkupExtension完成轉換。 這是完整的代碼(它使用System.Reflection命名空間中的PropertyInfo):

ReflectionHelper.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;
        }
    }
}

Test.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; }
    }
}

PropertyInfoPathExtension.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}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM