2012-12-06 127 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