使用Silverlight 4&
WPF 4,我试图创建一个按钮样式,改变任何包含的文本的文本颜色,当按钮是mouSEOver’d.因为我试图使它兼容Silverlight& WPF,我正在使用视觉状态管理器:
<Style TargetType="{x:Type Button}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border x:Name="outerBorder" CornerRadius="4" BorderThickness="1" BorderBrush="#FF757679"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="MouSEOver"> <Storyboard> <ColorAnimation Duration="0" To="#FFFEFEFE" Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="contentPresenter"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid> <Border x:Name="Background" CornerRadius="3" BorderThickness="1" BorderBrush="Transparent"> <Grid> <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}"/> </Grid> </Border> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter>
既然这是一个常规的旧按钮的模板,我知道这里不存在一个文本框,不知道这是甚么可能的.奇怪的是,如果按钮被声明为如下,文本颜色会改变:
<Button Content="Hello,World!" />
但是如果按钮被声明为:
<Button> <TextBlock Text="Hello,World!" /> <!-- Same result with <TextBlock>Hello,World </TextBlock> --> </Button>
即使视觉树(在snoop中进行检查)是相同的(Button – > ContentPresenter – > TextBlock),与第一版本中创建的文本块的数据上下文设置为“Hello,World”的警告相反,第二个版本中的textblock仅设置其text属性.我假设这与控件创建的顺序有关(按钮创建TextBlock的第一个版本,在第二个版本中可能会首先创建文本框),真的不知道这一点).
在研究这个过程中,我看到了一些在Silverlight中工作的解决方案(比如用ContentControl替换ContentPresenter),但这在WPF(程序实际上是崩溃)中不起作用.
因为这是在按钮的控件模板中,如果可能,我想使用VSM,我认为也排除了显式地更改Button自己的Foreground属性(我不知道如何从模板中访问它? )
我真的很感激任何帮助,任何人都可以给予.
解决方法
所以经过一些思考之后,我最终得到的解决方案是在按钮控件模板中的ContentPresenter元素中添加一个附加的属性.附加的属性接受颜色,当设置检查任何TextBlocks的内容呈现者的可视树,并将Foreground属性设置为传入的值.这显然可以扩展/使其处理其他元素,但现在它工作为我所需要的
public static class ButtonAttachedProperties { /// <summary> /// ButtonTextForegroundProperty is a property used to adjust the color of text contained within the button. /// </summary> public static readonly DependencyProperty ButtonTextForegroundProperty = DependencyProperty.RegisterAttached( "ButtonTextForeground",typeof(Color),typeof(FrameworkElement),new FrameworkPropertyMetadata(Color.FromArgb(255,0),FrameworkPropertyMetadataOptions.AffectsRender,OnButtonTextForegroundChanged)); public static void OnButtonTextForegroundChanged(DependencyObject o,DependencyPropertyChangedEventArgs e) { if (e.NewValue is Color) { var brush = new SolidColorBrush(((Color) e.NewValue)) as Brush; if (brush != null) { SetTextBlockForegroundColor(o as FrameworkElement,brush); } } } public static void SetButtonTextForeground(FrameworkElement fe,Color color) { var brush = new SolidColorBrush(color); SetTextBlockForegroundColor(fe,brush); } public static void SetTextBlockForegroundColor(FrameworkElement fe,Brush brush) { if (fe == null) { return; } if (fe is TextBlock) { ((TextBlock)fe).Foreground = brush; } var children = VisualTreeHelper.GetChildrenCount(fe); if (children > 0) { for (int i = 0; i < children; i++) { var child = VisualTreeHelper.GetChild(fe,i) as FrameworkElement; if (child != null) { SetTextBlockForegroundColor(child,brush); } } } else if (fe is ContentPresenter) { SetTextBlockForegroundColor(((ContentPresenter)fe).Content as FrameworkElement,brush); } } }
我修改了模板:
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" local:ButtonAttachedProperties.ButtonTextForeground="{StaticResource ButtonTextNormalColor}" />