Windows Phone 7 学习志(常见问题一:不能直接修改按钮Button背景色或前景色)

这个问题对于初学者估计是个蛮大的问题,至少我当初就是这样,听到同事说点击按钮事件中按钮前景色无法修改,心里十分纳闷,这怎么可能呢?可是当自己新建了一个页面,加了一个按钮和一个点击事件后,事实还就真的发生了。

  前台按钮代码:

<Button Content="Button" Background="Blue" Click="button1_Click" Height="173" HorizontalAlignment="Left" Margin="94,70,0,0" Name="button1" VerticalAlignment="Top" Width="267"/>

 

  为了看的明白点,把按钮背景色先设成了Blue,其他参数都可以无视。

  后台CS代码增加按钮事件:

 

privatevoid button1_Click(object sender, RoutedEventArgs e)
{
button1.Background
=new SolidColorBrush(Colors.Red);
}

  运行程序,点击按钮,的确一点反应都没有,那是为什么呢?想来无非那几种情况:

第一:值没有真正传入属性。

第二:难道和网页一样,需要刷新才能传值成功?

第三:存在内部其他机制。

  我们一个个来分析。

第一:把button1.Background = new SolidColorBrush(Colors.Red);放入画面初始化方法InitializeComponent()的后面,运行后,颜色改变,说明传值不存在问题。

第二:我表示我不知道刷新方法是哪个,要是读者知道可以告诉我。

第三:既然前两个都是未知,那必然这个原因嫌疑最大了。

遇到该问题时我查询了MSDN上WP7专区的疑问解答,有个链接把我指向了http://blogs.msdn.com/b/ptorr/archive/2010/06/18/why-can-t-i-change-the-background-of-my-button-on-a-click-event.aspx

  简单说明下该文章说明的关键:Silverlight使用VisualStateManager来显示不同的视觉状态(像普通,被按住等等动作),桌面版本的Silverlight的控制模板比手机中使用控制模板要复杂的多,所以桌面版本的Silvelight没有这个问题。

  那什么是VisualStateManager呢,是前台的设置还是后台的设置呢?

  先上示例:http://samples.msdn.microsoft.com/Silverlight/SampleBrowser/index.htm#/?sref=CustomTemplateSamples&id=3

  打开后是一个Silverlight Sample,鼠标放到按钮上然后移开有不同的效果,其实在WP7上也有一样的效果,只不过是按住鼠标后经过按钮有效果。点击上方的view sample source code,可以看到xaml文件里满满当当,cs文件里几乎没有代码,仅有的代码也和主题无关。

如此满满当当的代码自然理解起来非常难,想系统理解的可以去看“通过使用 ControlTemplate 自定义现有控件的外观”:http://msdn.microsoft.com/zh-cn/library/cc189093(v=VS.95).aspx

  回到正题,如何才能实现点击后改变背景色和前景色呢?

关键部分:借助Visual State Manager,自定义一个按钮模板,这样就可以对应用模板的按钮的参数进行修改。

下面是个按钮的基础模板文件(取自前面提到的一个网页里),我用绿颜色标注了下修改部分。先扫一遍,然后我会说这么昂长的代码哪里可以获得。总不见要自己输入对吧。

 

代码
<Button Content="Click Me" x:Name="ClickMe" Click="ClickMe_Click" Background="Red">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentContainer"
Storyboard.TargetProperty
="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PressedHighlightBackground"
Storyboard.TargetProperty
="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonBackground"
Storyboard.TargetProperty
="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentContainer"
Storyboard.TargetProperty
="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonBackground"
Storyboard.TargetProperty
="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonBackground"
Storyboard.TargetProperty
="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness
="{TemplateBinding BorderThickness}" CornerRadius="0"
Background
="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
<Border x:Name="PressedHighlightBackground" Background="Transparent">
<ContentControl x:Name="ContentContainer" Foreground="{TemplateBinding Foreground}"
HorizontalAlignment
="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment
="{TemplateBinding VerticalContentAlignment}" Padding="{TemplateBinding Padding}"
Content
="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
</Border>
</Border>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>

 

 

 

  乍看一下,属性分支很多,很乱。我们暂且不纠结与这个代码,要我说的话,也就是增加了一个背景属性和一个边框,然后把背景属性指向了边框,把原先背景设成了透明。如果再重新在后台进行背景色的修改,你会发现,成功了。但是前景色怎么弄呢?而且偶尔每个按钮都要这么长的前台代码未免太麻烦了吧,况且如果按钮是自动生成的话怎么办呢,所以刚才让你系统的去看那篇“通过使用 ControlTemplate 自定义现有控件的外观”也是必要的,里面讲到很多不同的实现方法。

  接下来我来讲一下模板代码的来源,如果你是正常安装开发工具环境的话,你应该还记得那个Microsoft Expression Blend 4吧,那个UI设计工具。运用这个工具,你可以简单的获取和制作控件模板。打开程序后,新建一个项目,然后左半边内容如下图:

  点击Assets标签,从中拖一个按钮控件到页面中,画面左下角对象里多出一个Button,右键Button,点击Edit Template – Edit a Copy,弹出对话框,自己填写要保存的样式名字,然后确定,你会发现左下角变了,右键任何一个对象然后点View XAML可以查看前台代码。然后你点击左上角的States,会发现里面多出很多东西。

  这其实是原始模板按钮的状态行为,有兴趣的可以自己去找Expression Blend 4的相关教程,这个教程可比WP7教程多得多。举个例子,你想点击按钮后,按钮前景色变成自己想要的,并且不想按钮下次再能点击,你直接在点击按钮操作方法里把按钮的IsEnabled属性设成false就可以了,因为false状态下的前景色你可以在Expression Blend 4中的States的Disabled状态进行方便的设置,然后你只要把自己想要的那段Style代码复制到前台里,在需要使用的按钮属性中加上一条Style属性即可。就此这个方法的介绍就此结束。

  总结一下:今天的主题是前台的Visual State Manager,虽然后台代码相比前台更亲近我们,但这次前台的的确确做了很大的贡献,我觉得既然修改如此麻烦,必然以后就会有改变。当然我也不能说我介绍的这个方法就是最好的,如果有更好的,希望能告诉我,因为现在做的程序里用到这方面其实还蛮多的。初学者有空的还是像我说的多去我上篇日志介绍的MSDN的论坛搜索问题,虽然全是E文,但是帮助很大,比如你觉得Foreground不能修改,你关键字打Foreground就可以了。今天这篇写的比较急,也有点乱,觉得哪里有问题的希望大家多提出来。

作者:Le Ruin
出处:http://www.cnblogs.com/leluyun/
关于作者:专注于Windows Phone 开发
Windows Phone Store上不再有作者独立开发的程序,但作者依然还在开发的路上前行。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过新浪微博 leluyun@hotmail.com 联系我,非常感谢。

原文地址:https://www.cnblogs.com/leluyun/p/1949914.html