-1

in my App.xaml I defined a resource for Validation.ErrorTemplate, which depends on dynamic BorderBrush resource. I intend to define unique BorderBrush in each window I have and also within different blocks inside window.

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

and this one to demonstrate my problem (also with dynamic brush resource)

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

and now window, where I use these templates, can resolve brush resource for normal template, but not for 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>

what should I do to get RED border around TextBox?

ASh
  • 34,632
  • 9
  • 60
  • 82

2 Answers2

3

Behavior you are seeing is perfectly fine. Reasoning behind it:

Validation.ErrorTemplateis placed in adorner layerof window which is placed above all other controls in the window. That's why it's not able to see resource defined at Grid level and resolve reference with window resource.

In case you want to get it resolved dynamically, only possible solution is to declare it in window resources OR use static assignment.

Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • my main purpose is to parametrize `ErrorTemplate`s individually. I attempted to do that using local resources but forgot about adorner behavior. thanks for clarification – ASh Jan 26 '16 at 17:48
0

I have implemented a binding converter which can find resources from Validation.ErrorTemplate. It needs an instance of FrameworkElement (element which shows ErrorTemplate) and resource key:

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();
    }
}

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

Binding and therefore converter are triggered every time when ErrorTemplate is shown. So it is possible to update resources and see changes in ErrorTemplate. But unlike DynamicResource it doesn't happen immediately. Still resource which is resolved by binding allows customization per instance.

ASh
  • 34,632
  • 9
  • 60
  • 82