动态创建附加属性

时间:2017-02-07 11:29:35

标签: c# wpf attached-properties

尝试重构一个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)因为那些不是该类型的静态成员

这是我的问题:这样做确定吗?

我担心的是记忆(即泄漏)和表现。如果确认没问题,我可能会开始使用这种技术。

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

编辑,这里是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。:尝试创建具有相同名称的依赖项属性将抛出。所以应该有办法访问它。

1 个答案:

答案 0 :(得分: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"

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