关于开发WPF的一些感想

开发的技术细节本文就不谈了,作者只想从感性上谈谈学习和实际开发WPF的感想。

      首先祝大家新年快乐,小生给大家拜个晚年!

      两年前暑假,从百度百科上第一次了解WPF,被它的强大特性所吸引,当然最让我着迷和期待的就是“绚丽”二字。两年来,放弃了曾经的Winform开发知识,全面转战WPF,开发了两三个大型项目,七八个游戏,和一些小型应用程序。也从当年的热烈走向现在的稳重。因此,愿意更从感性的角度讨论关于WPF的一些感想。

      本人只是在读研究生,且并非计算机科班出身,因此不足之处请海涵。

MVVM模式的思考

      以前开发winform程序,界面和程序是死死耦合在一起的,当修改了变量命名,改个样式,或者做了一些其他修改(那会还不知道resharper),不得不花费很长时间来“擦屁股”,因此深之界面和逻辑解耦的重要性。

      WPF很好的解决了这个问题,在设计之初就如此考虑,并引入了大名鼎鼎的MVVM模式。一开始不大了解,做得多了就懂了,一个ViewModel是不知道View的存在的,更利于分工合作,更利于单元测试。好处多得不得了。

     可是,凡是总有弊端,MVVM确实适应于大量数据的展示,修改等“业务逻辑”,通过数据和命令绑定,触发器等等的功能,可以很好的适应这种需求。可是,并非所有程序都是这种类型的,试想,开发一款简单的游戏,你需要控制时间线,动画效果,复杂样式还有数不清的其他需求。此时,你会发现,除了直接用ViewModel操作View,别无他法。当然,如果硬要做分离的话,也可以,附加行为(AttachBehavior)就是干这个的,通过静态依赖属性,写一个附加类来做这个,可惜,代码复杂度成倍增加,需要较高的学习成本,把简单问题搞复杂了。

     因此,我想说的是,MVVM是个好模式,可是别太追求完美,千万别捡了芝麻丢了西瓜,实在不行就耦合一下,这是一个很大的收获。

绑定到弱类型的xaml

      我和所有程序员一样,喜欢强类型的安全感。

      xaml绑定到了弱类型,好处在于更好的解耦,坏处在于没有了编译器和重命名工具的支持。我曾经用ReSharper修改变量名,从坐标名称”X“改成”PositionX“,于是,整个系统被这个重命名搞得一塌糊涂,让我修改了整整一天。运行时的绑定异常,比编译时更麻烦,好在有snoop.

      不过,这个没办法。慢慢适应吧。

到底是依赖属性还是INotifyCollectionChanged?

      常常需要在数据发生改变时通知界面(View)。于是便有了上面的问题。

      依赖属性真是个好东西,通过玩”静态“二字,玩得真是漂亮。博客园里有不少介绍依赖属性和附加属性的文章,此处就不引述了。它算是WPF的根基,动画,资源,绑定,无处不在的依赖属性。

      附加属性更是神奇,可以把属性记录在别的地方,”附加“这词用的很好。这让人想起了装饰器模式,动态增加属性和行为,只不过属性存储在了别的地方。

      既然依赖属性这么强大,我们干嘛还累死累活的让数据实现INotifyCollectionChanged接口?还写一堆麻烦的数据更新通知?比如如下恶心的代码:

private short _BreathRate;
       public short BreathRate
    {
        get { return _BreathRate; }
        set
        {
            if (_BreathRate != value)
            {
                _BreathRate = value;
                OnPropertyChanged("BreathRate");
            }

        }
    }

    这样的代码在WPF中无处不在,恶心死人。可是,如果用依赖属性的话,也会带来问题,有如下原因:

      1. 依赖属性的性能(肯定比原生的属性要慢)

      2. 依赖属性不能跨线程访问!包括读!这个问题在多线程情况下真是要命

      3. 必需继承于DependencyObject, 这不仅让你唯一的继承机会丧失,还引入了万恶的System.Windows命名空间,于是,你的未来代码移植会造成极大地困难。

      因此,我们有如下结论:

      算法和底层数据结构:毫无疑问,让它纯净一些,用INotifyCollectionChanged

      界面相关:包括自定义控件,自定义效果等等,放心的用依赖属性吧,绝对是正确选择。

     只有这样,界面逻辑解耦的愿望才能实现。

3D

       WPF号称支持3D,但我依旧要吐槽它,除了让人无法忍受的效率问题,开发工具,教学资料的匮乏,都让WPF的3D处于难以为继的状态。据我所知,仅有3DTools这些简单的WPF的3D扩展工具,以及一些很简单的辅助设计工具。用WPF开发3D,除非万不得已,否则我不会用它。在这一点上,WPF完全可以向Unity3D学习。

第三方类库

        WPF是个界面库,它天生就为良好的扩展性做好了准备。虽然不算多,但大部分需要的类库都有了,Avalondock, WPFToolkit, 物理引擎库,等等不一一列举了。这些库都比较新,不过很难看到WPF设计的完整软件作品,起码在国内看不到,他们都哪里去了???

性能

       程序性能问题,是任何程序员都非常关心的。WPF的性能疑问,来自两个方面,一个是动画,一个是数据更新造成的UI更新。

       我开发了几个游戏,发现比较复杂的物体移动,总会出现卡顿,那种令人不爽的“虚”感。使用更快的CPU和独立显卡可以较好的解决这个问题,可是在3317U这样的超级本平台上,程序运行起来风扇哄哄响,占用率达到一半。远远达不到unity3d这类3D平台上的性能和质量。同样效果的flash动画,也没有这种卡顿。这到底是怎么回事?

       在数据绑定上,我曾经懒惰的通过OnPropertyChanged(“”)的方式更新全部数据,但造成了严重的性能问题,因此建议仅更新对应的数据。

设计和美学

      这是个复杂的问题,有专门的学科研究,本部分仅浅尝辄止。

      我的经验,WPF在2D层面不限制你的任何想象力。但我有如下建议:对于一般软件而言,避免不必要的花哨,提供统一直观的UI效果是非常重要的,动画等技术的存在,仅在于表达数据和信息本身,若造成用户干扰,则有”炫技“嫌疑的东西可完全不要。Expression Design套件的设计对我们有很好的借鉴,黑色底色,淡灰色的文字,让你专注于设计本身,而非工具。我们应该专注如何让用户更好的关注数据。

     对于游戏或播放器等娱乐音乐而言,则设计思路有所不同。可以适当加入动画,在配色等角度可以更活泼,但一定注意整体设计的协调,与主题的搭配程度非常重要。

     设计是个复杂的事情,没事可以逛逛很多平面设计论坛,都有很大的收获。

前景?

      打个疑问号,表示该问题值得讨论。我没有真正深入业界,因此本节仅供参考。

      06年WPF技术公开,在08-09年貌似达到高峰。据我所知,博客园的绝大多数关于WPF的文章都是这个时期发布的,Blend等工具的出现,大大改进了界面设计方便性。但貌似,我这个软件控也没有看到除了微软这套Studio之外的,任何以WPF开发的商业软件系统。360,QQ,各类音乐播放器等等都没有,只有QQ概念版基于WPF,可是之后也没有更新了。究其原因,大概是需要安装.NET 3.5甚至4.0以上版本,部署起来不甚方便。也与当前程序普遍WEB化不无关系,

       但我依旧疑问,为什么在2010年之后,博客园很少有系统的WPF开发文章了?为什么到现在都没有客户端的WPF系统?它的前景究竟如何?

       不过,学WPF一点都不亏,xaml,数据绑定,和AE,PR类似的时间线系统,和绝高的开发效率,这些知识可以很快的转移到其他相关领域。

结语

       说了这么多,没用图片,也没拷贝大段代码,就是简单的聊聊。只是,在如今WEB化和移动化大行其道的情况下,windows桌面程序开发的价值又有几何?这难以估量,不过作为程序员,学习它,一点都不亏。

       本文的任何见解, 欢迎大家讨论。

时间: 2024-11-02 20:32:59

关于开发WPF的一些感想的相关文章

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十二)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十二) 雷.混.冰.毒.火.风 - 幻化中的魔法魅力 本节,我将为大家演示如何为游戏中的魔法增加华丽的附加属性. 第一步,定义规则: 1)定义魔法附加属性分类:在本教程示例游戏中,我将魔法附加属性定义为6类:雷.混.冰.毒.火.风,为什么要以这样无规律的方式去命名?因为是教程,我们需要学习的是如何实现对应效果,此6类属性算是目前网游中最流行的六大魔法属性,如果大家都掌握了,无论是中国式5行还是诸如其他的风格设

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)制作精美的可任意拖放对象的物品栏及装备栏 在通常的网络游戏中,物品.装备.技能.快捷按钮等窗口中的图标都是可以相互拖放的,不同的栏目有着不同的限制,例如技能图标不能拖放到物品栏及装备栏中,且不是所有的魔法技能都可以拖放(如被动技能等):而非装备类的所有物品则无法拖放到角色的装备栏中.那么本节我将向大家讲解如何在本教程示例游戏中添加物品栏及装备栏,并实现它们之间双向物品交换的两种模式:拖放模式和双击模

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)制作主角属性面板及加点器 游戏中会使用大量的菜单面板,而这些面板往往都带有选项卡.如果用Silverlight工具中的TabControl,则需要通过复杂的xaml重写模板来实现自定义样式,这一点时常让开发者头疼,毕竟界面的东西应该属于美工的范畴,这也是我所发现在目前Silverlight中唯一一处只能通过xaml而无法用代码实现的地方.当然,如果您对此特别感兴趣,同样可以到http://www.c

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)制作游戏主菜单面板及鼠标左右键快捷技能栏 每款MMORPG都有一个主菜单,通常置于窗口的底部.游戏中主角大部分的设置操作都从这里开启.如人物属性.物品(包裹).技能.任务.队伍.地图.家族.门派.商城.系统设置等等:当然,还包括快捷自定义菜单栏,以及类似<暗黑破坏神>中经典式的左右键快捷技能栏.这些内容在不同的游戏中往往会根据自身的特性稍做调整,但整体上大同小异.本节,我将同样以<剑侠世界&

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)制作精美的Mini地图② 前面章节中讲解的包括对象头像面板.Mini雷达地图等窗体都是位置固定的,在处理起来方式多样且简单:而RPG.SLG.休闲养成等类型的游戏中往往会大量使用到悬浮且可自由拖动的窗体,比如包裹面板.武器装备面板.个人属性面板.技能面板.系统设置面板等等,这就要求我们必须为游戏量身定做一个通用且易用的ChildWindow控件.那么本节我将为大家讲解如何制作一个包含可拖动头部.关闭

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十一)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十一)制作精美的Mini地图① 用什么来承受未来几个月日思夜想的折磨?除了学习还是学习. 感慨了一翻,嘿嘿.本节我将为大家讲解如何为Silverlight游戏制作一个精美的Mini地图.Mini地图又分两种,一种是通常处于游戏窗口右上角的Mini雷达(导航)地图:另一种是全景Mini寻路地图.本节我先向大家讲解如何制作导航Mini雷达地图.此类地图在游戏中主要起到导航作用,即引导主角前行的方向,并且呈现出

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十)斜度α地图的构造及算法 在当前的网络游戏中,地图基本都是采取一定斜度的拼装地图,这其中存在两种斜度地图的构造方式: 第一种我称之为伪斜度地图:该类型地图表现层图片为斜度的,但地图基底障碍物等的构造则实为正方形,如下图: 其实最典型的例子就是上一节所演示的内容了,地图是斜的,但是我们却用垂直的障碍物对其进行基底布局,这就是典型的伪斜度地图了. 这样的地图优点在于可以使用简单直接的地图构造算法(上一节中有详细的

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(九)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(九) 2D游戏角色在地图上的移动 本节将运用前两节的知识到实际的2D游戏人物在地图上移动中,同时也算是对前面八节的内容进行一次综合运用吧. 那么先从最底层的地图讲起.首先我将一张地图添加进游戏窗口中,这里我同样使用Image控件: Image Map = new Image(); private void InitMap() { Map.Width = 800; Map.Height = 600; Map.So

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(八)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(八) 完美实现A*寻径动态动画 本节将紧接着上一节,在它的基础上实现鼠标点击动态创建完美的A*寻路动画.(模拟游戏中人物的真实移动,这次可是有障碍物的,可以说基本上完成了人物移动引擎的一半了呢) 首先,在上一节的代码前部分加入一个叫做player的圆形作为我们将要控制的对象(模拟游戏中的主角,下文均称之为"主角"): Ellipse player = new Ellipse(); //用一个圆来模拟目