Windgate
Windgate

Reputation: 430

Assigning an object to another doesn't raise PropertyChanged event in WPF

I have tried to isolate my problem in a very simple (and working) project. Let's say I have a simple model with 2 fields, and I have configured its properties and a PropertyChanged event. This is a simplified implementation of my model, please notice the last method just gets a new client object from a list and returns it:

public class Clients : INotifyPropertyChanged
{
    private long _Id = 0;

    public long Id 
    {
        get { return this._Id; } 
        set { 
            this._Id = value;
            RaisePropertyChanged("Id");
        } 
    }

    private String _Name = string.Empty;

    public String Name 
    {
        get { return this._Name; }
        set { 
            if (value is null) 
                this._Name = string.Empty;
            else
                this._Name = value;
            RaisePropertyChanged("Name");
        } 
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    internal void RaisePropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    // Let's say this is a populated list with 100 clients with different ids and names
    public static List<Clients> clients = new List<Clients>();
    // ...method for loading the list with DB data

    public static Clients? LoadClient(long id)
    {
        return clients.FirstOrDefault(x => x.Id == id);
    }
}

And I have a simple .xaml file in order to display one client data (id and name). Each UI control has a binding with the client property and the trigger for updating. I have also 2 configured buttons that will make changes to the client values:

<TextBox x:Name="txtClientId" Text="{Binding Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</TextBox>
<TextBox x:Name="txtClientName" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</TextBox>
<Button Name="btnNext" Click="btnNext_Click">Next</Button>
<Button Name="btnRandom" Click="btnRandom_Click">Random</Button>

Now let's take a look to my .xaml.cs code. Here is the initializing and the code for the 2 buttons: one of them just modify the client properties in the DataContext object directly, and the other just assigns a new client object to the DataContext client:

public partial class ClientsPage : Page
{
    private Models.Clients? client = null;

    public ClientsPage()
    {
        InitializeComponent();

        // Load all clients data in Models.Clients.clients list...
        client = new Models.Clients();

        DataContext = client;
    }
    
    private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        client = Models.Clients.LoadClient(client.Id + 1);
    }

    private void btnRandom_Click(object sender, RoutedEventArgs e)
    {
        Random random = new Random();
        client.Id = random.Next(999);
        client.Name = "RANDOM";
    }
}

Of course this situation can be solved by assigning property values instead of assigning a new object directly:

private void btnNext_Click(object sender, RoutedEventArgs e)
{
    Models.Clients newClient = Models.Clients.LoadClient(client.Id + 1);

    this.client.Id = newClient.Id;
    this.client.Name = newClient.Name;
}

But it is so tedious in a real project with many models and methods that can load/modify an object with a lot of fields. I'm looking for an easy/scalable way for making the PropertyChanged event fire when I assign a new object to the DataContext variable. If you need more detail of my code or have any question I'll be happy to ask.

Upvotes: 0

Views: 77

Answers (1)

Gilad Waisel
Gilad Waisel

Reputation: 205

The new instance of the object is created but has not been assigned to DataContext. Assignment to DataContext is required. Correct code is :

private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        client = Models.Clients.LoadClient(client.Id + 1);
        DataContext = client; 
    }

Upvotes: 1

Related Questions