2012-04-24 9 views
13

Sto cercando di implementare la convalida nella mia applicazione WPF utilizzando l'interfaccia IDataErrorInfo, e ho incontrato una situazione non-così-desiderabile.Modello di errore viene visualizzato sopra altri controlli, quando dovrebbe essere nascosto

ho questo modello che viene utilizzato quando un controllo non riesce a convalidare

<ControlTemplate x:Key="errorTemplate"> 
    <DockPanel LastChildFill="true"> 
     <Border Background="Red" DockPanel.Dock="Right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10" 
            ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"> 
      <TextBlock Text="!" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White" /> 
     </Border> 
     <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" > 
      <Border BorderBrush="red" BorderThickness="1" /> 
     </AdornedElementPlaceholder> 
    </DockPanel> 
</ControlTemplate> 

Tutto è bene fino a quando cerco di visualizzare qualcosa sopra il controllo che ha fallito la validazione, come ad esempio la visualizzazione di un elemento del bacino sopra di esso:

Normal display Display when part of the control is hidden

come posso evitare questo e fare il mio modello di errore visualizzato sotto la voce dock, come dovrebbe?

EDIT

ho scoperto che avrei potuto avvolgere la mia TextBox con una AdornerDecorator per risolvere questo problema, ma davvero non voglio fare questo per ogni TextBox di controllo nella mia applicazione. C'è forse un modo per impostarlo con un Style o in qualche altro modo?

EDIT 2

probabilmente potrei cambiare il ControlTemplate predefinito TextBox per includere un AdornerDecorator, ma non sono troppo appassionato di cambiare qualsiasi dei modelli di controllo di default di WPF. Qualsiasi altro suggerimento è benvenuto.

risposta

10

OK, ho trovato una soluzione relativamente semplice che non mi obbliga a modificare alcun modello di controllo.

Invece di decorare ogni TextBox con una AdornerDecorator come questo

<StackPanel> 
    <AdornerDecorator> 
     <TextBox Text={Binding ...} /> 
    </AdornerDecorator> 
    <AdornerDecorator> 
     <TextBox Text={Binding ...} /> 
    </AdornerDecorator> 
</StackPanel> 

posso avere l'AdornerDecorator avvolgere tutta la mia vista, che ottiene lo stesso risultato.

<AdornerDecorator> 
    <StackPanel> 
     <TextBox Text={Binding ...} /> 
     <TextBox Text={Binding ...} /> 
    </StackPanel> 
</AdornerDecorator> 

In questo modo posso definirlo al massimo una volta per visualizzazione.

0

vorrei utilizzare uno stile, ed ecco qui un esempio di quello che si può adattare facilmente.

Nota che ErrorContent proviene da (Validation.Errors) .CurrentItem.ErrorContent anziché Errori [0]. Anche se entrambi funzioneranno, la finestra l'output quest'ultimo volontà lettiera con inghiottiti come outlined here eccezioni.

<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}"> 
    <Setter Property="Margin" Value="0,0,16,0" /> 
    <Setter Property="VerticalAlignment" Value="Center" /> 
    <Setter Property="VerticalContentAlignment" Value="Center" /> 

    <!-- 
    Error handling 
    --> 
    <Setter Property="Validation.ErrorTemplate"> 
     <Setter.Value> 
      <ControlTemplate> 
       <DockPanel LastChildFill="True"> 
        <TextBlock DockPanel.Dock="Right" Text=" *" 
           Foreground="Red" FontWeight="Bold" FontSize="16" 
           ToolTip="{Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/> 
        <Border BorderBrush="Red" BorderThickness="1"> 
         <AdornedElementPlaceholder Name="placeholder"></AdornedElementPlaceholder> 
        </Border> 
       </DockPanel> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    <Style.Triggers> 
     <Trigger Property="Validation.HasError" Value="True"> 
      <Setter Property="Background" Value="LightYellow"/> 
     </Trigger> 
    </Style.Triggers> 
</Style> 
+1

non lo faccio guarda come questo risolve qualsiasi cosa Il bordo è ancora visualizzato sopra la voce del dock. –

2

Sulla base @AdiLester grande risposta, se i controlli sono derivanti da una classe base e non si vogliono mettere AdornerDecorator in XAML di ogni controllo, poi andare in questo modo:

public class MyBaseUserControl : UserControl 
{ 
    public MyBaseUserControl() 
    { 

    } 

    protected override void OnContentChanged(object oldContent, object newContent) 
    { 
     base.OnContentChanged(oldContent, newContent); 

     if (!(newContent is AdornerDecorator)) 
     { 
      this.RemoveLogicalChild(newContent); 

      var decorator = new AdornerDecorator(); 
      decorator.Child = newContent as UIElement; 

      this.Content = decorator; 
     } 
    } 
} 
Problemi correlati