简体   繁体   中英

WPF MVVM textBox Text Binding

I am just getting started with MVVM so apologies if I've done something really stupid. I tried writing a very simple test to see if I could remember everything, and for the life of me I can't see why its not working.

In my view I have a textBox where its text property is bound to a value in the ViewModel. Then when pressing a button the value should be altered and the textBox update.

I can see the value does alter (I have added a MessageBox.Show() line in the buttom press command) however the textBox does not update.

I assume that this means I have not properly implemented the INotifyPropertyChanged event properly but am unable to see my mistake.

Could anyone point me in the right direction?

Here is the code:

View

<Window x:Class="Mvvm.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    <TextBox Height="40" Width="200" Text="{Binding helloWorld.Message, UpdateSourceTrigger=PropertyChanged}"/>
    <Button Command="{Binding UpdateTimeCommand}">Update</Button>
</StackPanel>
</Window>

Behind View

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel.MainWindowViewModel();
    }
}

ViewModel

namespace Mvvm.ViewModel
{
internal class MainWindowViewModel
{
    private HelloWorld _helloWorld;

    /// <summary>
    /// Creates a new instance of the ViewModel Class
    /// </summary>
    public MainWindowViewModel()
    {
        _helloWorld = new HelloWorld("The time is " + DateTime.Now.ToString("HH:mm:ss"));
        UpdateTimeCommand = new Commands.UpdateTimeCommand(this);
    }

    /// <summary>
    /// Gets the HellowWorld instance
    /// </summary>
    public HelloWorld helloWorld
    {
        get
        {
            return _helloWorld;
        }
        set
        {
            _helloWorld = value;
        }
    }

    /// <summary>
    /// Updates the time shown in the helloWorld 
    /// </summary>
    public void UpdateTime()
    {
        helloWorld = new HelloWorld("The time is " + DateTime.Now.ToString("HH:mm:ss"));
    }

    public ICommand UpdateTimeCommand
    {
        get;
        private set;
    }
}

Model

namespace Mvvm.Model
{
    class HelloWorld : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public HelloWorld(string helloWorldMessage)
        {
            Message = "Hello World! " + helloWorldMessage;
        }

        private string _Message;
        public string Message
        {
            get
            {
                return _Message;
            }
            set
            {
                _Message = value;
                OnPropertyChanged("Message");
            }
        }

        private void OnPropertyChanged(string p)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(p));
            }
        }
    }
}

Commands

namespace Mvvm.Commands
{
    internal class UpdateTimeCommand : ICommand
    {
        private ViewModel.MainWindowViewModel _viewModel;
        public UpdateTimeCommand(ViewModel.MainWindowViewModel viewModel)
        {
            _viewModel = viewModel;
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _viewModel.UpdateTime();
        }
    }
}

Sorry for such a long post and it being a spot my mistake post but I've looked at it for so long and I don't know what I'm doing wrong

Thanks!

The Problem that you have is that you are changing the wrong Property. Instead of changing the HelloWorld.Message Property, you are changing MainWindowViewModel.HelloWorld property. Your code will work OK if you change this line:

public void UpdateTime()
{
    helloWorld = new HelloWorld("The time is " + DateTime.Now.ToString("HH:mm:ss"));
}

For this one

public void UpdateTime()
{
    helloWorld.Message = "The time is " + DateTime.Now.ToString("HH:mm:ss");
}

If you want to keep your original code, then you need to implement INotifyPropertyChanged for your ViewModel, and rise the event when you change helloWorld object.

Hope this helps

I think you need to implement PropertyChanged notification on your ViewModel. You are creating a new HelloWorld in the UpdateTime method, but the UI doesn't know it.

Edit

I have a ViewModel base class which I derive all of my ViewModels from. It implements INotifyPropertyChanged, and has references to my relay command classes, and some other common stuff. I recommend always having INotifyPropertyChanged implemented on the ViewModel. The ViewModel is there to expose data to the UI, and it cant do that for data that changes without that interface.

我认为您的ViewModel也需要实现INotifyPropertyChanged,或者您可以在调用InitializeComponents()之前设置DataContext,如果这样做,您应该将代码更改为不创建每个更新的新实例,如Agustin Meriles所说。

  1. i think you mistake Model and VM: Model is MainWindowViewModel and VM is HelloWorld
  2. In your VM (class HelloWorld ) you need use your model

    So, your classes will look like:

      using System.ComponentModel; namespace WpfApplication1 { public sealed class TextVM : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private TextInfo _info; public TextVM() { _info = new TextInfo(); } public string MyText { get { return _info.MyText; } set { _info.MyText = value; OnPropertyChanged("MyText"); } } private void OnPropertyChanged(string p) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(p)); } } } } using System; namespace WpfApplication1 { public sealed class TextInfo { public TextInfo() { MyText = String.Empty; } public string MyText { get; set; } } } 

inset inside your ICommands

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