-1

I have below xaml file (this a piece):

                        <Grid Opacity="1" Margin="5">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />                                
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />                                   
                            </Grid.ColumnDefinitions>

                            <Label Grid.Row="0" Grid.Column="0" Content="ID"/>
                            <Label Grid.Row="0" Grid.Column="1" Content="Name"/>
                            <Label Grid.Row="0" Grid.Column="2" Content="Description"/>                                

                            <TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding ID}"/>
                            <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
                            <TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding Description}"/>

                        </Grid>

Below the Data Class:

public class Data : INotifyPropertyChanged
{        
    private string id= string.Empty;
    private string name = string.Empty;
    private string description = string.Empty;


    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string ID
    {
        get
        {
            return this.id;
        }

        set
        {
            if (value != this.id)
            {
                this.id = value;
                NotifyPropertyChanged("ID");
            }
        }
    }

    public string Name
    {
        get
        {
            return this.name;
        }

        set
        {
            if (value != this.name)
            {
                this.name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    public string Description
    {
        get
        {
            return this.description;
        }

        set
        {
            if (value != this.description)
            {
                this.description = value;
                NotifyPropertyChanged("Description");
            }
        }
    }
}

Also in xaml.cs I implement INotifyPropertyChanged:

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

Furthermore, in the above xaml I have a button defined as:

<Button Click="btn_Click"/>

and the implementation for that is in xaml.cs as below:

    private void btn_Click(object sender, System.Windows.RoutedEventArgs e)
    {
      (DataContext as MyViewModel).SearchInDb('0303003'); // 0303003 -> this is only an example.
    }

On button click a method on MyViewModel class is called, and from there it invokes a query to database to retrieve data using ID = 0303003.

Below MyViewModel class (I show only the method):

 public void SearchInDb(string id)
 {
      // request data to sql server database
      // and then populate a Data Class Object with the data retrieved
      // from database:

      Data = new Data(){                            
                ID = sReader[0].ToString().Trim(),
                Name = sReader[1].ToString().Trim(),
                Description = sReader[2].ToString().Trim()
             };
 }

Note: MyViewModel class does not implement INotifyPropertyChanged.

My problem is the following:

After populating a new Data object within above method "SearchInDb", my labels in the grid are not updated, they remain empty.

Willy
  • 9,848
  • 22
  • 141
  • 284
  • So you assign a new value to the `Data` property, and nothing happens in the UI. You didn't show us how `Data` is defined. Does it raise `PropertyChanged` in its `set`? It's a member of the main viewmodel, right? Secondly, you don't bind to any properties of `Data` in your XAML. If `Data` is a property of the `DataContext` for the XAML you showed, and if you raise `PropertyChanged` when it changes, this should work: `{Binding Data.ID}`. – 15ee8f99-57ff-4f92-890c-b56153 Jun 15 '17 at 16:00
  • I see several confusion in the way MVVM works, but first, do you set your View Datacontext ? – fharreau Jun 15 '17 at 16:01
  • There is missing information here, I can't see why or how you are expecting an assignment of Data to update the labels in your grid? Are you setting the View's DataContext? How are you binding the View to Data exactly? –  Jun 15 '17 at 16:09
  • 1
    1) click [edit] 2) select XAML in first code block 3) ctrl-k until indentation is fixed 4) thank me for teaching you about ctrl-k –  Jun 15 '17 at 16:53

1 Answers1

1

You need to set the View's DataContext:

View.xaml.cs

public View()
{
    InitializeComponent();
    this.DataContext = new MyViewModel();
}

But there is some other issues in your snippets. In the MVVM way, it is the ViewModel which is supposed to implements INotifyPropertyChanged. Not the data class.

Here is how it is supposed to be:

Data Class

public class Data
{        
    public string Id {get;set;}
    public string Name {get;set;}
    public string Description {get; set;}
}

MyViewModel

public class MyViewModel : INotifyPropertyChanged
{        
    private Data _data;

    public string ID
    {
        get { return _data.Id;}
        set 
        {
            if(_data.Id != value)
            {
                _data.Id = value;
                NotifyPropertyChanged();
            }
        }
    }

    // Same stuff for the other properties

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName]String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void SearchInDb(string id)
    {
        // request data to sql server database
        // and then populate a Data Class Object with the data retrieved
        // from database:

        _data = new Data()
        {                            
            Id = sReader[0].ToString().Trim(),
            Name = sReader[1].ToString().Trim(),
            Description = sReader[2].ToString().Trim()
        };

        NotifyPropertyChanged(nameof(ID));
        NotifyPropertyChanged(nameof(Name));
        NotifyPropertyChanged(nameof(Description));
    }
}

There was nothing wrong with your NotifyPropertyChanged code. It is just an old way of doing it. This way is more modern and does not require magic strings ;-).

You can also bind the Command dependency property of your button to your SearchInDb methods by using a Command property in you view model. This way, you do not need to write code in your code behind. But that's another question :D.

And there is no need for your View to implements INotifyPropertyChanged (unless your case specifically required this).

fharreau
  • 2,105
  • 1
  • 23
  • 46
  • In the MyViewModel you provided you never calls the properties within the MyViewModel, ID, Name, Description. I am using visual studio 2008 with NET Framework 3.5 SP1. So how can I call the properties within MyViewModel after set the new Data() in SearchInDb method? – Willy Jun 15 '17 at 17:03
  • 1
    Your bindings declared in XAML are the 'calls to the properties' – Adam Vincent Jun 16 '17 at 03:33
  • nameof is not working in .NET 3.5 so I have used string name instead: "ID", "Name", "Description" – Willy Jun 16 '17 at 07:58
  • @user1624552 In that case, I doubt `[CallerMemberName]` will work. I think you will have to call `NotifyPropertyChanged` like you did in your question: `NotifyPropertyChanged("ID")`. Is your problem solved? – fharreau Jun 16 '17 at 08:29