在ControlTemplate内绑定嵌套属性

7

目标是为我的自定义按钮模板建立一个图标路径几何资源字典。

到目前为止,以下内容已经可用:

资源字典:

<Geometry x:Key="ArrowDown">
    M0,10 M10,0 M5,1 L5,7 4.2,7 5,8 5.8,7 5,7
</Geometry>
<Geometry x:Key="ArrowUp">
    M0,0 M10,10 M5,9 L5,3 4.2,3 5,2 5.8,3 5,3
</Geometry>

Path 的附加属性:

public static Geometry GetIconPath(UIElement element)
{
    return (Geometry)element.GetValue(IconPathProperty);
}

public static void SetIconPath(UIElement element, Geometry value)
{
    element.SetValue(PIconPathProperty, value);
}

public static readonly DependencyProperty IconPathProperty =
    DependencyProperty.RegisterAttached("IconPath", typeof(Geometry), typeof(Attached));

模板:

<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
    <Viewbox>
        <Path Name="Icon" Stroke="Black" StrokeThickness="1" Stretch="Uniform"
              Data="{Binding (local:Attached.IconPath), RelativeSource={RelativeSource TemplatedParent}}"/>
    </Viewbox>
    <ControlTemplate.Triggers>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Stroke" TargetName="Icon" Value="Gray"/>
            <Setter TargetName="Icon" Property="Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth="0.2" Color="Black" Direction="125"/>
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

按钮:
<Button local:Attached.IconPath="{StaticResource ArrowDown}"/>

这个工作很好,但现在我有了一个额外的复杂性:一些图标需要被填充,而另一些不需要。我希望在ResourceDictionary中包含这些信息和GeometryData。
一个解决方案是将整个路径存储在ResourceDictionary中,但是正如您在ControlTemplate中看到的那样,我需要能够访问路径来触发DropShadowEffect。
所以我尝试使用POCO来存储两个元素的替代方案。
public class IconData
{
    public bool Fill { get; set; }
    public Geometry Geometry { get; set; }
}

因此,ResourceDictionary 现在包含:

<local:IconData x:Key="ArrowUp" Fill="True" Geometry="
    M0,0 M10,10 M5,9 L5,3 4.2,3 5,2 5.8,3 5,3"/>

通过适当的附加属性,ControlTemplate 变得如下:

<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
    <Viewbox>
        <Path Name="Icon" Stroke="Black" StrokeThickness="1" Stretch="Uniform"
              Data="{Binding (local:Attached.IconData.Geometry), RelativeSource={RelativeSource TemplatedParent}}"/>
    </Viewbox>
    <ControlTemplate.Triggers>
        <Trigger Property="local:Attached.IconData.Fill" Value="True">
            <Setter Property="Fill" TargetName="Icon" Value="#00000000"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Stroke" TargetName="Icon" Value="Gray"/>
            <Setter TargetName="Icon" Property="Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth="0.2" Color="Black" Direction="125"/>
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

很不幸,这里两个对 IconData 的引用都说 Nested types are not supported: Attached.IconData(不支持嵌套类型:Attached.IconData)。

我可以接受解决方案,或者任何变通方法或不同的解决方案。

1个回答

4
<Path Name="Icon" Stroke="Black" StrokeThickness="1" Stretch="Uniform"
      Data="{Binding (local:Attached.IconData.Geometry), RelativeSource={RelativeSource TemplatedParent}}"/>

(local:Attached.IconData.Geometry)表示嵌套类型。要获取Attached.IconData对象的属性,应使用以下绑定路径:

<Path Name="Icon" Stroke="Black" StrokeThickness="1" Stretch="Uniform"
      Data="{Binding (local:Attached.IconData).Geometry, RelativeSource={RelativeSource TemplatedParent}}"/>

同时请确保在Attached类型中将附加属性类型从Geometry更改为IconData

IconData类不应嵌套到任何类型中,因为它正是所说的不支持的(只需将其放置在与其他使用的类型相同的命名空间中即可)。

进行这些修改后,您的代码对我有效。

以下是主窗口XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="250" Width="260">
    <Window.Resources>
        <ResourceDictionary>
            <local:IconData x:Key="ArrowUp" Fill="False" Geometry="M0,0 M10,10 M4.8,9 4.8,3 4.2,3 5,2 5.8,3 5.2,3 5.2,9 Z"/>
            <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
                <Viewbox>
                    <Path Name="Icon" Stretch="Uniform"
                          Data="{Binding (local:Attached.IconPath).Geometry, RelativeSource={RelativeSource TemplatedParent}}">
                        <Path.Style>
                            <Style TargetType="Path">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding (local:Attached.IconPath).Fill, RelativeSource={RelativeSource TemplatedParent}}"
                                                     Value="True">
                                        <Setter Property="Fill" Value="Black" />
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding (local:Attached.IconPath).Fill, RelativeSource={RelativeSource TemplatedParent}}"
                                                     Value="False">
                                        <Setter Property="Stroke" Value="Black" />
                                        <Setter Property="StrokeThickness" Value="0.2" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Path.Style>
                    </Path>
                </Viewbox>
            </ControlTemplate>

        </ResourceDictionary>
    </Window.Resources>

    <Button local:Attached.IconPath="{StaticResource ArrowUp}" Template="{StaticResource ButtonTemplate}" />
</Window>

请注意,我已经修改了路径几何形状M0,0 M10,10 M4.8,9 4.8,3 4.2,3 5,2 5.8,3 5.2,3 5.2,9 Z,使其闭合并适合填充。
以下是<local:IconData Fill="False" ... /><local:IconData Fill="True" ... />两种情况的屏幕截图: Fill=False情况的屏幕截图 Fill=True情况的屏幕截图

它构建成功了,但出于某些原因我看不到路径。你走到那一步了吗? - Benjol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接