我试图编写一个显示背景渐变的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" />
然后我希望看到一个带有红色到灰色背景渐变的按钮。相反,只显示渐变的灰色部分:
我遗失了多么痛苦的事情?
修改强调:
答案 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" />
“您认为编译器或运行时会抛出某种错误,但显然不会。”
一个好点。我没有在输出窗口中看到任何绑定错误。但是,我使用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并不想知道)。