Metro XAML - 使用TemplateBinding和SolidColorBrush时出现的问题

5
这是一个简单的自定义控件,用于说明我的问题。
public sealed class TestControl : Control
{
    public static DependencyProperty TestColorProperty = DependencyProperty.Register("TestColor", typeof(Brush), typeof(TestControl), new PropertyMetadata(new SolidColorBrush(Colors.Blue)));

    public Brush TestColor
    {
        get { return (Brush)GetValue(TestColorProperty); }
        set { SetValue(TestColorProperty, value); }
    }

    public TestControl()
    {
        this.DefaultStyleKey = typeof(TestControl);
    }
}

如您所见,它有一个名为Brush的依赖属性,其默认值为Blue(如上所示,在PropertyMetaData中设置)。
这是我在Generic.xaml中控件的XAML代码。
<Style TargetType="local:TestControl">
        <Setter Property="TestColor" Value="Red" />
        <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:TestControl">
                <Border
                    Background="{TemplateBinding TestColor}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
                        <TextBlock Text="TEST"  />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

正如您所看到的,我在Style中设置了TestColor Brush依赖属性为红色,覆盖了默认值蓝色,如我在PropertyMetaData中声明的。请注意,我的模板中的边框使用TemplateBinding将背景设置为讨论中的刷子。
那么您认为边框背景会设置成什么颜色?红色还是蓝色?
答案都不是。
如果我在控件的某个应该可用此值的位置(例如OnApplyTemplate)中设置断点,则该值为null,而不是预期的默认值红色。实际上,我已经在控件的所有生命周期点设置了断点,并且从未使用ProprtyMetaData中的默认值。
样式中设置该值也没有任何作用(它不会根据我的样式setter delaration设置为蓝色)。这表明,对于SolidColorBrush,样式setter出现了问题。
然而,这个可以工作。
public BlankPage()
{
    this.InitializeComponent();
    testcont.TestColor = new SolidColorBrush(Colors.Orange);
}

这也可以正常工作:

<Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
    <local:TestControl  TestColor="Green" />
</Grid>

但是TemplateBinding根本不起作用,这很重要,因为我正在尝试编写可重复使用的自定义控件。

这是一个 bug 吗?

迪恩

5个回答

0

个人认为这可能是XAML解析器中的某个错误。尝试使用以下代码,应该可以解决问题:

    <Setter Property="SelectedDayBrush">
        <Setter.Value>
            <SolidColorBrush>#7F7F7F7F</SolidColorBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="SelectedDayBrush">
        <Setter.Value>
            <SolidColorBrush Color="Orange"/>
        </Setter.Value>
    </Setter>

很奇怪,我遇到了同样的问题,看了一下我的编辑答案 - 这些都在我的当前项目中工作。 - notacat

0

这是我们正在努力解决的问题。在此期间,请按照以下方式设置:

<SolidColorBrush x:Key="DefaultTestColorBrush">Red</SolidColorBrush>

然后在你的模板中:

<Setter Property="TestColor" Value="{StaticResource DefaultTestColorBrush}" />

那么你现在应该能够清除这个障碍了。


很抱歉,这种方法也不起作用(使用TemplateBinding或RelativeSource/TemplatedParent都没有效果)。 - Dean Chalk
你们修复这个问题的预计时间是什么?在游戏的这个晚阶段,我真的很惊讶一些XAML基础知识,比如颜色和模板绑定,竟然还没有。我目前正在编写一个用于商业销售的Metro控件套件,如果Metro/XAML不能正常工作,我无法实现这个目标。 - Dean Chalk

0

看起来还没有被修复。如果您开发了类似自定义按钮的东西,而PointerOver效果只是较浅的背景,则一个有效的技巧是在内容上方放置一个具有白色背景的不可见PointerOverVisual。然后PointerOver动画将使其略微可见。这就是我使用的方法:

<VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames   Storyboard.TargetProperty="Opacity" Storyboard.TargetName="pointerOverVisual">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="0.15"/>
                                    </ObjectAnimationUsingKeyFrames>

.......

<Border x:Name="Border" BorderThickness="0" Background="{TemplateBinding Background}" Margin="3">   
        content here                                                    
</Border>
    <Rectangle x:Name="pointerOverVisual" Fill="White" Opacity="0" Margin="3"/>
    <Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
    <Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>

0

我有一个可行的解决方案,它使用了一个自定义控件,而这个自定义控件又被多次放置到一个用户控件中(这在我的框架中非常好用且可重复使用)。

(在generic.xaml中,记得我创建了一个自定义控件)

<Style TargetType="local:myPad">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:myPad">
                <Path Data="..." Height="60" Width="30" Fill="{TemplateBinding myPadColor}"/>

(在myPad.cs中)

    public sealed class myPad : Control
    {
        public myPad()
        {
            this.DefaultStyleKey = typeof(myPad);
        }

        public SolidColorBrush myPadColor
        {
            get { return (SolidColorBrush)GetValue(PadColorProperty); }
            set { SetValue(PadColorProperty, value); }
        }

        public static readonly DependencyProperty PadColorProperty =
            DependencyProperty.Register("myPadColor", typeof(SolidColorBrush), typeof(myPad), new PropertyMetadata(null));
}

在我的用户控件中,我放置了模板控件并可以拥有多个相同的“颜色”版本...
<UserControl
    x:Class=....
    <Canvas Width="235" Height="235">
        <local:myPad x:Name="thisPad" myPadColor="White">

...

我删去了很多多余的东西(...), 但我认为你已经明白了这里的意思。我现在也相信,你可以使用另一个绑定来控制用户控件或者在代码后台中来实现更多的创意。

顺便说一下,我正在使用带有SP3的VS2012..所以也许现在已经修复了一些问题。

此外,我对编程XAML还是比较新手,但在Tim Heuer的博客上,我找到了正确的方法来实现依赖属性(感谢Tim!)

如果你将propertymetadata值中的(null)替换为(new SolidColorBrush(Colors.Black)),你将在设计模式下得到一个默认值。

:)

希望这能帮到你。


0
您可以尝试以下代码片段来绑定TestColor:
 Background="{Binding  RelativeSource={RelativeSource TemplatedParent}, Path=TestColor}"

希望这对你有所帮助。

祝好, Rex


@Dean Chalk 这样可以行吗?应该可以,因为TemplateBinding是在编译时评估的,而Binding RelativeSource.. "获取"了运行时值 - 我想这可能是您绑定时遇到的问题。 - fex

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