简体   繁体   中英

Understanding Data Binding from a ViewModel

I'm new to C#/.NET and especially to binding since it is a new concept for me, I do understand simple binding like the one below...

<TextBox Name="myTextField" Text="{Binding Path=Text, ElementName=myTextField2}" />
<TextBox Name="myTextField2" Text="{Binding Path=Text, ElementName=myTextField}"/>

But I'm confused on how to do it from a ViewModel . I was watching a video about MVVM which helped me understand a few concepts that I had trouble understanding, but since no code was provided I tried to write the code to see the demonstration in action but I'm missing the XAML/Binding part since the presenter doesn't show that part of the code. You can see how all works in minute 5:05 .

Here is all of the code:

Person Class:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MVVM_BestPractices 
{
    public class Person : INotifyPropertyChanged 
    {
        private string _firstName;
        public string FirstName 
        {
            get { return _firstName; }
            set 
            {
                _firstName = value;
                OnPropertyChanged();
                OnPropertyChanged("FullName");
            }
        }

        private string _lastName;
        public string LastName 
        {
            get { return _lastName; }
            set 
            {
                _lastName = value;
                OnPropertyChanged();
                OnPropertyChanged("FullName");
            }
        }

        public string FullName 
        {
            get { return string.Format("{0} {1}", this.FirstName, this.LastName); }
        }

        public Person() {}

        public Person(string firstName, string lastName) 
        {
            this.FirstName = firstName;
            this.LastName = lastName;
        }

        // INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propertyName = "") 
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

ViewModel Class:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MVVM_BestPractices {
    public class ViewModel : INotifyPropertyChanged
    {
        Person _model;
        public Person Model 
        {
            get { return _model; }
            set 
            {
                _model = value;
                OnPropertyChanged();
            }
        }

        public ViewModel() 
        {
            Model = new Person("Brian", "Lagunas");
        }

        // INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propertyName = "") 
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

    }
}

XAML Code: As you can see I have no clue on how to bind the data from the ViewModel.

<Window x:Class="MVVM_BestPractices.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MVVM_BestPractices"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <TextBox  Width="200" Height="30" Margin="158,57,159,233"/>
        <TextBox  Width="200" Height="30" Margin="158,102,159,188"/>
        <TextBlock Text="{Binding Person, Mode=OneWay}" Width="200" Height="30" Margin="158,148,159,142"/>
    </Grid>
</Window>

Can someone help me bind the data from the ViewModel to the textBoxes as shown in minute 5:05 ?

This will help me understand Binding and MVVM .

Without watching the video, I would say:

<TextBox  Text={Binding Model.FirstName} ... />
<TextBox  Text={Binding Model.LastName} ... />
<TextBlock Text="{Binding Model.FullName, Mode=OneWay}" ... />

This ought to work but only because you implemented INotifyPropertyChanged on your Model class here. You don't always have or want that.

Side note: try to avoid using Margin="" for layout purposes. I know that's what the Designer does but it's a really bad practice.

In your ViewModel, you call your property Model, not Person (Person being your type). So you need to change your binding to {Binding Model, Mode=OneWay} . The binding will then happen, but you won't have the result (that I guess) you are looking for. What you want to write is not the value of Model (ie Model.ToString()), but the value of the FullName property of Model. So it's quite simple: {Binding Model.FullName, Mode=OneWay}

Moreover, in the set of your properties, you should begin with checking if the new value is different from the old one.

set
{
    if (_firstName == value) return;
    _firstName = value;
    OnPropertyChanged();
    OnPropertyChanged(nameof(FullName)); // And use nameof() like this if you're in C# 6
}

Binding to the Model property in the ViewModel is straightforward if you have set the DataContext (which you have):

<TextBlock Text="{Binding Person, Path=FirstName}"/>

or you can omit the Path:

<TextBlock Text="{Binding Person.FirstName}"/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM