Шаблон ошибки отображается над другими элементами управления, когда он должен быть скрыт
Я пытаюсь выполнить проверку в моем приложении 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]()
Как я могу избежать этого и сделать мой шаблон ошибки отображаемым под элементом док-станции, как и должно быть?
ИЗМЕНИТЬ
Я обнаружил, что могу поместить мой TextBox
с помощью AdornerDecorator
, чтобы исправить это, но я действительно не хочу делать это для каждого элемента управления TextBox
в моем приложении. Может ли быть способ установить его с помощью Style
или каким-либо другим способом?
РЕДАКТИРОВАТЬ 2
Возможно, я мог бы изменить стандартный TextBox
ControlTemplate по умолчанию, чтобы включить AdornerDecorator
, но я не слишком сильно хочу изменить какие-либо шаблоны управления по умолчанию WPF. Любые другие предложения приветствуются.
Ответы
Ответ 1
ОК, я нашел относительно простое решение, которое не заставляет меня изменять какие-либо шаблоны управления.
Вместо украшения каждого 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>
Таким образом, я могу определить его не более одного раза для каждого представления.
Ответ 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;
}
}
}
Ответ 3
Я бы использовал стиль, и вот здесь пример того, который можно легко адаптировать.
Обратите внимание, что ErrorContent исходит из (Validation.Errors).CurrentItem.ErrorContent в отличие от Errors [0]. Хотя оба они будут работать, последний будет засорять ваше окно вывода с пропущенными исключениями, как описанный здесь.
<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>