【问题标题】:TemplateBinding fails when the target is an ImageBrush.ImageSource当目标是 ImageBrush.ImageSource 时,TemplateBinding 失败
【发布时间】:2014-03-02 22:11:43
【问题描述】:

为什么TemplateBinding 在这种特定情况下似乎失败了?

拿一个基本的扩展按钮:

public class IconButton : Button
{
    public ImageSource Icon
    {
        get { return (ImageSource)GetValue(IconProperty); }
        set { SetValue(IconProperty, value); }
    }
    public static readonly DependencyProperty ImageProperty =
        DependencyProperty.Register("Icon", typeof(ImageSource), typeof(IconButton), new PropertyMetadata(null));

    public IconButton()
    {
        DefaultStyleKey = typeof(IconButton);
    }
}

控件模板使用OpacityMask显示图标:

<Style TargetType="controls:IconButton">
    <Setter Property="Width" Value="30" />
    <Setter Property="Height" Value="30" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:IconButton">
                <Grid>
                    <Rectangle Fill="{StaticResource PhoneForegroundBrush}"
                               Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                        <Rectangle.OpacityMask>
                            <ImageBrush ImageSource="{TemplateBinding Icon}" />
                        </Rectangle.OpacityMask>
                    </Rectangle>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这会静默失败——控件显示为实心矩形。如果我使用常规图像,而不是ImageBrush,则绑定成功:

            <ControlTemplate TargetType="controls:IconButton">
                <Grid>
                    <Image Source="{TemplateBinding Icon}" />
                </Grid>
            </ControlTemplate>

如果我对图像源路径进行硬编码,它也可以正常工作:

            <ControlTemplate TargetType="controls:IconButton">
                <Grid>
                    <Rectangle Fill="{StaticResource PhoneForegroundBrush}"
                               Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                        <Rectangle.OpacityMask>
                            <ImageBrush ImageSource="/Images/appbar.next.rest.png" />
                        </Rectangle.OpacityMask>
                    </Rectangle>
                </Grid>
            </ControlTemplate>

那么,为什么 TemplateBindingImageBrush 中会失败?


更新

通过推论(感谢克里斯的回答),可能的因素是:

我仍然看不出这些点是如何连接的……

【问题讨论】:

    标签: c# silverlight xaml windows-phone templatebinding


    【解决方案1】:

    这里有一个解决方法。奇怪的是,使用RelativeSource TemplatedParent 绑定而不是TemplateBinding 解决了这个问题。

    <ImageBrush ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Icon}" />
    

    理论上这是完全相同的绑定...所以,谁知道呢?什么都行。

    【讨论】:

      【解决方案2】:

      有趣的是,我设法从你的例子中复制了这种行为,虽然我不能完全确定,但我想我可能明白发生了什么。

      根据这个问题的答案:WPF TemplateBinding vs RelativeSource TemplatedParent 似乎虽然 两种方法实现了几乎相同的目标,它们在一些关键行为上有所不同。 Miroslav Nedyalkov 提到的最相关的一个 -

      "TemplateBindings 不允许值转换。它们不允许你 传递一个转换器并且不会自动将 int 转换为字符串 示例(这对于 Binding 来说是正常的)。”

      我猜想在第二种情况下,绑定将使用内置的 WPF 转换器将绑定的 string/URI 转换为 ImageSource(指定 ImageSource 时的常见行为 - 这就是你不这样做的原因'通常不需要指定绑定转换器)。

      在第一种情况下,您不会得到默认值转换,因此您不会看到掩码。有趣的是,如果指定了转换器,它是否会起作用。

      编辑:看起来ImageBrush 没有继承自FrameworkElement 可能会带来一些额外的复杂性:Bind an ImageBrush to a template with a DependencyProperty

      【讨论】:

      • 很好的发现——类型转换的问题似乎可以解释它。唯一让我摸不着头脑的是为什么&lt;Image Source="{TemplateBinding Icon}" ... /&gt; 能够绑定。你会认为Image.Source 会失败,原因与ImageBrush.ImageSource 失败的原因相同——这似乎是一种异常情况。
      • 嗯,你是对的 - 我添加了一个编辑,看起来可能还有其他事情发生。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多