2012-01-10 12 views
11

Estoy creando una ventana de WPF con varios cuadros de texto, cuando el usuario presiona el botón Aceptar Quiero que todos los cuadros de texto sean evaluados como no en blanco. Entiendo que tengo que usar TextBoxes con 'UpdateSourceTrigger of' Explicit ', pero ¿necesito llamar a' UpdateSource() 'para cada uno de ellos? p.UpdateSourceTrigger = Explicit

<TextBox Height="23" 
    HorizontalAlignment="Left" 
    Margin="206,108,0,0" 
    Text="{Binding Path=Definition, UpdateSourceTrigger=Explicit}" 
    Name="tbDefinitionFolder" 
    VerticalAlignment="Top" 
    Width="120" /> 

<TextBox Height="23" 
    HorizontalAlignment="Left" 
    Margin="206,108,0,0" 
    Text="{Binding Path=Release, UpdateSourceTrigger=Explicit}" 
    Name="tbReleaseFolder" 
    VerticalAlignment="Top" 
    Width="120" /> 

...

BindingExpression be = tbDefinitionFolder.GetBindingExpression(TextBox.TextProperty); 
be.UpdateSource(); 
BindingExpression be2 = tbReleaseFolder.GetBindingExpression(TextBox.TextProperty); 
be2.UpdateSource(); 

Respuesta

4

Un enfoque alternativo puede ser fijar su UpdateSourceTrigger a PropertyChanged.

Y luego herede su VM tanto de INotifyPropertyChanged como de IDataErrorInfo. He aquí un ejemplo ...

public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo 
{ 
    private string myVar; 
    public string MyProperty 
    { 
     [DebuggerStepThrough] 
     get { return myVar; } 
     [DebuggerStepThrough] 
     set 
     { 
      if (value != myVar) 
      { 
       myVar = value; 
       OnPropertyChanged("MyProperty"); 
      } 
     } 
    } 
    private void OnPropertyChanged(string prop) 
    { 
     if(PropertyChanged!=null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(pro)); 
     } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    public string Error 
    { 
     get { return String.Empty; } 
    } 
    public string this[string columnName] 
    { 
     get 
     { 
      if (columnName == "MyProperty") 
      { 
       if (String.IsNullOrEmpty(MyProperty)) 
       { 
        return "Should not be blank"; 
       } 
      } 
      return null; 
     } 
    } 
} 

Supongamos que uno de sus cuadros de texto está obligado a 'MyProperty' según lo declarado anteriormente. El indexador se implementa en IDataErrorInfo y se llama cuando cambia 'MyProperty'. En el cuerpo del indexador, puede realizar una comprobación si el valor está vacío y devolver una cadena de error. Si la cadena de error no es nula, el usuario obtiene un adorno agradable en el TextBox como una señal visual. De modo que está en una oportunidad para realizar la validación y entregar la experiencia de UI.

Todo esto es gratis si usa las dos interfaces como se indica arriba y usa UpdateSourceTrigger = PropertyChanged. El uso de UpdateSourceTrigger = Explicit es una sobrecarga masiva para proporcionar la validación que describió.

el XAML para el cuadro de texto sería ...

<TextBox DataContext="{StaticResource Vm}" Text="{Binding MyProperty, 
       UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, 
       NotifyOnSourceUpdated=True, Mode=TwoWay}" Width="200" Height="25"/> 
+1

+1 porque este tipo de validación de datos debe hacerse en ViewModel con 'IDataErrorInfo' – Rachel

+1

Gracias por esto Garry Ive lo implementó como sugirió, el problema que tengo ahora es cuando el cuadro de diálogo se inicia; el cuadro de texto está en error, es decir, ¿rojo? –

+0

@Rachel No entiendo por qué su enfoque todavía está actualizando la fuente sin llamar a 'UpdateSource()'. – Igor

4

Si utiliza Explicit que necesita para llamar UpdateSource.

No estoy seguro de si este es el mejor enfoque de lo que intenta hacer, sin embargo, virtualmente nunca uso Explicit, prefiero vincularme a una copia de un objeto si no deseo que los cambios se apliquen de inmediato, o guardo una copia y devuelvo todo si las ediciones deben cancelarse.

+0

Entonces, si tiene un formulario con varios cuadros de edición que deben verificarse cuando el usuario presiona 'enviar' (como el formulario de detalles de un seguro de automóvil), ¿cómo lo diseñaría? –

+0

@ChrisMilburn: Probablemente agregaría [reglas de validación] (http://msdn.microsoft.com/en-us/library/system.windows.controls.validationrule.aspx) a los enlaces y luego ver si cada control es válido antes de continuar. [Aquí hay un artículo sobre el tema] (http://msdn.microsoft.com/en-us/magazine/ff714593.aspx). –

-1

Sería más sencillo que acaba de establecer a UpdateSourceTrigger=PropertyChanged pesar de que se actualice la variable subyacente a cada vez que cambia el valor (por cada letra introducida)

1

Hay algunas buenas razones para utilizar UpdateSourceTrigger = explícita, en lugar de otros valores. Imagine que tiene que verificar si el valor ingresado es único, lo que se hará leyendo la base de datos. Eso puede llevar un tiempo, incluso 0,3 segundos es inaceptable. Al usar PropertyChanged, esta verificación de la base de datos se realizará cada vez que el usuario presiona la tecla, lo que hace que la interfaz del usuario no responda. Lo mismo sucede si UpdateSourceTrigger = LostFocus y el usuario cambiará rápidamente entre los controles (si mantiene presionada la tecla Tab, se produce un ciclo rápido entre los controles). Por lo tanto, nuestro objetivo es validar todo de una vez en el momento clave (generalmente antes de guardar los datos). Este enfoque necesitará código mínimo detrás, lo que empujará los datos desde la vista al modelo de vista y forzará la validación. No existe un código de validación u otra lógica de aplicación dentro del código, por lo que los puristas MVVM pueden estar relativamente tranquilos. Creé un ejemplo completamente funcional en VB.NET, que usa Caliburn.Micro para MVVM e IoC. Puede descargarlo aquí: https://drive.google.com/file/d/0BzdqT0dfGkO3OW5hcjdBOWNWR2M

Cuestiones relacionadas