2012-12-06 131 views
5

我刚刚开始使用MVVM,所以如果我已经做了一些非常愚蠢的事情,请致歉。我试着写一个非常简单的测试,看看我能否记得所有的东西,而对于我的生活,我不明白为什么它不工作。WPF MVVM textBox文本绑定

在我看来,我有一个textBox,其文本属性绑定到ViewModel中的值。然后当按下一个按钮时,该值应该被改变,文本框更新。

我可以看到值改变(我在buttom按下命令中添加了一个MessageBox.Show()行),但是textBox不更新。

我认为这意味着我没有正确实施INotifyPropertyChanged事件,但无法看到我的错误。

任何人都可以指向正确的方向吗?

下面是代码:

查看

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

查看

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

视图模型

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; 
    } 
} 

型号

背后
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)); 
      } 
     } 
    } 
} 

命令

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(); 
     } 
    } 
} 

对不起,这么长的帖子,并将其作为一个点我的错误后,但我看过了这么久,我不知道我做错了什么

谢谢!

+0

我想你还需要在'helloWorld'属性上有一个属性更改通知,因为你正在使用绑定路径'helloWorld.Message'。 – 2012-12-06 14:46:32

回答

6

您遇到的问题是您正在更改错误的属性。而不是更改HelloWorld.Message属性,您正在更改MainWindowViewModel.HelloWorld属性。您的代码将工作OK,如果你改变这一行:如果你想保持你原来的代码

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

对于这一个

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

,那么你需要执行INotifyPropertyChanged您的视图模型,并上升事件当你改变helloWorld对象。

希望这有助于

+0

是的,现在的作品。这应该是非常明显的。不确定VMMV是否被破解为:P。在ViewModel中实现属性更改是否可以接受? –

+0

@PetePetersen视图模型实际上是INotifyPropertyChanged必须首先实现的地方!请记住,视图模型是您将在绑定过程中绑定UI的类,它可以适用于您的视图模型的事件。 – Ucodia

+1

更多然后在模型中;)您应该始终在您绑定到的类中实现INotifyPropertyChanged,否则可能导致内存泄漏。 http://code.logos.com/blog/2008/10/detecting_bindings_that_should_be_onetime.html – blindmeis

2

我认为你需要实现您的视图模型的PropertyChanged通知。您正在UpdateTime方法中创建新的HelloWorld,但UI不知道它。

编辑

我有一个ViewModel基类派生我所有我的ViewModels从。它实现INotifyPropertyChanged,并且引用了我的中继命令类以及其他一些常见的东西。我建议始终在ViewModel上实施INotifyPropertyChanged。 ViewModel在那里向用户界面公开数据,并且它无法为没有该界面的情况下更改的数据做到这一点。

+0

即使模型已经实现了该实现,在VM上实现更改通知的情况下,该实现肯定会更好。 – Ucodia

+0

确实。拥有ViewModel的想法是有一个向View提供数据的类,以便视图可以更好地使用它。即使显示的数据像文本(在这种情况下,HelloWorld.Message)不是由ViewModel直接提供的,最终很可能其他属性会暴露在那里,刷子,可见状态等等。 – CodeWarrior

1

我觉得你的ViewModel需要执行INotifyPropertyChanged也 也可以设置在DataContext调用InitializeComponents(前),如果你这样做,你应该改变你的代码不创建一个新的实例像奥古斯丁Meriles每次更新说。

1
  1. 我认为你错模型与虚拟机:型号是MainWindowViewModel和VM是HelloWorld的
  2. 在你的虚拟机(类的HelloWorld),你需要用你的模型

    所以,你的类将是这样的:

    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; } 
        } 
    } 
    

您的插图里个ICommand