原文链接:Silverlight 3 – System Colours
Silverlight 3 中加入了一个名为“SystemColors”类,其包括如下属性;
如果我创建一个Silverlight 应用,并在其中放入一个button(按钮)的话:
<
Button
Content
="Click Me"
FontSize
="24"
HorizontalAlignment
="Center"
VerticalAlignment
="Center"
/>
会显示如下内容:
你会看到在左侧我启动了一个计算器. 如果此时我在Windows中修改了我的系统颜色时,比如
使用”高亮对比”这种设置时;
这时会显示:
也就是计算器和FireFox会跟随着系统颜色而变化,但Silverlight 应用却不会。它还是老样子,
不受系统颜色设置的影响.
如果Silverlight应用能按用户或开发者设想的去应用这些设置(系统颜色)该多好呀。
现在,SystemColors就可以实现(尽管其仅有少数一些静态属性可以使用,且当用户修改设置时
还无法修改(通知)当前显示界面等等)。
不过,我认为如果用户刷新浏览器的话(或可以点击Silverlight UI上的一个按钮来通知当前应用
已修改了WINDOWS主题的话),这些就不是什么主要的缺失了。It’s liveable.
抱着这种想法,我打算显露出SystemColors的一些静态属性,将其作为非静态属性以便于在XAML
使用.
下面这是相关的尝试 :-)
public
class
MySystemColours
{
public
Brush ControlTextBrush
{
get
{
if
(controlTextBrush
==
null
)
{
controlTextBrush
=
new
SolidColorBrush(SystemColors.ControlTextColor);
}
return
(controlTextBrush);
}
}
Brush controlTextBrush;
}
而相应的Xaml内容如下:
<
UserControl
x:Class
="SilverlightApplication36.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local
="clr-namespace:SilverlightApplication36"
>
<
UserControl.Resources
>
<
local:MySystemColours
x:Key
="mySystemColours"
/>
</
UserControl.Resources
>
<
Grid
x:Name
="LayoutRoot"
>
<
Grid.Resources
>
</
Grid.Resources
>
<
Button
Foreground
="
{Binding Source={StaticResource mySystemColours},Path=ControlTextBrush}
"
Content
="Click Me"
FontSize
="24"
HorizontalAlignment
="Center"
VerticalAlignment
="Center"
/>
</
Grid
>
</
UserControl
>
现在,看上去已经差不多了。但我并不真想在每个控件实现上显式的设置“Foreground”和
“Background”属性,我想用一个Style来实现。
那么,我可能要创建一个Style,其使用了诸如ControlTextBrush等的brushes,以便于应用到
Buttons, CheckBoxes等等UI元素上.
这也就导致了我的第二个尝试,其 XAML代码如下;
<
UserControl
x:Class
="SilverlightApplication36.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local
="clr-namespace:SilverlightApplication36"
>
<
UserControl.Resources
>
<
local:MySystemColours
x:Key
="mySystemColours"
/>
<
Style
x:Key
="mySystemStyle"
TargetType
="Button"
>
<
Setter
Property
="Foreground"
Value
="
{Binding Source={StaticResource mySystemColours},Path=ControlTextBrush}
"
/>
</
Style
>
</
UserControl.Resources
>
<
Grid
x:Name
="LayoutRoot"
>
<
Grid.Resources
>
</
Grid.Resources
>
<
Button
Style
="
{StaticResource mySystemColours}
"
Content
="Click Me"
FontSize
="24"
HorizontalAlignment
="Center"
VerticalAlignment
="Center"
/>
</
Grid
>
</
UserControl
>
除了不能实际运行,其它看起来还都不错 :-) 问题在于我要在绑定一个 Brush值。但在Silverlight
中你不能绑定这个Brushes或 Colors值, 你只能将这些绑定应用到从FrameworkElement派生出来的元素上。
在这个论坛中有相关的主题,如果别人有不同的做法请通知我,以便我能够及时了解到.
那该怎么办呢?
好吧, 我们可以数据绑定方式来为Styles设置Brush和Color,但却不能数据绑定setters。也许我能在
运行时创建一个完整的style 并添加这些属性(到元素中);
public
class
MySystemStyles
{
public
Style ButtonStyle
{
get
{
if
(buttonStyle
==
null
)
{
buttonStyle
=
MakeStyle(
typeof
(Button));
}
return
(buttonStyle);
}
}
static
Style MakeStyle(Type t)
{
Style style
=
new
Style(t);
foreach
(var item
in
propertiesValues)
{
style.Setters.Add(
new
Setter(item.Key, item.Value));
}
return
(style);
}
static
Dictionary
<
DependencyProperty,
object
>
propertiesValues
=
new
Dictionary
<
DependencyProperty,
object
>
()
{
{ Control.ForegroundProperty,
new
SolidColorBrush(SystemColors.ControlTextColor) },
{ Control.BackgroundProperty,
new
SolidColorBrush(SystemColors.ControlColor) }
};
Style buttonStyle;
}
现在,除了默认的Button模版不依赖于Foreground 和 Background 之外,活干的差不多了。
它可以使用更多的颜色和一个BorderBrush,但也有一些颜色在Button的属性上是无效的。具我
所知也就能修改这两种属性.
我需要另外一个Button版本,其使用Foreground, Background 和 BorderBrush. 那我要如何
组合这个style呢?
我想到可以使用BasedOn style,其XAML如下;
<
UserControl.Resources
>
<
local:MySystemStyles
x:Key
="mySystemStyles"
/>
<
Style
x:Key
="buttonStyle"
BasedOn
="
{Binding Source={StaticResource mySystemStyles},Path=ButtonStyle}
"
>
在运行时无法工作( BasedOn 绑定时IE报错).
也许可以变换一下思路,当它在运行时创建一个style时,我可以通知 MySystemStyles 类。它应该
基于当前的style。看起来有些麻烦但却可行;
public
class
MySystemStyles
{
public
Style BasedOnButtonStyle
{
get
{
return
(basedOnButtonStyle);
}
set
{
basedOnButtonStyle
=
value;
}
}
public
Style ButtonStyle
{
get
{
if
(buttonStyle
==
null
)
{
buttonStyle
=
MakeStyle(
typeof
(Button), basedOnButtonStyle, buttonPropertyValues);
}
return
(buttonStyle);
}
}
static
Style MakeStyle(Type t, Style basedOnStyle, Dictionary
&
lt;DependencyProperty,
object
&
gt; propertyValues)
{
Style style
=
new
Style(t);
style.BasedOn
=
basedOnStyle;
foreach
(var item
in
propertyValues)
{
style.Setters.Add(
new
Setter(item.Key, item.Value));
}
return
(style);
}
static
Dictionary
&
lt;DependencyProperty,
object
&
gt; buttonPropertyValues
=
new
Dictionary
&
lt;DependencyProperty,
object
&
gt;()
{
{ Control.ForegroundProperty,
new
SolidColorBrush(SystemColors.ControlTextColor) },
{ Control.BackgroundProperty,
new
SolidColorBrush(SystemColors.ControlColor) },
{ Button.BorderBrushProperty,
new
SolidColorBrush(SystemColors.ActiveBorderColor) }
};
Style buttonStyle;
Style basedOnButtonStyle;
}
相应的XAML 如下;
<
UserControl
x:Class
="SilverlightApplication36.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vsm
="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:local
="clr-namespace:SilverlightApplication36"
>
<
UserControl.Resources
>
<
Style
x:Key
="buttonStyle"
TargetType
="Button"
>
<
Setter
Property
="Template"
>
<
Setter.Value
>
<
ControlTemplate
TargetType
="Button"
>
<
Grid
>
<
vsm:VisualStateManager.VisualStateGroups
>
<
vsm:VisualStateGroup
x:Name
="CommonStates"
>
<
vsm:VisualState
x:Name
="Normal"
/>
<
vsm:VisualState
x:Name
="MouseOver"
>
<
Storyboard
>
<
DoubleAnimationUsingKeyFrames
Storyboard.TargetName
="BackgroundAnimation"
Storyboard.TargetProperty
="Opacity"
>
<
SplineDoubleKeyFrame
KeyTime
="0"
Value
="1"
/>
</
DoubleAnimationUsingKeyFrames
>
</
Storyboard
>
</
vsm:VisualState
>
<
vsm:VisualState
x:Name
="Pressed"
>
<
Storyboard
>
<
DoubleAnimationUsingKeyFrames
Storyboard.TargetName
="BackgroundAnimation"
Storyboard.TargetProperty
="Opacity"
>
<
SplineDoubleKeyFrame
KeyTime
="0"
Value
="1"
/>
</
DoubleAnimationUsingKeyFrames
>
</
Storyboard
>
</
vsm:VisualState
>
<
vsm:VisualState
x:Name
="Disabled"
>
<
Storyboard
>
<
DoubleAnimationUsingKeyFrames
Storyboard.TargetName
="DisabledVisualElement"
Storyboard.TargetProperty
="Opacity"
>
<
SplineDoubleKeyFrame
KeyTime
="0"
Value
=".55"
/>
</
DoubleAnimationUsingKeyFrames
>
</
Storyboard
>
</
vsm:VisualState
>
</
vsm:VisualStateGroup
>
<
vsm:VisualStateGroup
x:Name
="FocusStates"
>
<
vsm:VisualState
x:Name
="Focused"
>
<
Storyboard
>
<
DoubleAnimationUsingKeyFrames
Storyboard.TargetName
="FocusVisualElement"
Storyboard.TargetProperty
="Opacity"
>
<
SplineDoubleKeyFrame
KeyTime
="0"
Value
="1"
/>
</
DoubleAnimationUsingKeyFrames
>
</
Storyboard
>
</
vsm:VisualState
>
<
vsm:VisualState
x:Name
="Unfocused"
/>
</
vsm:VisualStateGroup
>
</
vsm:VisualStateManager.VisualStateGroups
>
<
Border
x:Name
="Background"
Background
="
{TemplateBinding Background}
"
BorderBrush
="
{TemplateBinding BorderBrush}
"
BorderThickness
="
{TemplateBinding BorderThickness}
"
CornerRadius
="3"
>
<
Grid
Margin
="1"
Background
="
{TemplateBinding Background}
"
>
<
Border
x:Name
="BackgroundAnimation"
Opacity
="0"
Background
="
{TemplateBinding Background}
"
/>
</
Grid
>
</
Border
>
<
ContentPresenter
x:Name
="contentPresenter"
HorizontalAlignment
="
{TemplateBinding HorizontalContentAlignment}
"
Margin
="
{TemplateBinding Padding}
"
VerticalAlignment
="
{TemplateBinding VerticalContentAlignment}
"
Content
="
{TemplateBinding Content}
"
ContentTemplate
="
{TemplateBinding ContentTemplate}
"
/>
<
Rectangle
x:Name
="DisabledVisualElement"
Fill
="#FFFFFFFF"
RadiusX
="3"
RadiusY
="3"
IsHitTestVisible
="false"
Opacity
="0"
/>
<
Rectangle
x:Name
="FocusVisualElement"
Stroke
="
{TemplateBinding BorderBrush}
"
StrokeThickness
="1"
RadiusX
="2"
RadiusY
="2"
Margin
="1"
IsHitTestVisible
="false"
Opacity
="0"
/>
</
Grid
>
</
ControlTemplate
>
</
Setter.Value
>
</
Setter
>
</
Style
>
<
local:MySystemStyles
x:Key
="mySystemStyles"
BasedOnButtonStyle
="
{StaticResource buttonStyle}
"
/>
</
UserControl.Resources
>
<
Grid
x:Name
="LayoutRoot"
>
<
Grid.Resources
>
</
Grid.Resources
>
<
Button
Style
="
{Binding Source={StaticResource mySystemStyles},Path=ButtonStyle}
"
Content
="Click Me"
FontSize
="24"
HorizontalAlignment
="Center"
VerticalAlignment
="Center"
/>
</
Grid
>
</
UserControl
>
现在,它可以按我起初的想法,很好的运行了。当我在Windows中修改我的颜色主题时并刷新当前的
Silverlight 应用,按钮会去获取已修改的系统颜色.
但是,目前在按钮上只有三个属性可以设置. 我需要为每个控件设置一系列的styles,然后再去扩展
MySystemStyles 类,诸如一些:ComboBoxStyle, TreeViewStyle, TextBoxStyle 属性等等。它也
必须包括诸如BasedOnComboBoxStyle 或 BasedOnTreeViewStyle属性等等.
哎…虽然可以工作,但应该还有更好的变法吧?
Anyone got ideas? :-)
原文链接:http://www.cnblogs.com/daizhj/archive/2009/05/06/1450455.html
译者: daizhj, 代震军
Tags: silverlight,system color,系统主题,theme
网址: http://daizhj.cnblogs.com/