2016-08-12 6 views
0

Я разрабатываю приложение в C# WPF.Копировать EventHandler в унаследованном классе

Я использую класс PropertyChangedNotifier для управления INotifyPropertyChanged (см. that link).

Я использую классический ViewModelBase:

public class ViewModelBase : INotifyPropertyChanged, IRequestClose 
{ 
    public PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = _propertyChanged; 

     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

В моем MainViewModel : ViewModelBase у меня PropertyChangedNotifier<MainViewModel> работает так:

class MainViewModel : ViewModelBase 
{ 
    private PropertyChangedNotifier<MainViewModel> _notifier; 
    public new event PropertyChangedEventHandler PropertyChanged 
    { 
     add { _notifier.PropertyChanged += value; } 
     remove { _notifier.PropertyChanged -= value; } 
    } 

    public MainViewModel() 
    { 
     _notifier = new PropertyChangedNotifier<MainViewModel>(this); 
    } 

    protected new void OnPropertyChanged(string propertyName) 
    { 
     _notifier.OnPropertyChanged(propertyName); 
    } 
} 

Но изменения не обнаружены, когда изменяется значение, мои MainWindows Безразлично» t обновить (без использования PropertyChangedNotifier он работает). Я видел, что система инициирует окна с помощью WindowsBase.dll!System.ComponentModel.PropertyChangedEventManager.StartListening(object source), а затем я увидел, что мой ViewModelBase.PropertyChanged не имеет значения null, когда вызывается конструктор для MainViewModel.

Можно ли сделать что-то вроде этого:

public MainViewModel() 
{ 
    _notifier = new PropertyChangedNotifier<MainViewModel>(this); 
    _notifier.PropertyChanged = base.PropertyChanged; 
} 

И будет, что исправить мою ошибку?

Edit:

PropertyChangeNotifier от ссылки:

[AttributeUsage(AttributeTargets.Property)] 
public class DepondsOnAttribute : Attribute 
{ 
    public DepondsOnAttribute(string name) 
    { 
     Name = name; 
    } 

    public string Name { get; } 
} 

public class PropertyChangedNotifier<T> : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public PropertyChangedNotifier(T owner) 
    { 
     mOwner = owner; 
    } 

    public void OnPropertyChanged(string propertyName) 
    { 
     var handler = PropertyChanged; 
     if(handler != null) handler(mOwner, new PropertyChangedEventArgs(propertyName)); 

     List<string> dependents; 
     if(smPropertyDependencies.TryGetValue(propertyName, out dependents)) 
     { 
      foreach(var dependent in dependents) OnPropertyChanged(dependent); 
     } 
    } 

    static PropertyChangedNotifier() 
    { 
     foreach(var property in typeof(T).GetProperties()) 
     { 
      var dependsOn = property.GetCustomAttributes(true) 
            .OfType<DepondsOnAttribute>() 
            .Select(attribute => attribute.Name); 

      foreach(var dependency in dependsOn) 
      { 
       List<string> list; 
       if(!smPropertyDependencies.TryGetValue(dependency, out list)) 
       { 
        list = new List<string>(); 
        smPropertyDependencies.Add(dependency, list); 
       } 

       if (property.Name == dependency) 
        throw new ApplicationException(String.Format("Property {0} of {1} cannot depends of itself", dependency, typeof(T).ToString())); 

       list.Add(property.Name); 
      } 
     } 
    } 

    private static readonly Dictionary<string, List<string>> smPropertyDependencies = new Dictionary<string, List<string>>(); 

    private readonly T mOwner; 
} 
+0

Какова цель 'PropertyChangedNotifier '? Почему бы просто не реализовать «INotifyPropertyChanged» правильно? –

+0

@ LasseV.Karlsen Особенно, когда он * уже реализован наследованием от ViewModelBase. ИМО, вопрос не имеет смысла. – Clemens

+0

@Clemens: Правильно –

ответ

0

Проблема заключается в том, что, когда мой MainViewModel создан, base.PropertyChanged равно нулю. Вызывается конструктор, поля/свойства инициализированы (некоторые называют OnPropertyChanged), а после MainView.InitializeComponent() добавляют обработчик в base.PropertyChanged (я приложил к нему отладчик, чтобы увидеть это). Это добавление сделано в ViewModelBase, игнорируя public new event PropertyChangedEventHandler PropertyChanged в MainViewModel.

У меня есть идея проверить, было ли base.PropertyChanged было изменено и скопировано.

Я сделал это, я не знаю, есть ли хорошая идея, что вы думаете?

public class ViewModelBase : INotifyPropertyChanged, IRequestClose 
{ 
    protected event PropertyChangedEventHandler _propertyChanged; 
    protected bool propertyAdded { get; private set; } 
    public event PropertyChangedEventHandler PropertyChanged 
    { 
     add 
     { 
      _propertyChanged += value; 
      propertyAdded = true; 
     } 
     remove { _propertyChanged -= value; } 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = _propertyChanged; 

     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public Delegate[] Get_PropertyChanged() 
    { 
     isPropertyAdded = false; 
     Delegate[] delegates = new Delegate[0]; 
     if (_propertyChanged != null) 
     { 
      delegates = _propertyChanged.GetInvocationList(); 
      _propertyChanged = null; 
     } 

     return delegates; 
    } 
} 

и

class MainViewModel : ViewModelBase 
{ 
    private PropertyChangedNotifier<MainViewModel> _notifier; 
    public new event PropertyChangedEventHandler PropertyChanged 
    { 
     add { _notifier.PropertyChanged += value; } 
     remove { _notifier.PropertyChanged -= value; } 
    } 

    public MainViewModel() 
    { 
     _notifier = new PropertyChangedNotifier<MainViewModel>(this); 
    } 

    protected new void OnPropertyChanged(string propertyName) 
    { 
     if (isPropertyAdded) 
     { 
      foreach (Delegate d in Get_PropertyChanged()) 
      { 
       _notifier.PropertyChanged += (PropertyChangedEventHandler)d; 
      } 
     } 

     _notifier.OnPropertyChanged(propertyName); 
    } 
} 
0

Похож замысловатым решением простого NotifyPropertyChanged("dependentProperty"), хотя я понимаю желание спроектировать орнаментальные решения. Было бы разумно, если бы у него были некоторые преимущества производительности/локализации, но это не так. Это просто добавляет сложности.