2014-03-07 2 views
9

Ich habe einen Datenkontext (UserPreferences), der meinem Hauptfenster zugeordnet ist, und ein Textfeld, das im Kontext eine bidirektionale Bindung an eine Eigenschaft innerhalb einer der Datenkontexteigenschaften (CollectionDevice) herstellt.WPF-Zweiwege-Bindung funktioniert nicht

Wenn das Fenster geladen wird, binden die Textfelder nicht an die Eigenschaften in meinem Modell. Ich verifiziere innerhalb des Debuggers, dass der Datenkontext auf das Modellobjekt eingestellt ist und die Eigenschaften des Modells korrekt zugewiesen sind. Alles, was ich bekomme, sind jedoch eine Reihe von Textfeldern mit Nullen.

Wenn ich die Daten in die Textfelder eingabe, werden die Daten im Modell aktualisiert. Das Problem tritt nur auf, wenn ich die Daten lade und sie auf den Datenkontext anwende. Das Textfeld wird nicht aktualisiert.

Wenn ich das Modell in der Datenbank speichern, werden die richtigen Daten aus dem Textfeld gespeichert. Wenn ich das Modell von der Datenbank wiederherstelle, werden die richtigen Daten angewendet. Wenn das Modell auf den Datenkontext in meinem Konstruktor angewendet wird, enthält der Datenkontext des Textfelds die korrekten Daten und die Eigenschaften werden so zugewiesen, wie sie sein sollten. Das Problem ist, dass die Benutzeroberfläche dies nicht widerspiegelt.

XAML

<Window.DataContext> 
    <models:UserPreferences /> 
</Window.DataContext> 

     <!-- Wrap pannel used to store the manual settings for a collection device. --> 
     <StackPanel Name="OtherCollectionDevicePanel"> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock VerticalAlignment="Center" Margin="10, 10, 0, 0" Text="Baud Rate" /> 
       <TextBox Name="BaudRateTextBox" Text="{Binding Path=SelectedCollectionDevice.BaudRate, Mode=TwoWay}" Margin="10, 10, 0, 0" MinWidth="80" ></TextBox> 
      </StackPanel> 
      <WrapPanel> 
       <TextBlock VerticalAlignment="Center" Margin="10, 10, 0, 0" Text="Com Port" /> 
       <TextBox Text="{Binding Path=SelectedCollectionDevice.ComPort, Mode=TwoWay}" Margin="10, 10, 0, 0" MinWidth="80" ></TextBox> 
      </WrapPanel> 
      <WrapPanel> 
       <TextBlock VerticalAlignment="Center" Margin="10, 10, 0, 0" Text="Data Points" /> 
       <TextBox Text="{Binding Path=SelectedCollectionDevice.DataPoints, Mode=TwoWay}" Margin="10, 10, 0, 0" MinWidth="80" ></TextBox> 
      </WrapPanel> 
      <WrapPanel Orientation="Horizontal"> 
       <TextBlock VerticalAlignment="Center" Margin="10, 10, 0, 0" Text="WAAS" /> 
       <CheckBox IsChecked="{Binding Path=SelectedCollectionDevice.WAAS, Mode=TwoWay}" Content="Enabled" Margin="20, 0, 0, 0" VerticalAlignment="Bottom"></CheckBox> 
      </WrapPanel> 
     </StackPanel> 

Modell < - Datacontext.

/// <summary> 
/// Provides a series of user preferences. 
/// </summary> 
[Serializable] 
public class UserPreferences : INotifyPropertyChanged 
{ 
    private CollectionDevice selectedCollectionDevice; 

    public UserPreferences() 
    { 
     this.AvailableCollectionDevices = new List<CollectionDevice>(); 

     var yuma1 = new CollectionDevice 
     { 
      BaudRate = 4800, 
      ComPort = 31, 
      DataPoints = 1, 
      Name = "Trimble Yuma 1", 
      WAAS = true 
     }; 

     var yuma2 = new CollectionDevice 
     { 
      BaudRate = 4800, 
      ComPort = 3, 
      DataPoints = 1, 
      Name = "Trimble Yuma 2", 
      WAAS = true 
     }; 

     var toughbook = new CollectionDevice 
     { 
      BaudRate = 4800, 
      ComPort = 3, 
      DataPoints = 1, 
      Name = "Panasonic Toughbook", 
      WAAS = true 
     }; 


     var other = new CollectionDevice 
     { 
      BaudRate = 0, 
      ComPort = 0, 
      DataPoints = 0, 
      Name = "Other", 
      WAAS = false 
     }; 

     this.AvailableCollectionDevices.Add(yuma1); 
     this.AvailableCollectionDevices.Add(yuma2); 
     this.AvailableCollectionDevices.Add(toughbook); 
     this.AvailableCollectionDevices.Add(other); 

     this.SelectedCollectionDevice = this.AvailableCollectionDevices.First(); 
    } 

    /// <summary> 
    /// Gets or sets the GPS collection device. 
    /// </summary> 
    public CollectionDevice SelectedCollectionDevice 
    { 
     get 
     { 
      return selectedCollectionDevice; 
     } 
     set 
     { 
      selectedCollectionDevice = value; 
      this.OnPropertyChanged("SelectedCollectionDevice"); 
     } 
    } 

    /// <summary> 
    /// Gets or sets a collection of devices that can be used for collecting GPS data. 
    /// </summary> 
    [Ignore] 
    [XmlIgnore] 
    public List<CollectionDevice> AvailableCollectionDevices { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Notifies objects registered to receive this event that a property value has changed. 
    /// </summary> 
    /// <param name="propertyName">The name of the property that was changed.</param> 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

CollectionDevice < - Wo Textfeld bindet an.

/// <summary> 
/// CollectionDevice model 
/// </summary> 
[Serializable] 
public class CollectionDevice : INotifyPropertyChanged 
{ 
    /// <summary> 
    /// Gets or sets the COM port. 
    /// </summary> 
    private int comPort; 

    /// <summary> 
    /// Gets or sets a value indicating whether [waas]. 
    /// </summary> 
    private bool waas; 

    /// <summary> 
    /// Gets or sets the data points. 
    /// </summary> 
    private int dataPoints; 

    /// <summary> 
    /// Gets or sets the baud rate. 
    /// </summary> 
    private int baudRate; 

    /// <summary> 
    /// Gets or sets the name. 
    /// </summary> 
    public string Name { get; set; } 

    /// <summary> 
    /// Gets or sets the COM port. 
    /// </summary> 
    public int ComPort 
    { 
     get 
     { 
      return this.comPort; 
     } 

     set 
     { 
      this.comPort= value; 
      this.OnPropertyChanged("ComPort"); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the COM port. 
    /// </summary> 
    public bool WAAS 
    { 
     get 
     { 
      return this.waas; 
     } 

     set 
     { 
      this.waas = value; 
      this.OnPropertyChanged("WAAS"); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the COM port. 
    /// </summary> 
    public int DataPoints 
    { 
     get 
     { 
      return this.dataPoints; 
     } 

     set 
     { 
      this.dataPoints = value; 
      this.OnPropertyChanged("DataPoints"); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the COM port. 
    /// </summary> 
    public int BaudRate 
    { 
     get 
     { 
      return this.baudRate; 
     } 

     set 
     { 
      this.baudRate = value; 
      this.OnPropertyChanged("BaudRate"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Notifies objects registered to receive this event that a property value has changed. 
    /// </summary> 
    /// <param name="propertyName">The name of the property that was changed.</param> 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public override string ToString() 
    { 
     return this.Name; 
    } 
} 

Kann mir jemand in die richtige Richtung zeigen? Ich nehme an, das Problem ist meine Bindung in XAML; Ich kann es jedoch nicht finden. Ich benötige eine bidirektionale Bindung, da sich die Daten jederzeit während der Lebensdauer der App im Modell ändern können (die Datenbank wird über Synchronisationen aktualisiert), und die Benutzeroberfläche muss diese Änderungen widerspiegeln. Der Benutzer kann jedoch Änderungen am Modell vornehmen die Benutzeroberfläche.

Update 1

ich das Textfeld databind zu zwingen versucht, aktualisiert werden, aber das hat nicht so gut funktionieren.

BindingExpression be = this.BaudRateTextBox.GetBindingExpression(TextBox.TextProperty); 
be.UpdateSource(); 

Ich habe auch versucht die UpdateSourceTrigger zu PropertyChanged Einstellung und das schien nicht das Problem zu lösen.

<TextBox Name="BaudRateTextBox" Text="{Binding Path=SelectedCollectionDevice.BaudRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10, 10, 0, 0" MinWidth="80" ></TextBox> 

Update 2

habe ich versucht, mit einigen documentation from Microsoft zu folgen und es scheint nicht das Problem zu beheben. Die Werte bleiben weiterhin 0, wenn das Fenster geladen wird. Die Bindung wird nicht aktualisiert, nachdem ich den Status des Objekts aus der Datenbank wiederhergestellt habe. Die Bindung ist jedoch verdrahtet, weil, wenn ich Daten eingabe, der Datenkontext aktualisiert wird. Aus irgendeinem Grund verhält es sich wie One-Way, wenn ich es auf Two-Way eingestellt habe.

Update 3

Ich habe versucht, den Code in das Fenster geladen Ereignis und aus dem Konstruktor zu bewegen, aber das schien nicht zu helfen.Interessant ist, dass das PropertyChanged-Ereignis während des Deserialisierungsprozesses nicht ausgelöst wird. Ich denke nicht, dass es in diesem Fall wichtig ist, weil das Objekt vollständig wiederhergestellt ist und ich es dann einfach dem Datenkontext zuordne. Ich habe den Datenkontext aus dem XAML in den WindowLoaded verschoben, um zu testen, ob XAML das Problem war. Das Ergebnis war das gleiche.

private void WindowLoaded(object sender, RoutedEventArgs e) 
{ 
    // Restore our preferences state. 
    var preferences = new UserPreferenceCommands(); 
    Models.UserPreferences viewModel = new Models.UserPreferences(); 

    // Set up the event handler before we deserialize. 
    viewModel.PropertyChanged += viewModel_PropertyChanged; 
    preferences.LoadPreferencesCommand.Execute(viewModel); 

    // At this point, viewModel is a valid object. All properties are set correctly. 
    viewModel = preferences.Results; 

    // After this step, the UI still shows 0's in all of the text boxs. Even though the values are not zero. 
    this.DataContext = viewModel; 
} 

// NEVER gets fired from within the WindowLoaded event. 
void viewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    MessageBox.Show("Property changed!"); 
} 

// This changes the model properties and is immediately reflected in the UI. Why does this not happen within the WindowLoaded event? 
private void TestButtonClickEvent(object sender, RoutedEventArgs e) 
{ 
    var context = this.DataContext as Models.UserPreferences; 
    context.SelectedCollectionDevice.ComPort = 1536; 
} 

Update 4 - Problem identifiziert

ich das Problem identifiziert haben, müssen aber noch eine Auflösung. Der entscheidende Punkt der Datenbindung ist, dass ich diese manuelle Zuweisung nicht durchführen muss. Stimmt etwas nicht mit meinen INotify-Implementierungen?

private void WindowLoaded(object sender, RoutedEventArgs e) 
{ 
    // Restore our preferences state. 
    var preferences = new UserPreferenceCommands(); 
    Models.UserPreferences viewModel = new Models.UserPreferences(); 

    // Set up the event handler before we deserialize. 
    viewModel.PropertyChanged += viewModel_PropertyChanged; 
    preferences.LoadPreferencesCommand.Execute(viewModel); 

    // At this point, viewModel is a valid object. All properties are set correctly. 
    viewModel = preferences.Results; 

    // After this step, the UI still shows 0's in all of the text boxs. Even though the values are not zero. 
    this.DataContext = viewModel; 

    // SOLUTION: - Setting the actual property causes the UI to be reflected when the window is initialized; setting the actual data context does not. Why? Also note that I set this property and my PropertyChanged event handler still does not fire. 
    ((Models.UserPreferences) DataContext).SelectedCollectionDevice = viewModel.SelectedCollectionDevice; 

} 
+0

Der erste, was ich tun würde, ist die Veränderung 'List ' auf 'ObservableCollection ' – EkoostikMartin

+0

Es gibt sogar eine eigene Klasse I verwendet werden, die Updates Multi-Thread unterstützt: https://code.google.com /p/mutinyirc/source/browse/MvvmFoundation.Wpf/MTObservableCollection.cs Falls Sie es brauchen. –

+0

Dank @Ekoostik, der Grund, warum ich es nicht als beobachtbar gemacht habe, ist, weil es nicht beobachtet werden muss. Die Sammlung wird innerhalb des Objektkonstruktors eingerichtet und ändert sich nie. Es ist mit vorbestimmten Sammlungsgeräten gefüllt. Der letzte Eintrag ist ein Gerät, bei dem Name auf "Andere" gesetzt ist und der Benutzer dann benutzerdefinierte Daten eingeben kann. Aus diesem Grund wird das SelectedCollectionDevice beobachtet, nicht jedoch das AvailableCollectionDevice. –

Antwort

4

In Ordnung, ich war in der Lage, das Problem zu bestimmen und es gelöst zu bekommen. Es stellte sich heraus, dass es eine Zusammenstellung von Dingen war, die das verursachten.

Zuerst mein Modell.

UserPreferences < - MainWindow ist an diese Daten gebunden.

[Serializable] 
public class UserPreferences : INotifyPropertyChanged 
{ 
    private CollectionDevice selectedCollectionDevice; 

    public UserPreferences() 
    { 
     this.AvailableCollectionDevices = new List<CollectionDevice>(); 

     var yuma1 = new CollectionDevice 
     { 
      BaudRate = 4800, 
      ComPort = 31, 
      DataPoints = 1, 
      Name = "Trimble Yuma 1", 
      WAAS = true 
     }; 

     var yuma2 = new CollectionDevice 
     { 
      BaudRate = 4800, 
      ComPort = 3, 
      DataPoints = 1, 
      Name = "Trimble Yuma 2", 
      WAAS = true 
     }; 

     var toughbook = new CollectionDevice 
     { 
      BaudRate = 4800, 
      ComPort = 3, 
      DataPoints = 1, 
      Name = "Panasonic Toughbook", 
      WAAS = true 
     }; 


     var other = new CollectionDevice 
     { 
      BaudRate = 0, 
      ComPort = 0, 
      DataPoints = 0, 
      Name = "Other", 
      WAAS = false 
     }; 

     this.AvailableCollectionDevices.Add(yuma1); 
     this.AvailableCollectionDevices.Add(yuma2); 
     this.AvailableCollectionDevices.Add(toughbook); 
     this.AvailableCollectionDevices.Add(other); 

     this.SelectedCollectionDevice = this.AvailableCollectionDevices.First(); 
    } 

    /// <summary> 
    /// Gets or sets the GPS collection device. 
    /// </summary> 
    public CollectionDevice SelectedCollectionDevice 
    { 
     get 
     { 
      return selectedCollectionDevice; 
     } 
     set 
     { 
      selectedCollectionDevice = value; 

      if (selectedCollectionDevice.Name == "Other") 
      { 
       this.AvailableCollectionDevices[3] = value; 
      } 

      this.OnPropertyChanged("SelectedCollectionDevice"); 
     } 
    } 

    /// <summary> 
    /// Gets or sets a collection of devices that can be used for collecting GPS data. 
    /// </summary> 
    [Ignore] 
    [XmlIgnore] 
    public List<CollectionDevice> AvailableCollectionDevices { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Notifies objects registered to receive this event that a property value has changed. 
    /// </summary> 
    /// <param name="propertyName">The name of the property that was changed.</param> 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

In dem Setter für die SelectedCollectionDevice suchte ich nicht, ob das ausgewählte Gerät andere war zu sehen. Alle anderen Geräte (yuma1, panasonic usw.) haben vorab festgelegte Eigenschaftswerte, die niemals geändert werden. Wenn der Benutzer "Andere" auswählt, werden die Textfelder angezeigt und sie können die Daten manuell eingeben. Das Problem war, dass wenn die manuell eingegebenen Daten während des Ladens des Fensters aus der Datenbank wiederhergestellt wurden, ich die benutzerdefinierten Daten in SelectedCollectionDevice nicht dem entsprechenden Objekt in der Sammlung zuordnete.

Während des Ladens des Fensters wurde Combobox.SelectedItem auf den Index SelectedCollectionDevice gesetzt. Diewurde auf die AvailableCollectionDevices Sammlung gesetzt.

this.CollectionDevice.SelectedIndex = 
    viewModel.AvailableCollectionDevices.IndexOf(
     viewModel.AvailableCollectionDevices.FirstOrDefault(
      acd => acd.Name == viewModel.SelectedCollectionDevice.Name)); 

Wenn der obige Code ausgeführt wird, zieht das Kombinationsfeld das Standardobjekt aus seiner Datenquelle, die alle Werte auf Null gesetzt hat. Innerhalb des Ereignisses der Combobox SelectionChanged habe ich den Datenkontext SelectedCollectionDevice dem Null-Out-Element zugewiesen, das dem Kombinationsfeld zugeordnet ist.

private void CollectionDeviceSelected(object sender, SelectionChangedEventArgs e) 
{ 
    if (e.AddedItems.Count > 0 && e.AddedItems[0] is CollectionDevice) 
    { 
     // Assign the view models SelectedCollectionDevice to the device selected in the combo box. 
     var device = e.AddedItems[0] as CollectionDevice; 
     ((Models.UserPreferences)this.DataContext).SelectedCollectionDevice = device; 

     // Check if Other is selected. If so, we have to present additional options. 
     if (device.Name == "Other") 
     { 
      OtherCollectionDevicePanel.Visibility = Visibility.Visible; 
     } 
     else if (OtherCollectionDevicePanel.Visibility == Visibility.Visible) 
     { 
      OtherCollectionDevicePanel.Visibility = Visibility.Collapsed; 
     } 
    } 
} 

So lange Geschichte kurz, habe ich den Code oben in dem Setter für die SelectedCollectionDevice den Wert auf die AvailableCollectionDevices Liste <> anzuwenden. Wenn das Kombinationsfeld den Wert "Andere" ausgewählt hat, wird der Wert aus der Auflistung mit den richtigen Daten abgerufen. Während der Deserialisierung deserialisiere ich gerade die SelectedCollectionDevice und nicht die Liste <> weshalb die Daten beim ersten Laden des Fensters immer überschrieben wurden.

Dies erklärt auch, warum die Neuzuweisung des Datenkontexts SelectedCollectionDevice mit der lokalen viewModel.SelectedCollectionDevice funktionierte. Ich habe das zero-out-Objekt ersetzt, das dem Kombinationsfeld zugeordnet ist, das den Datenkontext während des Ereignisses SelectionChanged festgelegt hatte. Ich kann den DataContext nicht im XAML festlegen und die manuelle Zuweisung entfernen.

Vielen Dank für die Hilfe, es half mir, meine Fehlersuche einzuengen, bis ich das Problem endlich gelöst habe. Sehr geschätzt!

33

standardmäßig die Text Eigenschaft von TextBox wird nur dann aktualisiert, wenn der Fokus auf sie verloren geht. Dies ist das Standardverhalten. Haben Sie es mit Ihrem DataContext überprüft?

Wenn Sie dieses Verhalten außer Kraft setzen wollen, müssen Sie die Eigenschaft UpdateSourceTrigger auf diese Weise umfassen:

Text="{Binding Path=SelectedCollectionDevice.BaudRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} 

Einstellung UpdateSourceTrigger ‚s Wert PropertyChanged, wird die Änderung in dem Text reflektiert, wenn Sie den Wert ändern Ihrer gebundenen Eigenschaft, sobald sich der Text ändert. Ein nützliches Tutorial über die Verwendung von UpdateSourceTrigger Eigenschaft ist here.

+0

Ich hatte gerade mein OP aktualisiert, um zu erwähnen, dass ich das versucht hatte. Aus irgendeinem Grund wird der Text nicht auf die Eigenschaftswerte festgelegt, obwohl die Werte im Kontext vorhanden sind. Ich bin ratlos. Ich habe sogar eine harte Neuzuweisung des Datenkontexts mit this.txtBaudRate.DataContext = userPreferences durchgeführt; innerhalb des Sichtenkonstruktors (nachdem userPreferences deserialisiert wurde) und die Textfelder behalten den Wert 0. –

+0

@JohnathonSullinger Entschuldigung für meine späte Antwort! Ich bin froh, dass du es repariert hast! –

+2

+1 Die Einfachheit und hohe Generalisierung dieser Antwort hat mir geholfen. Ich wollte das Standardverhalten und hatte einfach '{Binding MyProp}', musste aber 'Mode' explizit auf' TwoWay' und 'UpdateSourceTrigger' auf' LostFocus' setzen. – Assimilater

2

keine Antwort, sondern wollten den Code schreiben, der auf meiner Maschine arbeitet OP zu helfen ...

komplette XAML Seite ...

<Window x:Class="WpfApplication1.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <StackPanel Name="OtherCollectionDevicePanel"> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock VerticalAlignment="Center" 
          Margin="10, 10, 0, 0" 
          Text="Baud Rate" /> 
       <TextBox Name="BaudRateTextBox" 
         Text="{Binding Path=SelectedCollectionDevice.BaudRate, Mode=TwoWay}" 
         Margin="10, 10, 0, 0" 
         MinWidth="80"></TextBox> 
      </StackPanel> 
      <WrapPanel> 
       <TextBlock VerticalAlignment="Center" 
          Margin="10, 10, 0, 0" 
          Text="Com Port" /> 
       <TextBox Text="{Binding Path=SelectedCollectionDevice.ComPort, Mode=TwoWay}" 
         Margin="10, 10, 0, 0" 
         MinWidth="80"></TextBox> 
      </WrapPanel> 
      <WrapPanel> 
       <TextBlock VerticalAlignment="Center" 
          Margin="10, 10, 0, 0" 
          Text="Data Points" /> 
       <TextBox Text="{Binding Path=SelectedCollectionDevice.DataPoints, Mode=TwoWay}" 
         Margin="10, 10, 0, 0" 
         MinWidth="80"></TextBox> 
      </WrapPanel> 
      <WrapPanel Orientation="Horizontal"> 
       <TextBlock VerticalAlignment="Center" 
          Margin="10, 10, 0, 0" 
          Text="WAAS" /> 
       <CheckBox IsChecked="{Binding Path=SelectedCollectionDevice.WAAS, Mode=TwoWay}" 
          Content="Enabled" 
          Margin="20, 0, 0, 0" 
          VerticalAlignment="Bottom"></CheckBox> 
      </WrapPanel> 
      <Button Click="ButtonBase_OnClick" Content="Set ComPort to 11"></Button> 
     </StackPanel> 
    </Grid> 
</Window> 

kompletten Code hinter ...

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Windows; 
using System.Xml.Serialization; 

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
      DataContext = new UserPreferences(); 
     } 

     private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
     { 
      ((UserPreferences) DataContext).SelectedCollectionDevice.ComPort = 11; 
     } 

    } 

    /// <summary> 
    /// Provides a series of user preferences. 
    /// </summary> 
    [Serializable] 
    public class UserPreferences : INotifyPropertyChanged 
    { 
     private CollectionDevice selectedCollectionDevice; 

     public UserPreferences() 
     { 
      this.AvailableCollectionDevices = new List<CollectionDevice>(); 

      var yuma1 = new CollectionDevice 
      { 
       BaudRate = 4800, 
       ComPort = 31, 
       DataPoints = 1, 
       Name = "Trimble Yuma 1", 
       WAAS = true 
      }; 

      var yuma2 = new CollectionDevice 
      { 
       BaudRate = 4800, 
       ComPort = 3, 
       DataPoints = 1, 
       Name = "Trimble Yuma 2", 
       WAAS = true 
      }; 

      var toughbook = new CollectionDevice 
      { 
       BaudRate = 4800, 
       ComPort = 3, 
       DataPoints = 1, 
       Name = "Panasonic Toughbook", 
       WAAS = true 
      }; 


      var other = new CollectionDevice 
      { 
       BaudRate = 0, 
       ComPort = 0, 
       DataPoints = 0, 
       Name = "Other", 
       WAAS = false 
      }; 

      this.AvailableCollectionDevices.Add(yuma1); 
      this.AvailableCollectionDevices.Add(yuma2); 
      this.AvailableCollectionDevices.Add(toughbook); 
      this.AvailableCollectionDevices.Add(other); 

      this.SelectedCollectionDevice = this.AvailableCollectionDevices.First(); 
     } 

     /// <summary> 
     /// Gets or sets the GPS collection device. 
     /// </summary> 
     public CollectionDevice SelectedCollectionDevice 
     { 
      get 
      { 
       return selectedCollectionDevice; 
      } 
      set 
      { 
       selectedCollectionDevice = value; 
       this.OnPropertyChanged("SelectedCollectionDevice"); 
      } 
     } 

     /// <summary> 
     /// Gets or sets a collection of devices that can be used for collecting GPS data. 
     /// </summary> 
     [XmlIgnore] 
     public List<CollectionDevice> AvailableCollectionDevices { get; set; } 

     public event PropertyChangedEventHandler PropertyChanged; 

     /// <summary> 
     /// Notifies objects registered to receive this event that a property value has changed. 
     /// </summary> 
     /// <param name="propertyName">The name of the property that was changed.</param> 
     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      if (this.PropertyChanged != null) 
      { 
       this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 

    /// <summary> 
    /// CollectionDevice model 
    /// </summary> 
    [Serializable] 
    public class CollectionDevice : INotifyPropertyChanged 
    { 
     /// <summary> 
     /// Gets or sets the COM port. 
     /// </summary> 
     private int comPort; 

     /// <summary> 
     /// Gets or sets a value indicating whether [waas]. 
     /// </summary> 
     private bool waas; 

     /// <summary> 
     /// Gets or sets the data points. 
     /// </summary> 
     private int dataPoints; 

     /// <summary> 
     /// Gets or sets the baud rate. 
     /// </summary> 
     private int baudRate; 

     /// <summary> 
     /// Gets or sets the name. 
     /// </summary> 
     public string Name { get; set; } 

     /// <summary> 
     /// Gets or sets the COM port. 
     /// </summary> 
     public int ComPort 
     { 
      get 
      { 
       return this.comPort; 
      } 

      set 
      { 
       this.comPort = value; 
       this.OnPropertyChanged("ComPort"); 
      } 
     } 

     /// <summary> 
     /// Gets or sets the COM port. 
     /// </summary> 
     public bool WAAS 
     { 
      get 
      { 
       return this.waas; 
      } 

      set 
      { 
       this.waas = value; 
       this.OnPropertyChanged("WAAS"); 
      } 
     } 

     /// <summary> 
     /// Gets or sets the COM port. 
     /// </summary> 
     public int DataPoints 
     { 
      get 
      { 
       return this.dataPoints; 
      } 

      set 
      { 
       this.dataPoints = value; 
       this.OnPropertyChanged("DataPoints"); 
      } 
     } 

     /// <summary> 
     /// Gets or sets the COM port. 
     /// </summary> 
     public int BaudRate 
     { 
      get 
      { 
       return this.baudRate; 
      } 

      set 
      { 
       this.baudRate = value; 
       this.OnPropertyChanged("BaudRate"); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     /// <summary> 
     /// Notifies objects registered to receive this event that a property value has changed. 
     /// </summary> 
     /// <param name="propertyName">The name of the property that was changed.</param> 
     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      if (this.PropertyChanged != null) 
      { 
       this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public override string ToString() 
     { 
      return this.Name; 
     } 
    } 
} 
+0

Ich nahm meinen Code und passte ihn so an, dass der Datenkontext erstellt wurde innerhalb des Konstruktors wie Ihres, um ein XAML-Problem mit meinem Kontext auszuschließen. Das Problem ging weiter. Ich kann Änderungen vornehmen, nachdem das Fenster initialisiert wurde und sie auf der Benutzeroberfläche angezeigt werden. Alle Änderungen an meinem Objekt vor dem Verlassen des Konstruktors werden jedoch nicht auf der Benutzeroberfläche angezeigt. –

+0

Ich habe auch meine Wiederherstellungscode- und Wertzuweisungen aus dem Konstruktor in das Loaded-Ereignis für das Fenster verschoben, um zu sehen, ob es nur ein Problem mit dem Timing war. Am Ende des Loaded-Ereignisses weise ich das gültige Objekt dem Datenkontext zu und die Benutzeroberfläche zeigt nur noch Nullen an. –

+0

Ich sehe ... Ich habe gerade erwähnt, dass Sie versuchen konnten, die Eigenschaften außerhalb der Seiten zu ändern ... aber dann sah ich diesen Kommentar und löschte meinen Kommentar oben. – Kevin

0

Ich hatte das gleiche Problem. Mein Problem war bindende Eigenschaft Name war falsch. Wenn Sie das Ausgabefenster betrachten, können Sie während der Laufzeit alle Bindungsfehler sehen.

System.Windows.Data Error: 40 : BindingExpression path error: 'SelectedProtectedWebsiteTemplate' property not found on 'object' ''ProtectedWebsitesViewModel' (HashCode=32764015)'. BindingExpression:Path=SelectedProtectedWebsiteTemplate.Name; DataItem='ProtectedWebsitesViewModel' (HashCode=32764015); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')