【问题标题】:Create attached property dynamically动态创建附加属性
【发布时间】:2017-02-07 11:29:35
【问题描述】:

尝试重构一个tedious solution,我想到了绝妙动态创建附加属性的想法,基本上:

void SomeMethod()
{
    ...
    var dp = DependencyProperty.RegisterAttached("SomeUniqueOrGeneratedName333", typeof(object), typeof(CurrentClass));
    ...
}

这不是recommended的方式。

我正在使用这样的属性(大吃一惊,比如如果有人将附加属性用于其他东西)作为与对象数据相关的一些存储(即绑定)。这些是稍后在相同方法的 lambda 中检索的(不确定它是如何调用的,closure 我能想到的最接近的词),例如:

// create attached property an store binding to retrieve result later
var dp = DependencyProperty.RegisterAttached("LolBinding", typeof(object), typeof(CurrentClass));
BindingOperations.SetBinding(obj, dp, someBinding);
// another ap and binding, this time with event (will trigger when DataContext for obj is set)
BindingOperations.SetBinding(obj, DependencyProperty.RegisterAttached("LolAnotherBinding", typeof(object), typeof(CurrentClass), new PropertyMetadata(null, (d, e) =>
{
     var value = obj.GetValue(dp); // accessing ap 
     if (value != null) { ... } // do something
})), Property);

这行得通。我可以附加任意数量的属性:

for(int i = 0; i < 10000; i++)
    DependencyProperty.RegisterAttached("SomeName" + i, typeof(object), typeof(MainWindow));

但它有问题,因为它不可能retrieve dependency property(也不是via reflection)。我的猜测 (feel free to discover) 这是因为它们不是该类型的静态成员

这是我的问题:这样做是否OK

我担心的是内存(即泄漏)和性能。如果确认没问题,我可能会开始大量使用这种技术。

可能听起来像是基于意见,但我怀疑能否单独正确测试。


编辑,这里是创建和检索此类属性的 mcve:

// put this into window constructor
var dp = DependencyProperty.RegisterAttached("SomeName", typeof(object), typeof(MainWindow));
SetValue(dp, "test"); // even trying to set value
// trying to access it by name
var a = DependencyPropertyDescriptor.FromName("SomeName", typeof(MainWindow), typeof(MainWindow), true);
var b = GetAttachedProperty(this, "SomeName", typeof(MainWindow)); // method from linked question

ab 都是 null。我只能通过传递引用来访问dp

P.S.:尝试创建具有相同名称的依赖属性会抛出异常。所以应该有办法访问它。

【问题讨论】:

  • 您引用的两个问题都显示了如何检索依​​赖项属性值,那么这是怎么回事?
  • @Evk,见编辑。
  • 除非您打算动态创建新类型(发射?),否则 IMO 唯一要做的就是自己跟踪这些属性
  • @AdrianoRepetti,如果无法按名称检索属性(所以我必须存储参考,而不是名称),我的问题仍然是:可以这样做吗?我不创建静态成员或 Get/SetProperty 方法(仅 xaml afaik 需要这些),它不会产生一些问题吗?有些东西不会被释放,等等?一些收藏品会不断增长而从未清理过?
  • AFAIK 没关系(当然……除非您一直添加属性直到内存不足……如果您添加的属性是临时的,那么它们需要注销。)我记得我看到有人尝试类似的方法

标签: c# wpf attached-properties


【解决方案1】:

我现在明白你的意思了。是的,DependencyPropertyDescriptor.FromName 对您的情况没有帮助,因为您没有在目标类型上定义 GetValue 和 SetValue 方法。但是,有一种方法可以通过名称通过一些反射来获取您的依赖属性。需要反射,因为这个有用的方法 (DependencyProperty.FromName) 出于某种奇怪的原因在内部:

// put this into window constructor
var dp = DependencyProperty.RegisterAttached("SomeName", typeof(object), typeof(MainWindow));
SetValue(dp, "test"); // even trying to set value                      
// do this only once per application
var fromNameMethod = typeof(DependencyProperty).GetMethod("FromName", BindingFlags.Static | BindingFlags.NonPublic);
var fromName = (Func<string, Type, DependencyProperty>) fromNameMethod.CreateDelegate(typeof(Func<string, Type, DependencyProperty>));
// now it's fast to call this method via delegate, almost 0 reflection costs
var a = fromName("SomeName", typeof(MainWindow));
var value = GetValue(a); // "test"

至于可以用吗。当然,这可能不是附加属性的预期用途,但我认为这没有问题。依赖属性值存储在对象本身中,而不是在某个静态位置,因此一旦对象本身被收集,它们就会被收集。当然,注册后附加属性本身不会被收集,但除非您注册太多,否则这应该不是问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 2011-04-06
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    相关资源
    最近更新 更多