使用“Color”类型依赖属性的控件

时间:2013-07-24 20:48:21

标签: c# silverlight xaml dependency-properties controltemplate

我试图编写一个显示背景渐变的Button控件,从自定义属性指定的颜色开始,以硬编码颜色结束。在我看来,这应该是一个简单的控制模板,但我不能让它工作。

Subclassed" Button"具有Color依赖属性:

public class GradientButton : Button
{
    public Color BackgroundColor
    {
        get { return (Color)GetValue(BackgroundColorProperty); }
        set { SetValue(BackgroundColorProperty, value); }
    }

    public static readonly DependencyProperty BackgroundColorProperty =
        DependencyProperty.Register("BackgroundColor", typeof(Color), typeof(GradientButton), new PropertyMetadata((sender, args) => {
            System.Diagnostics.Debug.WriteLine("Set bg col");
        }));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(GradientButton), null);
    public GradientButton()
        : base()
    {
        this.DefaultStyleKey = typeof(GradientButton);
    }
}

控制模板,使用BackgroundColor DP设置背景渐变:

<Style TargetType="custom:GradientButton">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Top" />
    <Setter Property="Width" Value="200" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="custom:GradientButton">
                <Grid>
                    <Grid.Background>
                        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                            <GradientStop Color="{TemplateBinding BackgroundColor}" Offset="0" />
                            <GradientStop Color="Gray" Offset="1" />
                        </LinearGradientBrush>
                    </Grid.Background>

                    <TextBlock Text="{TemplateBinding Text}" />
                    <TextBlock Text="{TemplateBinding BackgroundColor}" HorizontalAlignment="Right" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果我像这样使用控件:

<custom:GradientButton Text="Foo" BackgroundColor="#FF0000" /> 

然后我希望看到一个带有红色到灰色背景渐变的按钮。相反,只显示渐变的灰色部分:

Control does not show the red part of the background

我遗失了多么痛苦的事情?


修改强调:

  1. 我添加了#34; Text&#34; DP来证明我的DP / TemplateBinding实际上是犹太洁食。
  2. 请注意,我无法显示&#34; BackgroundColor&#34;,即使是文本块中的文本 - 但我已在调试器中确认实际上已设置为控件

3 个答案:

答案 0 :(得分:1)

没问题,

你的第一个问题是你如何宣布你的渐变。您目前的方式将显示上半部分的实线红色(或指定的任何颜色),下半部分显示实线灰色。你想要这样的东西,它会为你完成剩下的工作。

<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
     <GradientStop Color="Red" Offset="0"/>
     <GradientStop Color="Gray" Offset="1"/>
</LinearGradientBrush>

此外,您可以更轻松地对自己进行操作,只使用已经存在的属性就像这样的目的,因此您不需要任何其他代码。就像Tag属性一样(根据实例,我个人将各种不同的垃圾填入不同的目的。所以像这样的东西也足够了,不需要额外的依赖声明(除非真的很重要)叫做“BackgroundColor”);

<Style TargetType="custom:GradientButton">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Top" />
    <Setter Property="Width" Value="200" />
    <Setter Property="Tag" Value="Red"/><!-- For the sake of having a default -->

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="custom:GradientButton">
                <Grid>
                    <Grid.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                             <GradientStop Color="{TemplateBinding Tag}" Offset="0"/>
                             <GradientStop Color="Gray" Offset="1"/>
                        </LinearGradientBrush>
                    </Grid.Background>

                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

那应该做得很好,希望这会有所帮助。 :)

答案 1 :(得分:1)

很抱歉让人感到困惑。我的回答不正确。这里的问题是TemplateBinding。 TemplateBinding在编译时是一个lightwight绑定,而TemplateParent在运行时发生,因此TemplateBinding有一些限制,其中一个限制是它无法绑定到Freezables。您可以做的是使用传统的模板化父级:

<GradientStop Color="{Binding Path=BackgroundColor, RelativeSource={RelativeSource TemplatedParent}}" Offset="0" />

您可以参考http://blogs.msdn.com/b/liviuc/archive/2009/12/14/wpf-templatebinding-vs-relativesource-templatedparent.aspx

“您认为编译器或运行时会抛出某种错误,但显然不会。”

一个好点。我没有在输出窗口中看到任何绑定错误。但是,我使用Snoop来查看Color属性,并找到了我所期望的内容:

  

System.Windows.Data错误:2:找不到目标元素的管理FrameworkElement或FrameworkContentElement。 BindingExpression:路径= BACKGROUNDCOLOR;的DataItem = NULL; target元素是'GradientStop'(HashCode = 4605357); target属性为'Color'(类型'Color')

答案 2 :(得分:1)

我发现了一种解决方法:如果我使用TemplateBinding绑定代替RelativeSource,那么我的按钮会按照您的预期呈现:

Color="{Binding RelativeSource={RelativeSource AncestorType=custom:GradientButton},Path=BackgroundColor}"

当然,这使得没有任何意义。我确信这是一个错误(或至少其中一个 man并不想知道)。