2012-04-24 1 views
13

Я пытаюсь выполнить проверку в моем приложении WPF с помощью интерфейса IDataErrorInfo, и я столкнулся с не очень желательной ситуацией.Шаблон ошибки отображается над другими элементами управления, когда он должен быть скрыт

У меня есть шаблон, который используется, когда элемент управления не проверяет

<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> 

Все хорошо, пока я пытаюсь показать что-то выше контроля, который не прошел проверку, например, отображение пункта док над ней:

Normal display Display when part of the control is hidden

Как я могу избежать этого и сделать мой шаблон ошибки отображается ниже элемента док, как это должно?

EDIT

я обнаружил, что я мог бы обернуть мой TextBox с AdornerDecorator, чтобы исправить это, но я действительно не хочу, чтобы сделать это для всех и каждого TextBox управления в моем приложении. Есть ли способ установить его с помощью Style или каким-либо другим способом?

EDIT 2

Я мог бы изменить по умолчанию TextBox ControlTemplate к материалу включает AdornerDecorator, но я не слишком заинтересован в изменении любого из шаблонов управления по умолчанию WPF в. Любые другие предложения приветствуются.

ответ

10

ОК, я нашел относительно простое решение, которое не заставляет меня менять какие-либо шаблоны управления.

Вместо украшение каждого TextBox с AdornerDecorator как этого

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

я могу иметь AdornerDecorator обернуть весь мой взгляд, который достигает тот же результат.

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

Этот способ я могу определить его не более одного раза для каждого вида.

0

Я бы использовал стиль, и вот вот пример того, который вы можете легко адаптировать.

Обратите внимание, что ErrorContent исходит из (Validation.Errors) .CurrentItem.ErrorContent в отличие от Errors [0]. Хотя оба они будут работать, последний будет засорять окно вывода с заглатываемыми исключениями как outlined here.

<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

я не делаю см., как это решает что угодно. Граница все еще отображается над элементом док-станции. –

2

на основе @AdiLester большой ответ, если ваши средства управления, вытекающие из базового класса, и вы не хотите, чтобы положить AdornerDecorator в XAML каждого элемента управления, а затем идти по этому пути:

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; 
     } 
    } 
} 
Смежные вопросы