Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Реализация INotifyPropertyChanged средствами аспектно-ориентированного программирования

Читайте также:
  1. I.VI. Организация обращения со средствами разграничения доступа
  2. III. Порядок пользования средствами индивидуальной защиты
  3. III. Управление силами и средствами на пожаре
  4. Анализ материальных ресурсов и обеспеченности оборотными средствами
  5. БРАК - ЭТО ПРОДОЛЖЕНИЕ ЛЮБВИ ИНЫМИ СРЕДСТВАМИ
  6. Возврат и реализация грузов перевозчиком
  7. Выбор и реализация решения

Как было сказано ранее, так как создание экземпляров моделей представления происходит посредством IoC контейнера, возможно расширить логику создания объекта и дополнять его произвольными аспектами.

Данная функциональность недоступна в базовой версии MEF, и требует использования дополнительных библиотек, MefContrib и DynamicProxy (которые помимо перехвата создания объекта реализует некоторые другие полезные функции, выходящие за рамки лекции).

В целях лучшей расширяемости приложения следует объявить перечисление со всеми доступными аспектами (на текущий момент с 1 аспектом):

1: [Flags]

2: public enum Aspects

3: {

4: NotifyPropertyChanged = 1,

5: }

А также необходимо написать небольшой метод-расширение, добавляющий к контейнеру MEF логику перехвата создания объектов. Если в метаданных создаваемого экземпляра найден атрибут AspectMetadata и указан аспект NotifyPropertyChanged, он будет обернут прокси-объектом, реализующим логику INotifyPropertyChanged:

1: public static class AopExtensions

2: {

3: public const string AspectMetadata = "AspectMetadata";

4:

5: public static InterceptionConfiguration AddAopInterception(

6: this InterceptionConfiguration interceptionConfiguration)

7: {

8: return interceptionConfiguration

9:.AddInterceptionCriteria(

10: new PredicateInterceptionCriteria(

11: new PropertyChangedDynamicProxyExportInterceptor(),

12: def => def.ExportDefinitions.Any(export =>

13: export.Metadata.ContainsKey(AspectMetadata) &&

14: ((Aspects)export.Metadata[AspectMetadata] &

15: Aspects.NotifyPropertyChanged)!= 0)));

16: }

17: }

 

1: internal class PropertyChangedDynamicProxyExportInterceptor:

2: IExportedValueInterceptor

3: {

4: private static readonly ProxyGenerator Generator =

5: new ProxyGenerator();

6: private readonly Type[] _additionalInterfaces = new[]

7: { typeof(INotifyPropertyChanged) };

8:

9: public object Intercept(object value)

10: {

11: object proxy = Generator.CreateClassProxy(

12: value.GetType(), _additionalInterfaces,

13: new[] { new PropertyChangedInterceptor() });

14:

15: Type currentType = value.GetType();

16:

17: do

18: {

19: FieldInfo[] fields =

20: currentType.GetFields(BindingFlags.Instance |

21: BindingFlags.NonPublic | BindingFlags.Public)

22:.Where(field =>

23: (field.Attributes & FieldAttributes.InitOnly) == 0)

24:.ToArray();

25:

26: fields.Select(field => new { Field = field,

27: Value = field.GetValue(value) })

28:.ForEach(desc =>

29: desc.Field.SetValue(proxy, desc.Value));

30:

31: currentType = currentType.BaseType;

32: } while (currentType!= null);

33:

34: return proxy;

35: }

36: }

 

1: internal class PropertyChangedInterceptor: IInterceptor

2: {

3: private event PropertyChangedEventHandler PropertyChanged;

4:

5: public void Intercept(IInvocation invocation)

6: {

7: string methodName = invocation.Method.Name;

8:

9: if (invocation.Method.IsSpecialName)

10: {

11: if (invocation.Method.DeclaringType ==

12: typeof(INotifyPropertyChanged))

13: {

14: if (methodName.StartsWith("add_"))

15: {

16: PropertyChanged+=(PropertyChangedEventHandler)

17: invocation.Arguments[0];

18: }

19: else

20: {

21: PropertyChanged-=(PropertyChangedEventHandler)

22: invocation.Arguments[0];

23: }

24:

25: return;

26: }

27:

28: if (methodName.StartsWith("set_"))

29: {

30: PropertyInfo propertyInfo = invocation.Proxy

31:.GetType().GetProperty(methodName.Substring(4));

32: object oldValue = propertyInfo.GetValue(

33: invocation.Proxy,

34: invocation.Arguments.SkipLast(1).ToArray());

35:

36: invocation.Proceed();

37:

38: if (oldValue == invocation.Arguments

39: [invocation.Arguments.Length - 1])

40: {

41: return;

42: }

43:

44: OnPropertyChanged(invocation.Proxy,

45: new PropertyChangedEventArgs(propertyInfo.Name));

46:

47: return;

48: }

49: }

50:

51: invocation.Proceed();

52: }

53:

54: private void OnPropertyChanged(object sender,

55: PropertyChangedEventArgs e)

56: {

57: PropertyChangedEventHandler eventHandler=PropertyChanged;

58:

59: if (eventHandler!= null)

60: {

61: eventHandler(sender, e);

62: }

63: }

64: }

Последним шагом является вызов метода-расширения для MEF контекста приложения:

1: var catalog = new InterceptingCatalog(new DirectoryCatalog("."),

2: new InterceptionConfiguration().AddAopInterception());

Теперь любой класс, помеченный атрибутом [ExportMetadata(AopExtensions.AspectMetadata, Aspects.NotifyPropertyChanged)], при разрешении через IoC контейнер, автоматически получит реализацию INotifyPropertyChanged для своих виртуальных свойств.


Дата добавления: 2015-08-13; просмотров: 76 | Нарушение авторских прав


Читайте в этой же книге: Шаг 5. Команды | Создание ссылок на XAML файлы | Синхронное использование XAML | Отсутствие метода OverrideMetadata() | Отсутствие свойства No PathSegment.IsStroked | Краткие итоги | Задача 3. | Принцип инверсии зависимостей | Формы инверсии зависимостей | IoC контейнер |
<== предыдущая страница | следующая страница ==>
Сопоставление модели представления и представления| Краткие итоги

mybiblioteka.su - 2015-2024 год. (0.008 сек.)