Какой-либо способ не зарегистрировать свойство зависимости WPF?

Объявление переменной без ключевого слова var делает переменную глобальной переменной.

9
задан Gumbo 27 August 2011 в 10:23
поделиться

4 ответа

У меня вчера была аналогичная проблема, когда я пытался протестировать мой собственный класс создания DependencyProperty. Я столкнулся с этим вопросом и заметил, что реального решения для отмены регистрации свойств зависимостей не существует. Поэтому я немного покопался, используя Red Gate .NET Reflector , чтобы увидеть, что я могу придумать.

Глядя на перегрузки DependencyProperty.Register , все они, казалось, указывали на DependencyProperty.RegisterCommon . Этот метод состоит из двух частей:

Первая - для проверки, зарегистрировано ли свойство

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

Вторая, Регистрация DependencyProperty

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

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

Обе части сосредоточены вокруг DependencyProperty.PropertyFromName , HashTable. Я также заметил DependencyProperty.RegisteredPropertyList , ItemStructList , но не видел, где это используется. Однако, в целях безопасности, я решил, что постараюсь удалить и это, если возможно.

Итак, я получил следующий код, который позволил мне «отменить регистрацию» свойства зависимости.

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

Он работал достаточно хорошо для мне запустить мои тесты без получения исключения «уже зарегистрировано». Однако я настоятельно рекомендую вам не использовать это в каком-либо производственном коде. Вероятно, есть причина, по которой MSFT предпочла не иметь формального способа отменить регистрацию свойства зависимости, и попытки пойти против него просто напрашиваются на проблемы.

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

Это сработало достаточно хорошо, чтобы я мог запускать тесты, не получая исключения «Уже зарегистрировано». Однако я настоятельно рекомендую вам не использовать это в каком-либо производственном коде. Вероятно, есть причина, по которой MSFT предпочла не иметь формального способа отменить регистрацию свойства зависимости, и попытки пойти против него просто напрашиваются на проблемы.

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

Это сработало достаточно хорошо, чтобы я мог запускать тесты, не получая исключения «Уже зарегистрировано». Однако я настоятельно рекомендую вам не использовать это в каком-либо производственном коде. Вероятно, есть причина, по которой MSFT предпочла не иметь формального способа отменить регистрацию свойства зависимости, и попытки пойти против него просто напрашиваются на проблемы.

8
ответ дан 4 December 2019 в 21:13
поделиться

Если все остальное перестало работать, можно создать новый AppDomain для каждого Теста.

2
ответ дан 4 December 2019 в 21:13
поделиться

Я не думаю, что можно не зарегистрировать свойство зависимости, но можно переопределить его путем переопределения метаданных как это:

MyDependencyProperty.OverrideMetadata(typeof(MyNewType), 
                     new PropertyMetadata());
0
ответ дан 4 December 2019 в 21:13
поделиться

Если мы зарегистрируем имя для метки следующим образом:

Label myLabel = new Label();
this.RegisterName(myLabel.Name, myLabel);

Мы можем легко отменить регистрацию имени, используя:

this.UnregisterName(myLabel.Name);
0
ответ дан 4 December 2019 в 21:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: