Search code examples
wpfdata-bindingdependency-propertiesstaticresource

WPF: binding a static resource to a dependency property in a user control


I have a user control which is an icon container.

<Rectangle x:Name="Rectangle"
           Width="{Binding SquareWidth}"
           Height="{Binding SquareWidth}"
           Fill="{Binding FillBrush}"
           DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}, Mode=OneWay}">
    <Rectangle.OpacityMask>
        <VisualBrush Visual="{Binding VisualItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Stretch="UniformToFill" />
    </Rectangle.OpacityMask>
</Rectangle>

And in the code-behind:

    public static readonly DependencyProperty CanvasItemDependencyProperty =
        DependencyProperty.Register(nameof(VisualItem), typeof(Canvas),
            typeof(SquareIcon), new FrameworkPropertyMetadata());

    public Canvas VisualItem
    {
        get => GetValue(CanvasItemDependencyProperty) as Canvas;
        set => SetValue(CanvasItemDependencyProperty, value);
    }

The icon drawings are defined as Canvas items in a resource dictionary:

<Canvas x:Key="appbar_3d_3ds" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
    <Path Width="32" Height="40" Canvas.Left="23" Canvas.Top="18" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 27,18L 23,26L 33,30L 24,38L 33,46L 23,50L 27,58L 45,58L 55,38L 45,18L 27,18 Z "/>
</Canvas>

I instantiate my user control in the main form like this:

<controls:SquareIcon VisualItem="{StaticResource appbar_information_circle}" Width="16" Height="16" FillBrush="Black" SquareWidth="16" Margin="0,0,5,0"/>

But all I get is a transparent square.

If I replace the "Binding VisualItem" by "StaticResource appbar_information_circle", the icon shows up.

What am I missing?


Solution

  • You did not follow mandatory naming conventions for dependency properties. The identifier field of a dependency property called VisualItem must be named VisualItemProperty, otherwise the XAML parser can't resolve it.

    public static readonly DependencyProperty VisualItemProperty =
        DependencyProperty.Register(
            nameof(VisualItem), typeof(Canvas), typeof(SquareIcon));
    
    public Canvas VisualItem
    {
        get => (Canvas)GetValue(VisualItemProperty)
        set => SetValue(VisualItemProperty, value);
    }
    

    It is not useful to use the as operator in the property getter, because the property value is always a Canvas. In case it's not (which is a programming error) wou'll want to get an InvalidCastException instead of a NullReferenceException.

    You should also consider to change the type of your dependency property from Canvas to Visual. It would work the same way, but provide greater flexibility in terms of which elements could be assigned to the property.


    As a note, setting Mode=TwoWay and UpdateSourceTrigger=PropertyChanged on the Visual Binding is pointless. The Binding should just look like this:

    <VisualBrush Visual="{Binding VisualItem}" .../>