Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
221 views
in Technique[技术] by (71.8m points)

c# - WPF: Bind property to TextBlock not working

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...