2010-06-16 18 views
6

Tengo un cuadro de texto cuyo valor se aglutinaba a un modelo de vista de la propiedad:valor de TextBox de WPF no cambia en OnPropertyChanged

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

El conjunto y se les estaban trabajando bien hasta que he intentado añadir un poco de validación cuando el valor es 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"); 
       } 
      } 
     } 
    } 

Aunque se alcanza el OnPropertyChanged (he dubugged eso), la vista no se cambia. ¿Cómo puedo hacer que esto funcione?

Gracias, José Tavares

Respuesta

5

El problema es que está actualizando la fuente para el Binding mientras que el Binding está actualizando su propiedad. WPF en realidad no verificará el valor de su propiedad cuando se produzca el evento PropertyChanged en respuesta a una actualización Binding. Puede resolver esto mediante el uso de la Dispatcher para retrasar la propagación del evento en esa rama:

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

Actualización:

La otra cosa que he notado es que la Binding en su TextBox es usar el valor por defecto UpdateSourceTrigger, que ocurre cuando el TextBox pierde el foco. No verá que el texto vuelva a cambiar a 0 hasta que TextBox pierda el foco con este modo. Si lo cambia a PropertyChanged, verá que esto sucederá de inmediato. De lo contrario, su propiedad no conseguirá establecer hasta que su TextBox pierde el foco:

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

Supongo que su evaluación del problema es correcta, pero la llamada del operador no funciona. Mi UserControl se usa dentro de una aplicación WinForm usando ElementHost. ¿Esto puede afectar la llamada de Dispatcher? – jpsstavares

+0

De acuerdo, probé esto y funcionó bien (cuando se aleja del TextBox como el modo predeterminado de la vinculación no actualizará la propiedad hasta que TextBox pierda el foco). Actualicé la respuesta para explicar sobre UpdateSourceTrigger en los enlaces, en caso de que ese sea el comportamiento que estás viendo. No trato mucho con WPF alojado en WinForms, pero no veo por qué eso afectaría a Binding o Dispatcher en su contexto. –

3

Algunas cosas que noté aquí.

A menos que tenga una razón de peso para exponer la propiedad RunAfter como una cadena, no hay ninguna razón por la cual no pueda ser una int. Eso te ahorraría el yeso en el setter (así como una posible InvalidCastException al acecho si el usuario ingresa algo no entero en el campo).

segundo lugar, la OnPropertyChanged() llamada debe ocurrir fuera del interior sentencia if, como el siguiente:

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

Desde el _runAfter locales está siendo actualizado en ambos caminos de la condicional, la OnPropertyChanged() tiene ser llamado independientemente de la rama tomada. ¡Espero que eso te ayude a orientarte en la dirección correcta!

+0

+1 para señalar que se necesita para mover el OnPropertyChanged exterior de la persona. – Robaticus

+0

Bueno, el conjunto es llamado por la Vista (a través del enlace) así que pensé que solo sería necesario llamar a OnPropertyChanged si el valor se cambiaría del establecido en la Vista. – jpsstavares

+0

De todos modos, eso no resolvió mi problema ... – jpsstavares

1

que tenían la misma situación. Escribí lo siguiente y funcionó.

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

Y

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