Search code examples
c#wpfmvvmdependency-propertiesinotifypropertychanged

Problem with Dependency Property and PropertyChangedCallback in WPF


In my CustomControl, I have a View dependency property that is set by the outer control using a view model. When this property is set, the Refresh method is triggered and the View is rendered. This works as expected. However, I would also like the Refresh method to be triggered when a property of the View is changed. Is this the standard way of handling this situation, or should I define a public Refresh() method on the control and call it from outside? Can I use commanding to achieve this? Any guidance on the correct approach would be appreciated.

  public static readonly DependencyProperty ViewProperty =
     DependencyProperty.Register(
        "View", typeof(View),
        typeof(CustomControl), new PropertyMetadata(Refresh)
     );


  public View View
  {
     get => (View)GetValue(ViewProperty);
     set => SetValue(ViewProperty, value);
  }

  private static void Refresh(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
     // 
     MessageBox.Show("Refreshed!");
  }

   public sealed class View : INotifyPropertyChanged
   {
      private bool m_isDirty;

      public bool IsDirty
      {
         get => m_isDirty;
         set
         {
            m_isDirty = value;
            OnPropertyChanged();
         }
      }

      public event PropertyChangedEventHandler PropertyChanged;

      private void OnPropertyChanged([CallerMemberName] string propertyName = null)
      {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
   }

Solution

  • You could hook up an event handler for the PropertyChanged event of the View in your callback:

    private static void Refresh(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MessageBox.Show("Refreshed!");
    
        View newView = e.NewValue as View;
        if (newView != null)
            newView.PropertyChanged += NewView_PropertyChanged;
    
        View oldView = e.OldValue as View;
        if (oldView != null)
            oldView.PropertyChanged -= NewView_PropertyChanged;
    }
    
    private static void NewView_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        View view = (View)sender;
        //view updated...
    }