带验证的 WPF TextBox 丢失 ErrorTemplate
WPF TextBox with validation loses ErrorTemplate
我遇到的问题与这些非常相似:
Issue with WPF validation(IDataErrorInfo) and tab focusing
TextBox with validation loses ErrorTemplate on tab change
AdornerDecorator
在 Window
的同一实例 中执行技巧 ,但是当重新加载 Window
并且我切换到TabItem
包含错误的 TextBox
,ErrorTemplate
将不再显示 。
<Window x:Class="Views.MyWindowView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl HorizontalAlignment="Stretch"
Height="Auto"
VerticalAlignment="Top"
Width="Auto"
SelectionChanged="TabItemChanged"
Name="MyTabControl">
<!-- Below, AdornerDecorator are added for the following reason:
the Validation.Error cues are painted in the Adorner Layer.
When tabs are switched, that layer is discarded. -->
<!-- The view 1 tab.-->
<TabItem Header="{Resx tab1_Header}"
Name="Tbi1">
<AdornerDecorator>
<vw:MyView1 DataContext="{Binding}"/>
</AdornerDecorator>
</TabItem>
<!-- The view 2 tab.-->
<TabItem Header="{Resx tab2_Header}"
Name="Tbi2">
<AdornerDecorator>
<vw:MyView2 DataContext="{Binding}"/>
</AdornerDecorator>
</TabItem>
</TabControl>
...
我试图在 TabControl
SelectionChanged
的代码隐藏中重新触发验证,但没有成功。
有什么想法吗?
我在 WPF 中看到了一些奇怪的事情,并会提出这个建议。根据您引用并尝试在此处应用装饰器装饰器包装视图的其他帖子,将装饰器的包装直接移动到您的 "MvView1" XAML 页面中。
从您现有的...
<AdornerDecorator>
<vw:MyView1 DataContext="{Binding}"/>
</AdornerDecorator>
改为...
<vw:MyView1 DataContext="{Binding}"/>
并在
<XAML for MyView1>
<AdornerDecorator>
[wrapping is within the view... then the rest of the view...]
</AdornerDecorator>
</close XAML for MyView1>
我注意到类似的情况,例如应用控件的可见性,除非某些东西在一个级别上有效,而在另一个级别上则无效。虽然从未找到确切的模式。
拼图
AdornerLayer 表示用于渲染装饰器的表面。
由于 AdornerLayer
通常服务于整个视图,而不仅仅是一个控件,一些容器默认实现它们。
adorner 是绑定到 UIElement
的自定义 FrameworkElement
。装饰器在 AdornerLayer
中呈现,这是一个始终位于装饰元素或装饰元素集合之上的渲染表面。
所以在这种情况下,装饰器(红色矩形)绑定到 TextBox
,但在 TextBox
.
顶部的图层中呈现
装饰(例如,在验证错误的情况下)是通过调用静态方法 GetAdornerLayer
来获取要装饰的 UIElement
的 AdornerLayer
对象。
足够的理论
更改 TabItems
会丢弃 AdornerLayer
,导致装饰器未被绘制。 2 个修复:
\DRapp建议的手动方式:
<XAML for MyView1>
<AdornerDecorator>
...
</AdornerDecorator>
</close XAML for MyView1>
当然,如果在 AdornerDecorator
和 TextBox
之间(在可视化树中)有另一个容器实现了 AdornerLayer
,这不会有任何好处。所以显式 AdornerDecorator
需要是最后一个包装 TextBox
.
<XAML for MyView1>
<Grid>
...
<GroupBox>
<AdornerDecorator>
<Grid>
...
<TextBox ... />
</Grid>
</AdornerDecorator>
</GroupBox>
</Grid>
</close XAML for MyView1>
\第二种解决方案(我更喜欢)在每次 TextBox
可见时重置 ErrorTemplate。在这样做的过程中,缺少 AdornerLayer
的问题会被发现并修复。
<UserControl.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsVisible" Value="true">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
我遇到的问题与这些非常相似:
Issue with WPF validation(IDataErrorInfo) and tab focusing
TextBox with validation loses ErrorTemplate on tab change
AdornerDecorator
在 Window
的同一实例 中执行技巧 ,但是当重新加载 Window
并且我切换到TabItem
包含错误的 TextBox
,ErrorTemplate
将不再显示 。
<Window x:Class="Views.MyWindowView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl HorizontalAlignment="Stretch"
Height="Auto"
VerticalAlignment="Top"
Width="Auto"
SelectionChanged="TabItemChanged"
Name="MyTabControl">
<!-- Below, AdornerDecorator are added for the following reason:
the Validation.Error cues are painted in the Adorner Layer.
When tabs are switched, that layer is discarded. -->
<!-- The view 1 tab.-->
<TabItem Header="{Resx tab1_Header}"
Name="Tbi1">
<AdornerDecorator>
<vw:MyView1 DataContext="{Binding}"/>
</AdornerDecorator>
</TabItem>
<!-- The view 2 tab.-->
<TabItem Header="{Resx tab2_Header}"
Name="Tbi2">
<AdornerDecorator>
<vw:MyView2 DataContext="{Binding}"/>
</AdornerDecorator>
</TabItem>
</TabControl>
...
我试图在 TabControl
SelectionChanged
的代码隐藏中重新触发验证,但没有成功。
有什么想法吗?
我在 WPF 中看到了一些奇怪的事情,并会提出这个建议。根据您引用并尝试在此处应用装饰器装饰器包装视图的其他帖子,将装饰器的包装直接移动到您的 "MvView1" XAML 页面中。
从您现有的...
<AdornerDecorator>
<vw:MyView1 DataContext="{Binding}"/>
</AdornerDecorator>
改为...
<vw:MyView1 DataContext="{Binding}"/>
并在
<XAML for MyView1>
<AdornerDecorator>
[wrapping is within the view... then the rest of the view...]
</AdornerDecorator>
</close XAML for MyView1>
我注意到类似的情况,例如应用控件的可见性,除非某些东西在一个级别上有效,而在另一个级别上则无效。虽然从未找到确切的模式。
拼图
AdornerLayer 表示用于渲染装饰器的表面。
由于 AdornerLayer
通常服务于整个视图,而不仅仅是一个控件,一些容器默认实现它们。
adorner 是绑定到 UIElement
的自定义 FrameworkElement
。装饰器在 AdornerLayer
中呈现,这是一个始终位于装饰元素或装饰元素集合之上的渲染表面。
所以在这种情况下,装饰器(红色矩形)绑定到 TextBox
,但在 TextBox
.
装饰(例如,在验证错误的情况下)是通过调用静态方法 GetAdornerLayer
来获取要装饰的 UIElement
的 AdornerLayer
对象。
足够的理论
更改 TabItems
会丢弃 AdornerLayer
,导致装饰器未被绘制。 2 个修复:
\DRapp建议的手动方式:
<XAML for MyView1>
<AdornerDecorator>
...
</AdornerDecorator>
</close XAML for MyView1>
当然,如果在 AdornerDecorator
和 TextBox
之间(在可视化树中)有另一个容器实现了 AdornerLayer
,这不会有任何好处。所以显式 AdornerDecorator
需要是最后一个包装 TextBox
.
<XAML for MyView1>
<Grid>
...
<GroupBox>
<AdornerDecorator>
<Grid>
...
<TextBox ... />
</Grid>
</AdornerDecorator>
</GroupBox>
</Grid>
</close XAML for MyView1>
\第二种解决方案(我更喜欢)在每次 TextBox
可见时重置 ErrorTemplate。在这样做的过程中,缺少 AdornerLayer
的问题会被发现并修复。
<UserControl.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsVisible" Value="true">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>