Home > other >  PropertyChanged event always null even after setting DataContext
PropertyChanged event always null even after setting DataContext

Time:12-04

I have a Model with INotifyPropertyChanged handling copied from tutorials:

    public event PropertyChangedEventHandler? PropertyChanged;
    protected void Notify(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

When I update a member of the class, I call the handler:

    public string? Id
    {
        get => _id;
        set
        {
            if (value != _id)
            {
                _id = value;
                Notify(nameof(Id));
            }
        }
    }

And in the view code behind I have:

    private Goal _goal;
    public GoalControl()
    {
        InitializeComponent();
        this._goal = new MyGoal();
        this.DataContext = _goal;
        Binding binding = new Binding("Text");
        binding.Source = _goal.Id;
        binding.Mode = BindingMode.TwoWay;
        _ = Id.SetBinding(TextBox.TextProperty, binding);
    }

But the view doesn't pick up any changes to the field. When I debug, I find that PropertyChanged is always null. How should I set it to a useful value?

This is in a user control, by the way, which will be generated dynamically so I don't think I can do the binding from XAML.

CodePudding user response:

Assuming that Id is a TextBox in your GoalControl, you would bind its Text property to the Id of the MyGoal object in the DataContext like shown below.

You do not set the Source property of the Binding, because the source object should be provided by the current DataContext. Also note that TwoWay is the default binding mode for the TextBox.Text property and does not need to be set explicitly.

public GoalControl()
{
    InitializeComponent();

    _goal = new MyGoal();
    DataContext = _goal;

    Binding binding = new Binding("Id");
    Id.SetBinding(TextBox.TextProperty, binding);
}

The Binding could as well be written in XAML:

<TextBox Text="{Binding Id}"/>

Since this is in a UserControl, you should however not set the DataContext at all. UserControls, as any other controls, should not have "private" view models like your MyGoal object.

The UserControl would instead expose a dependency property Id, which is bound when you use the control, like

<local:GoalControl Id="{Binding SomeViewModelId}"/>

In the UserControl's XAML, the Binding to the own property would specify the Source object as RelativeSource:

<TextBox Text="{Binding Id,
                RelativeSource={RelativeSource AncestorType=UserControl}}"/>
  •  Tags:  
  • wpf
  • Related