Search code examples
c#wpf-controlsdependencyobject

PropertyChangedCallback not triggered when DependencyObject Class Member is Modified


I created a DependencyObject with properties in it, I also have it inherit INotifyPropertyChanged.

But when it is implemented as a DependencyProperty, it does not trigger PropertyChangedCallback when I change a single property from the DependencyObject both in design and code.

This is the dependency object that I will use for my CustomControl.

public class Basemap : DependencyObject, INotifyPropertyChanged
{
    private string identifier;
    private string name;
    private string alias;
    private string url;

    private Map.DetailRange detailrange;
    private Map.Attribution attribution;

    public string Identifier
    {
        get => identifier;
        set
        {
            identifier = value;
            OnPropertyChanged("Identifier");
        }
    }

    public string Name
    {
        get => name;
        set
        {
            name = value;
            OnPropertyChanged("Name");
        }
    }

    public string Alias
    {
        get => alias;
        set
        {
            alias = value;
            OnPropertyChanged("Alias");
        }
    }

    public string URL
    {
        get => url;
        set
        {
            url = value;
            OnPropertyChanged("URL");
        }
    }

    public Map.DetailRange DetailRange
    {
        get => detailrange;
        set
        {
            detailrange = value;
            OnPropertyChanged("DetailRange");
        }
    }

    public Map.Attribution Attribution
    {
        get => attribution;
        set
        {
            attribution = value;
            OnPropertyChanged("Attribution");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

It has a PropertyChangedEventHandler and invoking it whenever the OnPropertyChanged is called, just like in this GUIDE

This it the DependecyProperty I implemented into the CustomControl that has a PropertyChangedCallback.

public static DependencyProperty BasemapProperty = DependencyProperty.Register("Basemap", typeof(Basemap), typeof(Browser), new PropertyMetadata(null, BasemapChanged));
private static void BasemapChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    Debug.WriteLine("Basemap Changed");
}

But the PropertyChangedCallback is not triggered when an individual property's value is changed, but it is triggered only when the whole DependecyObject is updated or inserted. Both in design and code

<Window.Resources>
    <mMAP:Basemap x:Key="OpenStreetMap" 
                      Identifier="OpenStreetMap.Standard"
                      Name="OpenStreetMap Standard" 
                      Alias="OpenStreetMap" 
                      URL="https://tile.openstreetmap.org/{z}/{x}/{y}.png" 
                      DetailRange="0,0,18"
                      Attribution="© OpenStreetMap contributors, CC-BY-SA" />
</Window.Resources>

Can anyone suggest any fixes to this?

Thank you.

Edit: I assigned the PropertyChanged event from the DependecyObject to the control:

Basemap.PropertyChanged += Basemap_PropertyChanged;

so it can be triggered every time any member of the DependecyObject class. It may be sacrilegious to do it to WPF, but works for me.

PS: I needed it to be grouped, for it is a configuration for the CustomControl.


Solution

  • You are not binding to the Dependency Property you defined in the control, that is why the PropertyChangedCallback BasemapChanged is not triggered.

    While it works on some cases, I try to avoid implementing the INotifyPropertyChanged Interface on Controls and use only Dependency Properties instead when binding is required.

    public static DependencyProperty AliasProperty = DependencyProperty.Register(
        nameof(Alias),
        typeof(string),
        typeof(Basemap),
        new PropertyMetadata(null, AliasPropertyChangedCallback));
    
    public string Alias
    {
        get { return (string)GetValue(Alias); }
        set { SetValue(Alias, value); }
    }
    
    private static void AliasPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine($"New Value of Alias: {e.NewValue}");
    }
    

    See: Dependency properties overview (WPF .NET)