2010-06-16 15 views
6

Ich habe eine TextBox, dessen Wert auf eine Ansichtsmodell Eigenschaft binded ist:WPF TextBox Wert ändert auf OnPropertyChanged nicht

 <TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding Mode=TwoWay, Path=RunAfter}" Style="{StaticResource TestStepTextBox}"/> 

Das Set und erhalten funktioniert gut, bis ich einige Validierung hinzuzufügen versuchte, wenn der Wert set:

private int _runAfter = 0; 
    public string RunAfter 
    { 
     get 
     { 
      return _runAfter.ToString(); 
     } 

     set 
     { 
      int val = int.Parse(value); 

      if (_runAfter != val) 
      { 
       if (val < _order) 
        _runAfter = val; 
       else 
       { 
        _runAfter = 0; 
        OnPropertyChanged("RunAfter"); 
       } 
      } 
     } 
    } 

Obwohl die OnPropertyChanged erreicht ist (ich habe dubugged dass) wird die Ansicht nicht geändert. Wie kann ich das machen?

Danke, José Tavares

Antwort

5

Das Problem ist, dass Sie die Quelle für die Binding aktualisieren, während die Binding Ihre Eigenschaft aktualisiert. WPF wird Ihren Eigenschaftswert nicht überprüfen, wenn das Ereignis PropertyChanged als Reaktion auf ein Update Binding ausgelöst wird. Sie können dieses Problem lösen, indem Sie die Dispatcher mit der Ausbreitung der Veranstaltung in diesem Zweig zu verzögern:

set 
{ 
    int val = int.Parse(value); 

    if (_runAfter != val) 
    { 
     if (val < _order) 
     { 
      _runAfter = val; 
      OnPropertyChanged("RunAfter"); 
     } 
     else 
     { 
      _runAfter = 0; 
      Dispatcher.CurrentDispatcher.BeginInvoke(
       new Action<String>(OnPropertyChanged), 
       DispatcherPriority.DataBind, "RunAfter"); 
     } 
    } 
} 

Update:

Das andere, was mir aufgefallen ist, dass die Binding auf TextBox wird mit dem Standard UpdateSourceTrigger, was passiert, wenn der TextBox Fokus verliert. Der Text wird erst dann wieder in 0 angezeigt, wenn die TextBox den Fokus in diesem Modus verliert. Wenn Sie es in PropertyChanged ändern, sehen Sie dies sofort. Andernfalls wird die Eigenschaft nicht festgelegt werden, bis Ihr TextBox Fokus verliert:

<TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding RunAfter, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource TestStepTextBox}"/> 
+0

Ich denke, Ihre Einschätzung des Problems ist richtig, aber der Dispatcher Anruf funktioniert nicht. Mein UserControl wird in einer WinForm-Anwendung mit einem ElementHost verwendet. Kann dies den Dispatcher-Aufruf beeinflussen? – jpsstavares

+0

Okay, ich habe das ausprobiert und es hat gut funktioniert (wenn Sie die TextBox weglassen, da der Standardmodus der Bindung die Eigenschaft nicht aktualisiert, bis die TextBox den Fokus verliert). Ich habe die Antwort aktualisiert, um den UpdateSourceTrigger für die Bindungen zu erklären, falls das das Verhalten ist, das Sie sehen. Ich behandle nicht viel mit WPF, das in WinForms gehostet wird, aber ich sehe nicht, warum das den Binding oder Dispatcher in Ihrem Kontext betrifft. –

3

Ein paar Dinge, die ich hier bemerkt.

Wenn Sie keinen zwingenden Grund haben, die RunAfter-Eigenschaft als Zeichenfolge anzugeben, gibt es keinen Grund, warum es kein int sein kann. Das würde dir die Besetzung im Setter ersparen (sowie eine lauernde mögliche InvalidCastException, wenn der Benutzer etwas nicht ganzzahliges in das Feld eingibt).

Zweitens, die OnPropertyChanged() -Aufruf außerhalb des inneren if-Anweisung erfolgen soll, wie die folgenden:

if(_runAfter != val) 
{ 
    if(val < _order) 
     _runAfter = val; 
    else 
     _runAfter = 0; 
    OnPropertyChanged("RunAfter"); 
} 

Da die _runAfter lokale in beiden Pfaden der bedingten aktualisiert wird, die OnPropertyChanged() hat unabhängig von der gewählten Verzweigung aufgerufen werden. Ich hoffe, dass hilft Ihnen in die richtige Richtung!

+0

+1 für Hinweis darauf, dass Sie die OnPropertyChanged außerhalb des sonst bewegen müssen. – Robaticus

+0

Nun, die Menge wird von der View (via Bindung) aufgerufen, also dachte ich, es wäre nur notwendig, OnPropertyChanged aufzurufen, wenn der Wert von dem in der View gesetzten Wert geändert würde. – jpsstavares

+0

Wie auch immer, das hat mein Problem nicht gelöst ... – jpsstavares

1

ich die gleiche Situation hatte. Ich schrieb folgendes und es funktionierte.

<TextBox Grid.Column="3" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Text="{Binding Path=FirstName}"></TextBox>

Und

public string FirstName 
    { 
     get { return _client.FirstName; } 
     set 
     { 
      if (value == _client.FirstName) 
       return; 
      else 
       _client.FirstName = value; 
      OnPropertyChanged("FirstName"); 
     } 
    }