0

How to avoid error using binding in resource?

I'm now working on my first wpf poject. I put a Style in Windows.Resource to reference in following controls.

<Window.Resources>
<Style x:Key="EmojiButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="BorderBrush" Value="Transparent" />
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="Padding" Value="1" />
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect
                        BlurRadius="4"
                        Opacity="1.0"
                        ShadowDepth="0"
                        Color="Gray" />
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border
                            x:Name="border"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            SnapsToDevicePixels="true">
                            <ContentPresenter
                                x:Name="contentPresenter"
                                Margin="{TemplateBinding Padding}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                Focusable="False"
                                RecognizesAccessKey="True"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsDefaulted" Value="true" />
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="TextBlock.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect
                                            BlurRadius="5"
                                            ShadowDepth="0"
                                            Color="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=Foreground, Mode=OneWay, Converter={StaticResource SingleValueDebugPrintConverter}}" />
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="Foreground" Value="OrangeRed" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="TextBlock.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect
                                            BlurRadius="2"
                                            ShadowDepth="0"
                                            Color="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=Foreground, Mode=OneWay, Converter={StaticResource SingleValueDebugPrintConverter}}" />
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="Foreground" Value="DarkRed" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter TargetName="contentPresenter" Property="TextElement.Foreground" Value="LightGray" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

It works well, however I got an error when application startup.

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Foreground; DataItem=null; target element is 'DropShadowEffect' (HashCode=65300541); target property is 'Color' (type 'Color')

I'm sure the error is due to Color="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=Foreground, Mode=OneWay, Converter={StaticResource SingleValueDebugPrintConverter}}", that binding in Windows.Resource has no ancestor untill being referenced by other control.

Am I doing this in the right way? Is the error can be avoided?

Update #1

Have been looking into there similar questions for hours, none of them matches what I came cross.

Binding targets need to be part of the visual tree. There's no data context in the resource dictionary. The exact fix will depend on your scenario specifics. See duplicate for generalized advice. – Peter Duniho

Peter Duniho 's answer may explained why binding in Window.Resource is not working, but I can not find any walkaround. ProxyElement trick mentioned in other post is aim to binding to DataContext not Ancestor.

Update #2

Anyhow, I'v found the right way to do so. Use TemplateBinding instead of FindAncestor.

<Window.Resources>
<Style x:Key="EmojiButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="BorderBrush" Value="Transparent" />
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="Padding" Value="1" />
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect
                        BlurRadius="4"
                        Opacity="1.0"
                        ShadowDepth="0"
                        Color="Gray" />
                </Setter.Value>
            </Setter>
            <Setter Property="Cursor" Value="Hand" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border
                            x:Name="border"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            SnapsToDevicePixels="true">
                            <ContentPresenter
                                x:Name="contentPresenter"
                                Margin="{TemplateBinding Padding}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                Focusable="False"
                                RecognizesAccessKey="True"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="TextBlock.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect
                                            BlurRadius="8"
                                            ShadowDepth="0"
                                            Color="{TemplateBinding Property=Foreground}" />
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="TextBlock.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect
                                            BlurRadius="3"
                                            ShadowDepth="0"
                                            Color="{TemplateBinding Property=Foreground}" />
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter TargetName="contentPresenter" Property="TextElement.Foreground" Value="LightGray" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
</Window.Resources>

Thanks to Styles and templates (WPF .NET). Stackoverflow really needs to review someone's question before rush it as duplicate.

  • Binding targets need to be part of the visual tree. There's no data context in the resource dictionary. The exact fix will depend on your scenario specifics. See duplicate for generalized advice. – Peter Duniho Mar 10 '21 at 00:08
  • I am facing the same problem but I dont think your resolution would work :/ I attempt to bind to a Custom Registered BindingProperty of the TargetType, it works, but I still get the warning :( – Angevil Mar 19 '21 at 20:42

0 Answers0