Стили WPF Error Styles отображаются только на видимой вкладке элемента управления вкладкой
У меня есть объект данных, используемый для хранения моих данных пользовательского интерфейса, который поддерживает INotifyPropertyChanged
и IDataErrorInfo
. Первоначально у меня были все элементы управления пользовательского интерфейса, отображаемые в одном большом приложении WPF, и с радостью увидели ошибки, отмеченные этим пользовательским стилем:
<!-- Set error style for textboxes -->
<Style x:Key="txtBoxErrStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel DockPanel.Dock="Right">
<AdornedElementPlaceholder />
<Image Source="Error.png"
Height="16"
Width="16"
ToolTip="{Binding Path=AdornedElement.ToolTip, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Adorner}}}" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Я сегодня реорганизовал программу и решил распространять различные элементы пользовательского интерфейса на нескольких страницах TabControl
. Структура структуры, которую я использую для этого:
<tabcontrol>
<tabitem>
<AdornerDecorator>
[.. various Stack Panels, Groups and UI controls moved from original layout ..]
</AdornerDecorator>
</tabItem>
<tabitem>
<AdornerDecorator>
[.. various Stack Panels, Groups and UI controls moved from original layout ..]
</AdornerDecorator>
</tabItem>
...
</tabcontrol>
(Я использую AdornerDecorator
, как я уже имел в предыдущей программе, стиль ошибки не перерисовывается при перестановке страниц вкладок. Я не могу вспомнить, где я это видел, но это помогло мне.)
Теперь, когда я запускаю свою программу, стиль ошибки корректно отображается на TabItem
, который открывается при запуске программы, но не выполняет рендеринг на другом (скрытом) TabItem
s. Когда я выбираю (и обнаруживаю) один из этих TabItem
, устанавливается подсказка стиля ошибки, но изображение значка ошибки не отображается.
Я также протестировал удаление пользовательского стиля и вернусь обратно к стилю ошибки WPF по умолчанию для текстовых полей, и я по-прежнему получаю аналогичное поведение, т.е. красный блок вокруг элемента управления TabItem
, который скрыт при открытии программы.
Итак, кажется, что я полностью пропускаю то, что останавливает стили ошибок от правильной рендеринга, отличные от открытой вкладки Item. Любые идеи?
Изменить сентябрь 3 Изменено описание, чтобы лучше понять, что я видел
Разговор о Дежавю в 2014 году
В ноябре 2014 года и сегодня у меня была эта глупая проблема WPF с шаблонами ошибок, которые не отображаются на элементах, представленных в контроллере табуляции. Что-то в глубине моего ума предполагает, что я видел эту проблему раньше. Поэтому я google, и первое, что появляется, это мой собственный вопрос с 2009 года.
На этот раз я вижу комментарий от dkl, который был добавлен после того, как я решил вещи в последний раз. Поэтому я попробовал это и использовал это решение (которое хорошо работало, и мне не нужно было посыпать элемент Adorner над элементами управления вкладками):
<Style x:Key="TextBoxErrorStyle" TargetType="TextBox">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError" Value="True" />
<Condition Property="IsVisible" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Red"
FontSize="14pt"
Margin="-15,0,0,0" FontWeight="Bold">*
</TextBlock>
<Border BorderBrush="Red" BorderThickness="2">
<AdornedElementPlaceholder Name="controlWithError"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}" />
</MultiTrigger>
</Style.Triggers>
</Style>
Ответы
Ответ 1
(Я использую AdornerDecorator как я испытали в предыдущей программе стиль ошибки не перерисовывается при обмене языковыми страницами. Я не могу помните, где я это видел, но это было помогите мне)
Предположительно, этот действительно важный совет исходит из Karl Shifflets blog, по крайней мере, он обращается к одной теме: Ошибки проверки WPF исчезают внутри TabControl при переключении TabItems.
Учитывая это, ваша проблема может быть просто связана, то есть вышеприведенный совет/код гарантирует, что для каждой вкладки есть выделенный AdornerLayer
теперь, когда слой adorner родительского элемента отбрасывается при переключении вкладок. Этот выделенный слой adorner по-прежнему нуждается в особом лечении, хотя, например, вопрос WPF ErrorTemplate отображается, когда он не сфокусирован?, который в основном касается вашей проблемы с ног на голову. Следовательно, я предлагаю вам объединить и расширить выделенное решение для последнего с вашим стилем и попробовать следующий (непроверенный код на данный момент):
<Style x:Key="ErrorTemplate" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">...</Trigger>
<Trigger Property="IsVisible" Value="false">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Trigger>
<Trigger Property="IsVisible" Value="true">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>...</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
См. мой комментарий относительно вашего обновления "Стиль ошибки радио кнопки" , который пытается аналогичным образом решить ваш вероятный родственный вопрос; вы действительно попробовали мое предложение?
Подробнее о архитектуре adorner см. Обзор Adorners.
Ответ 2
Steffen Opel решил мою проблему со своей ссылкой: Ошибки проверки WPF исчезают внутри TabControl при переключении TabItems.
<TabControl>
<TabItem>
<AdornerDecorator>
<StackPanel>
...
</StackPanel>
</AdornerDecorator>
</TabItem>
<TabItem>
<AdornerDecorator>
<StackPanel>
...
</StackPanel>
</AdornerDecorator>
</TabItem>
<TabItem>
<AdornerDecorator>
<StackPanel>
...
</StackPanel>
</AdornerDecorator>
</TabItem>
</TabControl>
Ответ 3
Чтобы добавить к предоставленному ответу, шаблон ошибки можно установить один раз в словаре ресурсов. Просто триггеры должны быть скопированы и вставлены для всех стилей по умолчанию для всех соответствующих типов элементов.
Например:
<ResourceDictionary ...>
<!-- Add to the default style instead of replacing it -->
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError" Value="True" />
<Condition Property="IsVisible" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorTemplate}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
<Style TargetType="PasswordBox" BasedOn="{StaticResource {x:Type PasswordBox}}">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError" Value="True" />
<Condition Property="IsVisible" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorTemplate}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Или, сделайте еще один шаг и избегайте повторения триггера объединяющего стили:
<ResourceDictionary ...>
<Style x:Key="ErrorControlStyle" TargetType="Control">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError" Value="True" />
<Condition Property="IsVisible" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorTemplate}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
<Style TargetType="PasswordBox" BasedOn="{extensions:MultiStyle . ErrorControlStyle}"/>
<Style TargetType="TextBox" BasedOn="{extensions:MultiStyle . ErrorControlStyle}"/>
</ResourceDictionary>
но я бы держался подальше от этого подхода, так как он сломал конструктора.
В приведенных выше примерах я использовал шаблон с именем ValidationErrorTemplate
из MahApps.Metro
![введите описание изображения здесь]()
Кроме того, не забудьте также использовать AdornerDecorator
внутри исправления TabItem
, как описано @Abyte0, чтобы поддерживать проверки при переключении вкладок.