如何将WPF效果颜色绑定到ControlTemplate的前景或背景?

6
我在绑定ControlTemplate中Effect的Color属性时发现了一些奇怪的行为。当直接设置值时,我可以将颜色定义为字符串(例如“Red”)或十六进制值(例如#FFFF0000)。
然而,使用绑定时,仅当颜色定义为字符串时才起作用,在ControlTemplate样式中这是一个问题,因为我想使用TemplateParent属性的颜色,这些属性被绑定为十六进制值。
例如,请查看以下XAML代码(抱歉,我知道它很长,但我想展示所有情况):
<Window x:Class="EffectTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>

        <!-- 
        STYLE 1 
        This works, as the Color is hard coded, but note that the hard 
        coded value is identicle to the value in Style 2 (which doesn't work).
        -->
        <Style x:Key="Style1" TargetType="{x:Type Button}">
            <Style.Setters>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border Width="{TemplateBinding Width}"
                                    Height="{TemplateBinding Height}"
                                    Background="{TemplateBinding Foreground}">
                                <Border.Effect>
                                    <DropShadowEffect Color="#FFFF0000"/>
                                </Border.Effect>
                                <TextBlock Foreground="White" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>

        <!--
        STYLE 2
        This fails (the dropshadow appears black) even through the value being bound to is the same as Style 1.
        -->
        <Style x:Key="Style2" TargetType="{x:Type Button}">
            <Style.Setters>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border Width="{TemplateBinding Width}"
                                    Height="{TemplateBinding Height}"
                                    Background="{TemplateBinding Foreground}">
                                <Border.Effect>
                                    <!--NOTE: TemplateBinding does not work at all... <DropShadowEffect Color="{TemplateBinding Background}"/>-->
                                    <DropShadowEffect Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"/>
                                </Border.Effect>
                                <TextBlock Foreground="White" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>

        <!--
        STYLE 3
        This works, but note that I am binding to "Name" for the Color, which just happens to be a valid color "Red".
        -->
        <Style x:Key="Style3" TargetType="{x:Type Button}">
            <Style.Setters>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border Width="{TemplateBinding Width}"
                                    Height="{TemplateBinding Height}"
                                    Background="{TemplateBinding Foreground}">
                                <Border.Effect>
                                    <DropShadowEffect Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Name}"/>
                                </Border.Effect>
                                <TextBlock Foreground="White" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Name}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>
    </Window.Resources>

    <StackPanel Width="150">
        <Button Style="{StaticResource Style1}" Foreground="LightBlue" Background="Red"></Button>
        <Separator Visibility="Hidden" Height="5"/>
        <Button Style="{StaticResource Style2}" Foreground="LightBlue" Background="Red"></Button>
        <Separator Visibility="Hidden" Height="5"/>
        <Button Style="{StaticResource Style3}" Foreground="LightBlue" Name="Red"></Button>
    </StackPanel>
</Window>

结果如下:

结果

为什么会这样呢?有没有办法解决?我想要在控件模板的效果中使用按钮的背景和前景属性。


情况二:您遇到了绑定错误,因为TemplatedParent的“Background”类型不是“Color”,而是“System.Windows.Media.Brush”。 - kennyzx
1
解决方法是定义一个转换器,将Brush(在这种情况下为SolidColorBrush)转换为Color。 - kennyzx
感谢 @kennyzx 提供的替代方案! - Goose
1个回答

10
是的,Background 是一个 Brush 对象。如果你的模板背景属性是纯色,则可以将 Color 属性绑定到 Background 的 color 属性,例如: {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color} 或者你也可以使用转换器。
更新后的代码示例:
<Style x:Key="Style2" TargetType="{x:Type Button}">
    <Style.Setters>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border Width="{TemplateBinding Width}"
                            Height="{TemplateBinding Height}"
                            Background="{TemplateBinding Foreground}">
                        <Border.Effect>
                            <!-- Now uses Background.Color -->
                            <DropShadowEffect Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}"/>
                        </Border.Effect>
                        <TextBlock Foreground="White" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>

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