2012-12-06 14 views
5

Ich bin gerade erst mit MVVM so Entschuldigungen, wenn ich etwas wirklich dummes getan habe. Ich habe versucht, einen sehr einfachen Test zu schreiben, um zu sehen, ob ich mich an alles erinnern kann, und für das Leben von mir kann ich nicht sehen, warum es nicht funktioniert.WPF MVVM TextBox Textbindung

Meiner Ansicht nach habe ich eine TextBox, deren Texteigenschaft an einen Wert im ViewModel gebunden ist. Dann sollte beim Drücken einer Taste der Wert geändert und die textBox aktualisiert werden.

Ich kann sehen, der Wert ändert sich (Ich habe eine MessageBox.Show() Zeile in den Tastendruck Befehl) jedoch die TextBox nicht aktualisiert.

Ich nehme an, dass dies bedeutet, dass ich das Ereignis INotifyPropertyChanged nicht korrekt implementiert habe, aber nicht in der Lage bin, meinen Fehler zu sehen.

Kann mir jemand in die richtige Richtung zeigen? Hier

ist der Code:

Ansicht

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

Hinter Ansicht

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

Ansichtsmodell

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

Modell

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

Befehle

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 für einen so langen Pfosten und es eine Stelle, mein Fehler Post zu sein, aber ich habe so lange es sah, und ich weiß nicht, was ich falsch mache

Danke!

+0

Ich nehme an, dass Sie auch eine Property Change-Benachrichtigung für die Eigenschaft "helloWorld" benötigen, da Sie den Bindungspfad 'helloWorld.Message' verwenden. –

Antwort

6

Das Problem, das Sie haben, ist, dass Sie die falsche Eigenschaft ändern. Anstatt die Eigenschaft HelloWorld.Message zu ändern, ändern Sie die Eigenschaft MainWindowViewModel.HelloWorld. Ihr Code wird OK funktionieren, wenn Sie diese Zeile ändern:

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

Für diesen einen

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

Wenn Sie Ihren ursprünglichen Code behalten wollen, dann müssen Sie INotifyPropertyChanged für Ihre Ansichtsmodell implementieren, und steigen die Ereignis, wenn Sie helloWorld Objekt ändern.

hoffe, das hilft

+0

Ja, das funktioniert jetzt. Das hätte eigentlich ziemlich offensichtlich sein sollen. Nicht sicher VMMV ist alles, was es ist, um zu sein: P. Ist es akzeptabel, eine Eigenschaftsänderung im ViewModel zu implementieren? –

+0

@PetePetersen der Ansicht-Modell ist eigentlich, wo INotifyPropertyChanged in erster Linie umgesetzt werden muss! Denken Sie daran, dass der View-Modell der Klasse ist, zu dem Sie die Benutzeroberfläche und diese während des Bindungsprozesses binden, die die Benutzeroberfläche der Lage ist, auf die Ereignisse Ihrer Ansicht-Modell zum suscribe. – Ucodia

+1

mehr als in einem Modell;) sollten Sie immer implementieren INotifyPropertyChanged in den Klassen, die Sie binden sind, sonst kann es in memoryleaks führen. http://code.logos.com/blog/2008/10/detecting_bindings_that_should_be_onetime.html – blindmeis

2

Ich glaube, Sie Property Benachrichtigung auf Ihrem Ansichtsmodell implementieren müssen. Sie erstellen ein neues HelloWorld in der UpdateTime-Methode, aber die Benutzeroberfläche weiß es nicht.

bearbeiten

Ich habe ein Ansichtsmodell Basisklasse, die ich von allen meinen Viewmodels ableiten. Es implementiert INotifyPropertyChanged und enthält Verweise auf meine Relay-Befehlsklassen und einige andere allgemeine Dinge. Ich empfehle immer INotifyPropertyChanged auf dem ViewModel implementiert zu haben. Das ViewModel dient dazu, Daten für die Benutzeroberfläche verfügbar zu machen, und dies kann nicht für Daten verwendet werden, die sich ohne diese Schnittstelle ändern.

+0

Diese Implementierung wäre definitiv besser, wenn die Änderungsbenachrichtigung auf der VM implementiert ist, selbst wenn das Modell sie bereits implementiert. – Ucodia

+0

In der Tat. Die Idee hinter einem ViewModel ist, eine Klasse zu haben, die Daten an die View liefert, so dass die View sie besser nutzen kann. Auch wenn die angezeigten Daten wie Text (in diesem Fall HelloWorld.Message) nicht direkt von dem Ansichtsmodell dient, schließlich ist es wahrscheinlich, dass andere Eigenschaften dort ausgesetzt werden, Bürsten, sichtbare Zustände etc. – CodeWarrior

1

Ich denke Ihr ViewModel muss auch INotifyPropertyChanged implementieren, oder Sie können den DataContext vor dem Aufruf von InitializeComponents() setzen, wenn Sie das tun, sollten Sie Ihren Code ändern, um keine neue Instanz jedes Update wie Agustin Meriles zu erstellen.

1
  1. Ich glaube, Sie Fehler Modell und VM: Modell MainWindowViewModel ist und VM ist Hello World
  2. In Ihrer VM (Klasse Hello World) Sie Ihr Modell

    So verwenden müssen, wird sich Ihre Klassen wie:

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

in Ihrem ICommands Einschub