如何在样式中使用附加属性?

39

我已经在ButtonStyle中创建了一个Image。现在我创建了一个附加属性,以便我可以为该Image设置Source。应该很简单,但我卡住了。

这是我缩短后的ButtonStyle:

<Style x:Key="ToolBarButtonStyle"
        TargetType="Button">
    ...
    <Image x:Name="toolbarImage"
            Source="{TemplateBinding PrismExt:ImageSourceAttachable:ImageSource}"
            Width="48"
            Height="48" />
    ...
</Style>

以下是附加属性的定义。请注意,我不知道如何修复回调,因为依赖属性似乎是按钮而不是图片。而按钮在其样式中没有公开我的图像。这很棘手。

namespace SalesContactManagement.Infrastructure.PrismExt
{
    public class ImgSourceAttachable
    {
        public static void SetImgSource(DependencyObject obj, string imgSource)
        {
            obj.SetValue(ImgSourceProperty, imgSource);
        }

        public static string GetImgSource(DependencyObject obj)
        {
            return obj.GetValue(ImgSourceProperty).ToString();
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImgSourceProperty =
            DependencyProperty.RegisterAttached("ImgSource", typeof(string), typeof(ImgSourceAttachable), new PropertyMetadata(Callback));

        private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //((Button)d).Source = new BitmapImage(new Uri(Application.Current.Host.Source, e.NewValue.ToString()));
        }
    }
}

下面是我在XAML中设置图像源的方法:

<Button PrismExt:ImgSourceAttachable.ImgSource="./Images/New.png"
        Style="{StaticResource ToolBarButtonStyle}" />

请问有什么想法吗? 非常感谢。


我觉得我回答得太快了,你是否希望通过setter设置属性,然后在模板内绑定它? - Fredrik Hedblad
视图表示工具栏的四个按钮,如此:http://sl.venuscloud.com/。我想通过附加属性将每个按钮从视图中的图标路径注入到模板中。希望这样更清楚。谢谢。 - Houman
1个回答

55
这里是如何在样式中设置附加属性的方法。
<Style x:Key="ToolBarButtonStyle" TargetType="Button">
    <Setter Property="PrismExt:ImgSourceAttachable.ImgSource"
            Value="./Images/New.png"/>
    <!--...-->
</Style>

当绑定附加属性时,路径应该在括号内,因此请尝试使用RelativeSource绑定,并使用TemplatedParent代替。

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="Button">
            <Image x:Name="toolbarImage"
                    Source="{Binding RelativeSource={RelativeSource TemplatedParent},
                                    Path=(PrismExt:ImgSourceAttachable.ImgSource)}"
                    Width="48"
                    Height="48">
            </Image>
        </ControlTemplate>
    </Setter.Value>
</Setter>

编辑:上述代码适用于WPF,在Silverlight中,Image在运行时显示,但在设计器中会出现异常。您可以使用以下代码作为PropertyChangedCallback的解决方法来获取Image

private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    Button button = d as Button;
    Image image = GetVisualChild<Image>(button);
    if (image == null)
    {
        RoutedEventHandler loadedEventHandler = null;
        loadedEventHandler = (object sender, RoutedEventArgs ea) =>
        {
            button.Loaded -= loadedEventHandler;
            button.ApplyTemplate();
            image = GetVisualChild<Image>(button);
            // Here you can use the image
        };
        button.Loaded += loadedEventHandler;
    }
    else
    {
        // Here you can use the image
    }
}
private static T GetVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
    T child = default(T);

    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        DependencyObject v = (DependencyObject)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        {
            child = GetVisualChild<T>(v);
        }
        if (child != null)
        {
            break;
        }
    }
    return child;
}

谢谢。这段代码现在可以编译了,但是我仍然看不到图片。我相当确定这是因为附加属性的回调为空。然而,“DependencyObject d”中的按钮本身。我不明白... - Houman
我刚注意到你的问题同时有WPF和Silverlight标签,我的回答是针对WPF的。我会尝试为Silverlight测试一下。 - Fredrik Hedblad
你是对的。抱歉。我以为附加属性不会有什么不同。 :) - Houman
1
更新了我的答案。那段代码在我的运行时环境中可以正常工作,但在设计时出错。我添加了代码来在回调中获取图像。 - Fredrik Hedblad
非常感谢。它像魔法一样运行。如果没有你的帮助,我想我做不到。 :) - Houman

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