Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
517 views
in Technique[技术] by (71.8m points)

.net - Any way to un-register a WPF dependency property?

I'm running into an unusual problem in my unit tests. The class I'm testing creates a dependency property dynamically at runtime and the type of that dependency property can vary depending on the circumstances. While writing my unit tests, I need to create the dependency property with different types and that leads to errors because you can't redefine an existing dependency property.

So is there any way to either un-register a dependency property or to change the type of an existing dependency property?

Thanks!


OverrideMetadata() only lets you change a very few things like default value so it isn't helpful. The AppDomain approach is a good idea and might work but seems more complicated than I really wanted to delve into for the sake of unit testing.

I never did find a way to unregister a dependency property so I punted and carefully reorganized my unit tests to avoid the issue. I'm getting a bit less test coverage, but since this problem would never occur in a real application and only during unit testing I can live with it.

Thanks for the help!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I had similar issue just yesterday when trying to test my own DependencyProperty creating class. I came across this question, and noticed there was no real solution to unregister dependency properties. So I did some digging using Red Gate .NET Reflector to see what I could come up with.

Looking at the DependencyProperty.Register overloads, they all seemed to point to DependencyProperty.RegisterCommon. That method has two portions:

First to check if the property is already registered

FromNameKey key = new FromNameKey(name, ownerType);
lock (Synchronized)
{
  if (PropertyFromName.Contains(key))
  {
    throw new ArgumentException(SR.Get("PropertyAlreadyRegistered", 
      new object[] { name, ownerType.Name }));
  }
}

Second, Registering the DependencyProperty

DependencyProperty dp = 
  new DependencyProperty(name, propertyType, ownerType, 
    defaultMetadata, validateValueCallback);

defaultMetadata.Seal(dp, null);
//...Yada yada...
lock (Synchronized)
{
  PropertyFromName[key] = dp;
}

Both pieces center around DependencyProperty.PropertyFromName, a HashTable. I also noticed the DependencyProperty.RegisteredPropertyList, an ItemStructList<DependencyProperty> but have not seen where it is used. However, for safety, I figured I'd try to remove from that as well if possible.

So I wound up with the following code that allowed me to "unregister" a dependency property.

private void RemoveDependency(DependencyProperty prop)
{
  var registeredPropertyField = typeof(DependencyProperty).
    GetField("RegisteredPropertyList", BindingFlags.NonPublic | BindingFlags.Static);
  object list = registeredPropertyField.GetValue(null);
  var genericMeth = list.GetType().GetMethod("Remove");
  try
  {
    genericMeth.Invoke(list, new[] { prop });
  }
  catch (TargetInvocationException)
  {
    Console.WriteLine("Does not exist in list");
  }

  var propertyFromNameField = typeof(DependencyProperty).
    GetField("PropertyFromName", BindingFlags.NonPublic | BindingFlags.Static);
  var propertyFromName = (Hashtable)propertyFromNameField.GetValue(null);

  object keyToRemove = null;
  foreach (DictionaryEntry item in propertyFromName)
  {
    if (item.Value == prop)
      keyToRemove = item.Key;
  }
  if (keyToRemove != null)
  propertyFromName.Remove(keyToRemove);
}

It worked well enough for me to run my tests without getting an "AlreadyRegistered" exception. However, I strongly recommend that you do not use this in any sort of production code. There is likely a reason that MSFT chose not to have a formal way to unregister a dependency property, and attempting to go against it is just asking for trouble.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...