kme
kme

Reputation: 91

WPF MVVM TextBox Update not Occurring

I'm new to WPF MVVM; so, this is a very simple test program exposing a TextBox update issue. Referring to the code below, checking the CheckBox (Name="view1TextBox1" in View1.xml) invokes the property ViewModel1BoolField1 (ViewModel1.cs) where RunTest (Model1.cs) is called. RunTest then returns a string (ViewModel1.cs). This string is then assigned to the ViewModel1StringField1 property. This is where the issue occurs as the TextBox view1TextBox1 (View.xml) is not updated with the test string "Testing 123". I'm not sure if I'm using "OnPropertyChanged" (ViewModelBase.cs) or the the view1TextBox1 "UpdateSourceTrigger=PropertyChanged" (View1.xml) correctly to update the TextBox. Any insight would be great. Thanks!

<UserControl x:Class="WpfMVVMExample1.View.View1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <StackPanel Orientation="Vertical">
            <TextBox Width="100" Height="100" Name="view1TextBox1" TextWrapping="Wrap" AcceptsReturn="True" Text="{Binding ViewModel1StringField1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            <CheckBox Name="view1CheckBox1" IsChecked="{Binding ViewModel1BoolField1}"/>
        </StackPanel>
    </UserControl>

namespace WpfMVVMExample1.ViewModel
{
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        public void Dispose()
        {
            this.OnDispose();
        }

        protected virtual void OnDispose()
        {
        }
    }
}   

namespace WpfMVVMExample1.ViewModel
{
    class ViewModel1 : ViewModelBase
    {
        #region Fields
        Model1 _model1;
        #endregion

        #region Constructors
        public ViewModel1()
        {
            _model1 = new Model1 { Model1StringField1 = "Field1" };
        }
        #endregion

        #region Properties

        public Model1 Model1
        {
            set
            {
                _model1 = value;
            }
            get
            {
                return _model1;
            }
        }

        public string ViewModel1StringField1
        {
            get
            {
                return Model1.Model1StringField1;
            }

            set
            {
                Model1.Model1StringField1 = value;
                OnPropertyChanged(ViewModel1StringField1);
            }
        }

        public bool ViewModel1BoolField1
        {
            get
            {
                return Model1.Model1BoolField1;
            }
            set
            {
                Model1.Model1BoolField1 = value;
                if (value)
                {
                    ViewModel1StringField1 = Model1.RunTest();
                }
            }
        }         
        #endregion
    }
}

namespace WpfMVVMExample1.Model
{
    class Model1
    {
        #region Fields
        string _model1StringField1;
        bool _model1BoolField1;
        #endregion

        #region Properties
        public string Model1StringField1
        {
            get 
            { 
                return _model1StringField1; 
            }
            set
            {
                _model1StringField1 = value;
            }
        }

        public bool Model1BoolField1
        {
            get
            {
                return _model1BoolField1;
            }
            set
            {
                _model1BoolField1 = value;
            }
        }
        #endregion

        #region Functions
        public string RunTest()
        {
            return "Testing 123";
        }
        #endregion
    }
}

Upvotes: 1

Views: 243

Answers (2)

vesan
vesan

Reputation: 3369

If you look at your ViewModelBase class, you'll see this method signature:

protected virtual void OnPropertyChanged(string propertyName)

The parameter of this method is the name of the property that has changed. However, when you invoke it in your ViewModel1StringField1 setter, you do this:

OnPropertyChanged(ViewModel1StringField1);

Instead of the property name, you're passing in its value, which could be anything the user put in. Instead, you want to do this:

OnPropertyChanged("ViewModel1StringField1");

The downside is that the property name is now string and will not be checked by the compiler when you change the name of the property. So just be careful about that (there are alternative ways of doing this).

Upvotes: 1

Tim
Tim

Reputation: 2912

When you call on property changed you are supposed to pass in the property name that changed. Currently you are passing in the value of the property.

OnPropertyChanged(ViewModel1StringField1); }

Should be

OnPropertyChanged("ViewModel1StringField1"); }

Upvotes: 2

Related Questions