Fun with Silverlight2.0系列之三 -- Skinnable动态换肤效果

前段时间国外的大牛为Silverlight2定义了四套皮肤,效果让人称奇,美中不足的是四个皮肤不能动态切换,
所以我借花献佛将这四套皮肤放在一起实现了动态切换也就是换肤的效果。
开发平台:VS2008 + Silverlight2

Live Demo

效果图:

选择Bubbly皮肤


选择Flat皮肤


选择Red皮肤


选择Rough皮肤


实现技术主要是利用两个小技巧,
首先是ResourceDictionary,ResourceDictionary中文译做资源字典,顾名思义,就是一个用来存放资源的集合。
ResourceDictionary元素中可以直接嵌入资源,在资源文件里定义
ControlTemplate,因为所有的皮肤其实呈现的都是同样的控件,
所以将所有的控件写在里面便于实现元素的重用,然后所有控件的Style属性都和相应的Style动态绑定。

资源文件

保存这个资源文件为generic.xaml并设置为嵌入式资源。通过删除Custom Tool属性值并设置Build Action为Resource。
这样就可以动态的定义样式和资源文件里的控件模板绑定了。

下面说一说动态定义样式的小技巧,那就是依赖属性(DependencyProperty),它其实是WPF的核心技术点之一,和DependencyObject配合,
提供了WPF中基本的数据存储、访问和通知的机制,具体可参见MSDN上的解说DependencyProperty
这篇博客也说的不错WPF中如何实现数据与表示分离。


属性绑定

完成了这两点程序已经可以动态切换皮肤了,自动查找皮肤文件的功能其实可有可无,但是这样做可以省却维护配置文件的麻烦,
首先定义一个Skin的属性:

1namespace Skinnable
2{
3    [AttributeUsage(AttributeTargets.Class)]
4    public class SkinAttribute : Attribute
5    {
6        public string DisplayName getset; }
7    }

8}
然后所有的皮肤样式都实现这个属性,比如:
1    [Skin(DisplayName = "Red")]
2    public partial class RedSkin : UserControl, ISkin
3    {

最后在Assembly里找到所有实现Skin属性的皮肤,保存到List中做成画面上面的菜单
 1internal List<SkinDefinition> AppSkins getprivate set; }
 2
 3public App()
 4        {
 5            this.AppSkins = new List<SkinDefinition>();
 6            ScanAssemblyForSkins(Assembly.GetExecutingAssembly());
 7        }

 8
 9        /// <summary>
10        /// Scans an assembly for skins
11        /// </summary>
12        /// <param name="asm"></param>

13        private void ScanAssemblyForSkins(Assembly asm)
14        {
15            if (asm != null)
16            {                
17                LoadSkins(asm);
18            }

19        }

20
21
22        /// <summary>
23        /// Loads all the calculator skins that can be found inside the assembly
24        /// </summary>
25        /// <param name="asm"></param>

26        private void LoadSkins(Assembly asm)
27        {
28            // Look for all internal static classes in the assembly
29            var classTypes = from type in asm.GetTypes()
30                             let attr = GetSkinAttribute(type)
31                             where type.IsAbstract == false && type.IsClass == true && attr != null
32                             select new { ClassType = type, SkinAttribute = attr };
33
34            foreach (var ct in classTypes)
35            {
36                string name = ct.SkinAttribute.DisplayName;
37                if (string.IsNullOrEmpty(name))
38                    name = ct.ClassType.Name;
39
40                this.AppSkins.Add(new SkinDefinition(name, ct.ClassType));
41            }

42        }

43
44        /// <summary>
45        /// Finds the SkinAttribute if it is on the type
46        /// </summary>
47        /// <param name="member"></param>
48        /// <returns></returns>

49        static private SkinAttribute GetSkinAttribute(Type type)
50        {
51            return (from a in type.GetCustomAttributes(typeof(SkinAttribute), true)
52                    select a as SkinAttribute).FirstOrDefault();
53        }

代码下载:http://files.cnblogs.com/ithurricane/Skinnable.zip

到这里动态换肤的程序就告一段落了,但现在有一个问题,那就是假如有两个皮肤文件A和B,A定义了Button的皮肤,B中没有定义,
那么A切换到B,Button如何回到原始的样子?如果不同的样式文件定义的控件不一致有什么好方法调整吗?



作者:ithurricane
出处:http://ithurricane.cnblogs.com
联系:ithurricane@126.com
MSN:ithurricane@hotmail.com
QQ:20158686
Tag标签: silverlight2
0
0
(请您对文章做出评价)
« 上一篇:Fun with Silverlight系列之二 -- Accordion多层折叠效果
» 下一篇:Fun with Silverlight2.0系列之四 -- PictureSlide仿网易新闻图片轮转效果V1.0
posted @ 2008-04-01 13:04 ithurricane 阅读(3251) 评论(14)  编辑 收藏 网摘 所属分类: Fun with Silverlight2.0

不错,坐上沙发
  回复  引用  查看    
#2楼[楼主]2008-04-01 13:33 | ithurricane      
@自由、创新、研究、探索……
多谢高手的支持啊

  回复  引用  查看    
#3楼2008-04-01 13:40 | 生鱼片      
我也支持下
  回复  引用  查看    
#4楼[楼主]2008-04-01 14:19 | ithurricane      
@生鱼片
多谢,我写的或说明的有不正确的地方,也希望多多指点哦

  回复  引用  查看    
#5楼2008-04-01 15:44 | jillzhang      
支持,看好sliverlight
  回复  引用  查看    
#6楼[楼主]2008-04-01 15:59 | ithurricane      
@一瞬间
你是说我写错了?

  回复  引用  查看    
#7楼[楼主]2008-04-01 16:00 | ithurricane      
@jillzhang
恩,我相信随着大家对SL2研究不断的深入,会越来越有信心的

  回复  引用  查看    
#8楼2008-04-01 22:45 | 留恋星空      
很漂亮,心动
  回复  引用    
#9楼2008-09-05 11:00 | 匆匆过客[未注册用户]
博主可否重做一份 beta2版本的 demo?
现在微软不支持beta1 原有的demo无法运行

我在做beta2时 遇到的一个问题时 怎么把选定的style应用到 新建的控件上

您的这个帖子 附的几张图 各个控件(比如 slider,datagrid,)定义在 beta1 demo里的 generic.xaml
我复制修改generic.xaml到beta2 运行时 这些控件都不可见 图片和选择皮肤名称的_skinsPopup 可以显示

多谢

  回复  引用    
#10楼2009-01-21 17:30 | 疑问[未注册用户]
这个,好像是重做了多份控件页面。无法实现样式和页面分离,类似CSS之于HTML那样……
  回复  引用  查看    
#11楼2009-02-17 17:31 | 咸鱼翻身      
sl2不能使用
好多属性升级都没有了