Wpf动态资源查找Validation.ErrorTemplate

时间:2016-01-26 14:15:37

标签: c# wpf resourcedictionary dynamicresource

在我的App.xaml中,我为Validation.ErrorTemplate定义了一个资源,它依赖于动态BorderBrush资源。我打算在我拥有的每个窗口中以及窗口内的不同块中定义唯一的BorderBrush

<!--validation error template-->
<ControlTemplate x:Key="NonValid">
    <Border BorderBrush="{DynamicResource BorderBrush}" BorderThickness="2" Margin="5">
        <AdornedElementPlaceholder x:Name="ui"/>
    </Border>
</ControlTemplate>

这个用来演示我的问题(也用动态画笔资源)

<!--test template-->
<ControlTemplate x:Key="ButtonRes" TargetType="Button">
    <Border BorderBrush="{DynamicResource BorderBrush}" BorderThickness="2" Background="Khaki">
        <ContentPresenter />
    </Border>
</ControlTemplate>

现在窗口,我使用这些模板,可以解析普通模板的画笔资源,但不能解析Validation.ErrorTemplate

how it look like

<Window x:Class="MyApp.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" Height="300" Width="300">
    <Window.Resources>
        <!-- window overrides resource-->
        <SolidColorBrush x:Key="BorderBrush" Color="Blue"/>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <!-- button can see window resource-->
        <Button Template="{StaticResource ButtonRes}"/>        

        <Grid Grid.Row="1">
            <Grid.Resources>
                <!-- grid overrides resource-->
                <SolidColorBrush x:Key="BorderBrush" Color="Red"/>
            </Grid.Resources>

            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <!-- button can see grid resource-->
            <Button Template="{StaticResource ButtonRes}"/>

            <!-- errorTemplate CAN     SEE window resource-->
            <!-- errorTemplate CAN NOT SEE grid   resource-->
            <TextBox Grid.Row="1" VerticalAlignment="Center" Text="{Binding Name}" 
                 Validation.ErrorTemplate="{StaticResource NonValid}"/>
        </Grid>
    </Grid>
</Window>

我该怎么做才能在TextBox周围获得 RED 边框?

2 个答案:

答案 0 :(得分:3)

你看到的行为非常好。背后的推理:

Validation.ErrorTemplate位于窗口的adorner layer窗口,该窗口位于窗口中所有其他控件的上方。这就是为什么它无法在网格级别查看资源并使用窗口资源解析引用的原因。

如果你想动态解决它,只有可能的解决方案是在窗口资源中声明它或使用静态赋值。

答案 1 :(得分:0)

我实现了一个绑定转换器,该转换器可以从Validation.ErrorTemplate中找到资源。它需要一个FrameworkElement实例(显示ErrorTemplate的元素)和资源密钥:

public class ResourceProviderConverter : IValueConverter
{
    /// <summary>
    /// Returns requested resource from element visual tree
    /// </summary>
    /// <param name="value">Should contain FrameworkElement which has access to resource</param>
    /// <param name="targetType"></param>
    /// <param name="parameter">Resource key</param>
    /// <param name="culture"></param>
    /// <returns>Resource value if resource was found</returns>
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {            
        if (parameter != null && (value is FrameworkElement element))
        {
            var result = element.TryFindResource(parameter);
            if (result != null)
                return result;
        }

        return Binding.DoNothing;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

修改后的ErrorTemplate:

<local:ResourceProviderConverter x:Key="ResourceProvider"/>

<ControlTemplate x:Key="NonValid">
    <Border BorderBrush="{Binding ElementName=ui, Path=AdornedElement, 
                                  Converter={StaticResource ResourceProvider}, 
                                  ConverterParameter='BorderBrush', 
                                  FallbackValue={x:Static Brushes.Purple}}" 
            BorderThickness="2" Margin="5">
        <AdornedElementPlaceholder x:Name="ui"/>
    </Border>
</ControlTemplate>

每次显示ErrorTemplate时,绑定并因此触发转换器。因此,可以更新资源并查看ErrorTemplate中的更改。但是与DynamicResource不同,它不会立即发生。通过绑定解决的静态资源允许按实例自定义。