2012-09-19 22 views
8

Parece que he leído otra pregunta/respuesta en este sitio sobre este tema, pero no recuerdo cuál fue la respuesta y ahora no puedo encontrar la publicación original.Error Template Design

No soy seguidor de la plantilla de error predeterminada en WPF. Entiendo cómo cambiar esta plantilla de error. Sin embargo, si agrego algo de contenido al final de, por ejemplo, un cuadro de texto, el tamaño del cuadro de texto no cambia y el contenido agregado se recortará (potencialmente). ¿Cómo modifico el cuadro de texto (creo que la termonología correcta es un elemento adornado) en este escenario para que nada quede recortado?

Aquí es el XAML para la plantilla de error:

<Style TargetType="{x:Type TextBox}"> 
    <Setter Property="Validation.ErrorTemplate"> 
    <Setter.Value> 
     <ControlTemplate> 
     <StackPanel> 
      <AdornedElementPlaceholder /> 
      <TextBlock Foreground="Red" Text="Error..." /> 
     </StackPanel> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

Aquí es el XAML para un par de cuadros de texto en la forma: Hace

<StackPanel> 
    <TextBox Text="{Binding...}" /> 
    <TextBox /> 
</StackPanel> 
+2

Añada el XAM relevante L código para su pregunta – Spontifixus

+0

Agregué el XAML que podría usarse. El XAML es mucho más simple que lo que usaría, pero demuestra adecuadamente el problema. Cualquier mensaje de error realmente se mostraría en el segundo cuadro de texto. Me gustaría que el segundo cuadro de texto * automáticamente * se desplace hacia abajo cuando se muestre un mensaje de error para el primer cuadro de texto (y que se mueva hacia atrás cuando desaparezca el mensaje de error). –

Respuesta

10

dos semanas, que estaba frente a la misma cuestión .

Se me ocurrió una solución, después de ver este blog de Josh Smith.

http://joshsmithonwpf.wordpress.com/2008/10/08/binding-to-validationerrors0-without-creating-debug-spew/

El truco consiste en definir un DataTemplate para representar el objeto ValidationError y luego usar un ContentPresenter para mostrar el mensaje de error. Si no hay ningún error, entonces no se mostrará ContentPresenter.

A continuación, he compartido el código de la aplicación de muestra que he creado.

Without errorsWith errors

Aquí es el XAML:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     SizeToContent="WidthAndHeight" 
     Title="MainWindow"> 
    <StackPanel Margin="5"> 
     <StackPanel.Resources> 
      <DataTemplate DataType="{x:Type ValidationError}"> 
       <TextBlock Text="{Binding ErrorContent}" Foreground="White" Background="Red" VerticalAlignment="Center" FontWeight="Bold"/> 
      </DataTemplate> 
     </StackPanel.Resources> 
     <TextBox Name="TextBox1" Text="{Binding Text1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/> 
     <ContentPresenter Content="{Binding ElementName= TextBox1, Path=(Validation.Errors).CurrentItem}" HorizontalAlignment="Left"/> 

     <TextBox Name="TextBox2" Text="{Binding Text2, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/> 
     <ContentPresenter Content="{Binding ElementName= TextBox2, Path=(Validation.Errors).CurrentItem}" HorizontalAlignment="Left"/> 
     <Button Content="Validate" Click="Button_Click"/> 
    </StackPanel> 
</Window> 

El código detrás de archivo:

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private ViewModel _ViewModel = null; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      _ViewModel = new ViewModel(); 
      DataContext = _ViewModel; 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      _ViewModel.Validate = true; 
      _ViewModel.OnPropertyChanged("Text1"); 
      _ViewModel.OnPropertyChanged("Text2"); 
     } 
    } 
} 

El modelo de vista:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ComponentModel; 

namespace WpfApplication1 
{ 
    public class ViewModel : INotifyPropertyChanged, IDataErrorInfo 
    { 
     private string _Text1; 
     public string Text1 
     { 
      get { return _Text1; } 
      set 
      { 
       _Text1 = value; 
       OnPropertyChanged("Text1"); 
      } 
     } 

     private string _Text2; 
     public string Text2 
     { 
      get { return _Text2; } 
      set 
      { 
       _Text2 = value; 
       OnPropertyChanged("Text2"); 
      } 
     } 

     public bool Validate { get; set; } 

     #region INotifyPropertyChanged Implemenation 
     public event PropertyChangedEventHandler PropertyChanged; 

     public void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
     #endregion 

     #region IDataErrorInfo Implementation 
     public string Error 
     { 
      get { return null; } 
     } 

     public string this[string columnName] 
     { 
      get 
      { 
       string errorMessage = string.Empty; 
       if (Validate) 
       { 
        switch (columnName) 
        { 
         case "Text1": 
          if (Text1 == null) 
           errorMessage = "Text1 is mandatory."; 
          else if (Text1.Trim() == string.Empty) 
           errorMessage = "Text1 is not valid."; 
          break; 
         case "Text2": 
          if (Text2 == null) 
           errorMessage = "Text2 is mandatory."; 
          else if (Text2.Trim() == string.Empty) 
           errorMessage = "Text2 is not valid."; 
          break; 
        } 
       } 
       return errorMessage; 
      } 
     } 
     #endregion 
    } 
} 
+0

Gracias por la respuesta. Me olvidé de verificar si había alguna respuesta. La muestra que proporcionó hizo exactamente lo que estaba tratando de lograr. –

+0

Gracias por esa joya. Exactamente lo que estaba buscando. No encuentro ningún buen ejemplo +1 – Andez