目录
multibinding+imultivalueconverter
static resources/dynamic resources
datatemplate/controltemplate/itemspaneltemplate
子元素水平(horizontal)/垂直(vertical)对齐方式失效问题
visualtreehelper/logicaltreehelper
focusmanager的focusedelement/isfocusscope
iskeyboardfocused/iskeyboardfocuswithin
特点
- wpf的特点是数据驱动ui,界面上所有的变化都是通过数据模型来推动的。
- 以数据为核心,wpf提供数据绑定的机制,当数据发生变化时,wpf自动发出通知并更新ui。
mvvm
特点
mvvm的特点就是降低了xaml文件和cs文件的耦合度。
是什么
理解一
- view就是用xaml实现的界面,负责与用户交互,接受用户输入,把数据展现给用户。
- viewmodel就是c#类,负责组装需要绑定的数据和命令,聚合model对象,通过view类的datacontext 属性绑定到view上面。
- model就是系统中的对象。
- view对应一个viewmodel,viewmodel可以聚合多个model,viewmodel可以对应多view。
理解二
- model就是现实世界中的对象。
- view就是ui。
- viewmodel就是对view的抽象。
优势
mvvm的优势就是把ui层和业务层进行分离,view就是负责如何显示数据和发送命令,viewmodel就是如何提供数据和执行命令。
viewmodel和view的通信
理解
- 传递数据通过数据属性,需要实现inotifypropertychanged接口。
- 传递操作通过命令属性,需要实现icommand接口。
示意图
raisecanexecutechanged
raisecanexecutechanged用于重新判断command是否能够执行。
raisepropertychanged
- raisepropertychanged用于当属性发生变化通过set访问器更新字段的值然后通知界面的元素做 出相应的更新。
- callermembername特性用于自动获取属性的名称。
observablecollection
- observablecollection实现了inotifycollectionchanged接口,使得在集合发生变化的时候能够通知绑定到该集合的ui元素进行更新。
- 在observablecollection集合中动态添加,删除或者重新排序,ui界面会及时更新以显示相应的更改。
双向绑定的情景
- observablecollection中的对象发生改变,需要提供通知机制。
- 对象属性发生改变,需要提供通知机制。
- 集合的地址指向发生改变,也需要提供通知机制。
xaml
xaml是什么
xaml语言是一种声明性语言,每见到一个标签就声明一个实例。
- 定义:构建应用程序用户界面而创建的一种新的”可扩展应用程序标记语言”,提供一种便于扩展和定 位的语法来定义和程序业务逻辑分离的用户界面。
- 特点:
- 定义应用程序的界面元素
- 显式声明wpf资源(样式,模板,动画等)
- 集中关注界面设计
- 命名空间:xaml与.net程序语言一样,通过命名空间有效组织xaml内部的相关元素类。
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 默认命名空间
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xaml语法和编译相关的clr命名空间。
- 一个xmal文件至少要有两个命名空间。1.带x前缀。2.默认命名空间。
- 区分:应用时,不带前缀,来自于默认命名空间。否则来自于带前缀的命名空间。
xaml应用场景
- app.xaml:设置应用程序起始文件,系统及资源
- app.xaml.cs: app.xaml文件的后台类文件。
- startupuri 指定起始文件
- <application.resources>定义整个wpf应用程序的相关资源
- mainwindow.xaml:wpf应用程序界面与xaml设计文件。
- mainwindow.xmal.cs:xaml窗口文件的后台代码文件。
样式
basedon
指定当前样式的父样式,可以用来进行样式继承。
绑定
binding
binding是用来给ui界面绑定viewmode的数据。
multibinding
应用场景
- multibinding可以进行联合绑定。
- 当在wpf中进行数据绑定时,比如textblock的text属性,希望绑定两个或者两个以上的数据源,最 后得到的text是由这几个数据源按照自己的设计组合而成,就要用到multibinding。
multibinding+stringformat
multibinding+imultivalueconverter
updatesourcetrigger
- default:对于控件属性的双向绑定,会在失去焦点或者按回车键时更新数据源,对于非控件属性,比如 依赖属性,会立即更新数据源。
- explicit表示手动更新,需要明确指定更新时机,来更新数据源。
- lostfocus表示界面上绑定的属性值发生更改并且失去焦点时更新数据源。
- propertychanged表示界面上绑定的属性值发生改变时就立即更新数据源,对于控件属性的双向绑定,默认绑定模式就是twoway。
bindingmode
- oneway是指源变更新目标。
-
- twoway是指源变更新目标并且目标变更新源,对于控件属性的双向绑定,默认绑定模式就是twoway, 但是只有在失去焦点或者按回车键时才更新数据源,如果想立即更新数据源的话,那么需要指定 updatesourcetrigger=propertychanged。
- onetime是指只根据源设置目标,以后都不变。
- onewaytosoure是指目标变更新源。
- default是指绑定模式由系统自动确定,通常情况下,对于大多数属性,如果数据源属性是可读可写的, 那么默认的绑定模式为twoway,如果数据源属性是只读的,那么默认的绑定模式为oneway。
relativesource
- relativesource常用的有五种查找模式。
- self表示查找自身。
- findancestor表示查找父级,ancestorlevel表示父级级别,ancestortype表示父级类型。
- templateparent表示查找控件模板。
- source表示指定数据源。
- path表示指定属性。
static resources/dynamic resources
- static resources是静态资源,编译时就确定。
- dynamic resources是动态资源,在运行时确定。可以动态修改,比如主题切换,多语言支持。
触发器
应用场景
触发器的主要作用就是根据trigger的不同条件来自动更改外观的属性,或者执行一些动画操作。
trigger
当鼠标滑过时字体变成红色。
multitrigger
当checkbox勾选并且鼠标滑过时字体变绿色。
eventtrigger
鼠标划入长度变长,鼠标移除长度变短。
controltemplate中使用trigger
datatrigger
- 在listbox中,当选中的item为陕西省时,将item项的文字颜色设置为红色。
- 当选中的item为陕西省西安市时,将item项的背景色设置为绿色。
multidatatrigger
- hierarchicaldatatemplate:分层数据模板。
- 在treeview中,当treeviewitem没有展开并且treeviewitem是一个目录时,显示目录图片。否则当 该treeviewitem展开时,显示目录打开的图片。
- 当所有的radiobutton都没有选中时,按钮不可用,否则按钮可用。
区别
- trigger和multitrigger都是触发器,只不过multitrigger是满足多个条件时才触发。
- datatrigger和multidatatrigger也是触发器,multidatatrigger也是满足多个条件时才触发。
- trigger和multitigger仅适用于同一控件中的属性,可以简单理解为面向控件的property。
- datatrigger和multidatatrigger的条件是基于绑定数据的属性值而不是uielement的属性值,可以简单 理解为面向数据的binding。
- multitrigger和multidatatrigger的条件都是在conditions中编写的。
控件
page/usercontrol/window
- page通常用于承载网页。
- usercontrol是用户控件,如果控件需要被重复使用时就可以使用用户控件,比如在很多窗口中,用同 一个自定义的日期控件。
- window是主窗口,通常一个windows程序中只有一个主窗口。
datatemplate/controltemplate/itemspaneltemplate
- datatemplate是指数据模板。
- controltemplate是指控件模板。
- itemspaneltemplate是指项布局模板。
常用控件
- showintaskbar 窗口是否具有任务栏按钮
- 内容控件:只能有一个子元素作为它的内容。
- wpf允许控件没有name属性值,当后台代码需要引用对象的时候需要设置name。
- radiobutton:同一组单选按钮,它们是互斥的关系。
- border:边框,围绕在其它元素周围。
- 和布局面板一起使用,作为布局面板的边框。
- 作为任意控件的边框显示。
- border只能有一个元素作为它的子元素。border作为布局面板边框,布局面板内显示多个子元素。
- textblock和lable区别:加载labe比textblock耗费更多时间,label其实就是一个个性化的textblock, textblock比较底层只能显示文本。
-
run:是一个内联元素,用于在textblock或者flowdocument中显示一段文本,通常用于控制一段文本的样式,比如对一部分文本应用不同的样式,辅助textblock或者flowdocument完成文本的格式化和排版。
- stackpanel:堆栈面板,子元素超出的部分会被隐藏。
- wrappanel:流面板,子元素超出的部分会自动换行。
- dockpanel:停靠面板。特点:先添加的子元素,优先占用边角(优先占有权),所有子元素区域不会重叠。
- canvas:画布面板(坐标面板),定义区域子元素的显示位置,指定相对于面板的坐标来定 位子元素显示 的位置。
- 附加属性:canvas.left canvas.right canvas.top canvas.bottom
- 坐标:(left,top) (left bottom) (right,top) (right,bottom)
- 不能子元素指定两个以上的附加属性,如果制定了,忽略后者。
- 当窗口大小变化,canvas的尺寸就随之变动,子元素的位置也变化,但是子元素的坐标相对于 canvas的位置没有变化。
- cliptobounds 默认值false,溢出不裁剪。true,溢出裁剪。
- 应用:精确定位,画图,最简单的布局。
- grid:网格面板,类似于winform中tablelayoutpanel,行和列方式布局页面或页面中某一块区域。每 个单元格可以包含一个元素或多个元素。
- expander:折叠控件。
- fram:支持导航,可以将一个页面导航到另一个页面,可能承载page页。
- page页:封装一页的内容。
- listview:数据列表控件。用于显示数据项的列表。以列(gridviewcolumn)形式显示数据项的视图模式。
- datagrid:网格控件,可以自定义网格显示数据的控件。
-
datagrid属性:
-
rowheadertemplate:行标题模板
-
canuseraddrows:是否添加新行
-
isreadonly:是否可以编辑其中的值
-
verticalscrollbarvisibility/horizontalscrollbarvisibility 垂直/水平滚动条的显示
-
currentitem:当前单元格的行绑定的数据项
-
canuserdeleterows:是否可以删除行
-
rowstyle/cellstyle:行/单元格 样式
-
headervisibility:行和列头的可见性
-
alternatingrowsbackground:交替行上使用的背景画笔
-
gridlinesvisibility:显示哪些网格线
-
verticalgridlinesbrush/horizontalgridlinesbrush 垂直/水平网格线画笔
-
rowheaderwidth行标题宽度,columnheaderheight列标题高度,rowheight行高
-
autogeneratecolumns:是否自动创建列
-
selectionunit/selectionmode:选择单元(单元格,行或者两者) /单选或多选
-
-
datagrid中的列:
-
datagridtextcolum:文本显示内容,数据类型为string
-
datagridcheckboxcolumn:复选框的形式显示内容,数据类型为boolean
-
datagridcomboboxcolumn:下拉列表的形式显示内容,数据类型为enum
-
datagridhyperlinkcolumn:超链接的形式显示内容,数据类型为uri
-
datagridtemplatecolumn:模板列,自定义显示样式
-
-
-
uniformgrid:界面均等份布局。
- menu:windows菜单控件。
- menu属性:
- ismainmenu:是否接受主菜单激活通知,alt或f10激活。
- menuitem:menu控件中的可选项,带标题的条目控件。
- contextmenu:特定于某个元素之上的功能菜单。右键菜单,上下文菜单。
- contextmenu属性:horizontaloffset,verticaloffset 右键菜单控件相对于点击位置的水平,垂直距离点。
- treeview:树形控件,以节点的形式显示数据。节点对应树形控件的项,项可以展开与折叠。
- selecteditem:选择的项
- selectedvalue:选择项的值
- itemsource:数据源
- toolbar:工具栏控件。为一组命令或控件提供的容器。
- menu属性:
- toolbar属性
- orientation:指示内部项的布局方向,只读属性。
- toolbartray:布局toolbar的容器,呈放多个toolbar。
- statusbar:状态栏控件。
- mediaelement:媒体播放控件,音频或视频文件。
- richtextbox:对流文档(flowdocument)对象进行操作的丰富编辑控件。
常用的九种布局
gird
- grid是网格面板,最常用的布局容器,就是整体的页面布局。
- 注意:
- 固定长度:值为一个确定的数字。
- 自动长度:值为auto,就是取实际控件所需要的最小值。
- 比例长度:*表示占用剩余的全部长度。一个长度为2*,一个长度为*,2*表示占剩余全部长度的2/3,*表示占剩余全部长度的1/3。
stackpanel
stackpanel是堆栈面板,按照行或者列进行顺序排列,不会换行。
wrappanel
wrappanel是流面板,在有限的容器范围内,可以自动换行或者换列。
dockpanel
dockpanel是停靠面板,让元素停靠在整个面板的某一条边上,然后拉伸元素填满全部的宽度或者高度。
uniformgrid
uniformgrid是grid的简化版,可以进行界面均等份布局,每个单元格大小相同。
canvas
理解
canvas类似于坐标系的面板,所有的元素通过设置坐标来决定其在坐标系中的位置。
示意图
scrollviewer
scrollviewer是带有滚动条的面板,在scrollviewer中只能有一个子控件,如果要显示多个子控件,需要通过panel控件进行包裹。
viewbox
- viewbox的作用是拉伸或者延展位于其中的组件,用来填满可用的控件。viewbox中只能有一个子控件, 如果要显示多个子控件,需要通过panel控件进行包裹。
- 常用属性:
- stretch:获取或者设置拉伸模式,用来决定该组件中的内容应该用怎样的形式填充该组件的已有空间,默认值为uniform。
-
border
border是一个装饰控件,用来绘制边框和背景。border中只能有一个子控件,如果要显示多个子控件,需要通过panel控件进行包裹。
子元素水平(horizontal)/垂直(vertical)对齐方式失效问题
canvas/wrappanel
canvas/wrappanel子元素horizontalalignment,verticalalignment属性无效。
gird
grid子元素horizontalalignment,verticalalignment属性有效。
stackpanel
- stackpanel当orientation为horizontal时,子元素horizontalalignment属性无效,verticalalignment属性有效。
- 当orientation为vertical时,子元素horizontalalignment属性有效,verticalalignment属性无效。
dockpanel
- dockpanel子元素设置为dockpanel.dock=left/right,子元素的horizontalalignment属性无效,verticalalignment属性有效。
- 子元素设置为dockpanel.dock=top/bottom,子元素的horizontalalignment属性有效,verticalalignment属性无效。
- 子元素lastchildfill设置为true时,dockpanel.dock无效,horizontalalignment,verticalalignment属性有效。
visualtreehelper/logicaltreehelper
区别
- visualtreehelper用于遍历可视化树,可视化树表示在ui上呈现的元素及其关系,包括控件, 容器,布局等。
- logicaltreehelper用于遍历逻辑树,逻辑树表示了元素之间的逻辑关系,如控件的父子关系,嵌套关系 等。
获取控件的子元素
获取控件指定类型的子元素
visualtreehelper
逻辑树遍历和判断类型
逻辑树扩展和判断类型
visualtreehelper类和判断类型
logicaltreehelper
updatelayout
- updatelayout是一个用于强制ui元素更新布局的方法。
- 比如,在代码中修改了某个ui元素的属性或者数据源,然后希望立即看到这些变化反映在界面上,就可以调用updatelayout方法来触发布局更新。
- 频繁调用updatelayout可能会影响应用程序性能,因此建议只在确实需要立即刷新布局时才使用该方法,避免滥用。
焦点
键盘焦点/逻辑焦点
- 键盘焦点指接收键盘输入的元素。
- 逻辑焦点指焦点范围中具有焦点的元素。
focusmanager的focusedelement/isfocusscope
- focusedelement可以直接指定具有键盘焦点的元素,只有focusscope中的元素才能成为焦点元素。
- isfocusscope用于标识元素是否作为焦点范围,默认焦点范围是window,多个focusscope嵌套的情况下,焦点会在各个焦点范围之间传递。
istabstop/tabindex
- istabstop决定了元素是否可以通过tab键来获取焦点,默认是true。
- tabindex决定了元素在tab键焦点顺序中的位置,具有较小tabindex值的元素将先获得焦点,而具有 较大tabindex值的元素将后获得焦点。如果多个元素的tabindex值相同,则它们按照其在xaml中的 出现顺序来确定焦点顺序。
iskeyboardfocused/iskeyboardfocuswithin
- iskeyboardfocused判断元素是否具有键盘焦点。
- iskeyboardfocuswithin判断元素或其子元素是否具有键盘焦点。
清除焦点/获取焦点
获取单元格焦点
模板
控件模板
是什么
控件模板就是控件的外衣,通过修改控件模板来定义控件的外观。
示意图
数据模板
是什么
数据模板就是数据的外衣,通常用于在内容控件或者列表控件中显示数据。
示意图
面板模板
是什么
面板模板就是面板的外衣,通常用于自定义控件的布局。
示意图
区别
- 控件模板针对的是控件的本身,决定控件外观的是controltemplate,可以改变控件本身的样子。
- 数据模板针对的是控件的数据,决定数据外观的是datatemplate,可以改变控件绑定数据的表现形式。
- 面板模板应用的是itemspaneltemplate,针对的是控件的布局,可以改变控件的布局方式。
dispatcher
是什么
dispatcher属性可以将其它线程投放到ui线程,让ui线程去执行。
总结
- 在wpf中,所有的对象都派生自dispatcherobject对象,dispatcherobject对象通过dispatcher属性用 来获取创建对象线程对应的dispatcher属性。
- dispatcherobject对象只能被创建它的线程所访问,其它线程修改dispatcherobject对象时需要取得对 应的dispatcher属性,调用invoke方法或者begininvoke方法来投入任务。
- invoke方法和begininvoke方法从winform时代就是一直存在的,只是在wpf中使用了dispatcher属 性来封装这些线程级的操作。
依赖属性
是什么
- 依赖属性是自己没有值,需要通过绑定从其它数据源获取值的属性。
- 只有依赖属性才能进行绑定。
为什么要有依赖属性
- 在传统的oop中,多级继承的时候,父类的字段都被继承,子类占用内存空间不可避免的膨胀。
- 而且在多级继承中,大多数字段并没有被修改,为了减少对象的体积,从而需要依赖属性。
- 在winform中,每个ui控件的属性都被赋予了初始值,每个相同的控件在内存中都会保存一份初始值。
- wpf的依赖属性在内部使用哈希表的存储机制,对多个相同控件的相同属性值只保存一份。
如何添加依赖属性
依赖属性的优势
- 依赖属性主要解决了传统oop多级继承中,大多数字段值不改变的情况,减少了内存占比。
- 依赖属性是通过调用dependencyobject对象的getvalue方法和setvalue方法来对依赖属性进行读写 的。
- dependencyobject对象使用了哈希表的存储机制,对应的key就是属性的hashcode值,而值就是注 册的dependencyproperty属性。
- 依赖属性是以数据为中心,当数据源发生改变时,关联的ui数据也会改变。
- 依赖属性的值可以通过binding依赖于其它对象上,这就使得数据源一变动,依赖于此数据源的依赖属 性全部进行更新。
依赖属性继承
通过addower方法可以继承其它控件的依赖属性。
只读依赖属性
只读依赖属性是用
dependencyproperty.registerreadonly方法来替换dependencyproperty.register方法。
附加属性
附加属性最常见的场景就是布局容器中dockpanel和grid的附加属性。
附加属性是用registerattached方法替代了register方法。
依赖属性验证
- validatevaluecallback函数可以接受或拒绝新值,验证值是否合法。
- coercevaluecallback函数可以将新值强制修改为可被接受的值。
- propertychangedcallback函数可以触发依赖属性值的更改,当值发生改变时,可以做一些操作。
依赖属性的监听
- 第一种方法是使用propertychangedcallback函数进行监听。
- 第二种方法是获取dependencypropertydescriptor对象,并调用addvaluechange方法为其绑定一个回 调函数进行监听。
依赖对象
- 对象创建时不包含字段所占用的空间,在使用这个字段时通过其它对象的数据来分配空间,这种对象 就是依赖对象。
- 这种分配空间的能力就是依靠依赖属性来实现的。
事件
直接路由事件
直接路由事件,它来自一个元素,并且不传递给其它的元素,比如mouseenter事件就是当鼠标移动到一个元素上面时触发的事件,它就是一个直接路由事件。
冒泡事件
冒泡事件是指从事件源传递到顶部元素,也就是在包含层次中向上传递的事件,比如mousedown事件就是一个冒泡路由事件。它首先被单击的元素触发,然后就是该元素的父元素触发,以此类推,最后到达wpf元素树的顶部为止。
隧道事件
- 隧道(preview)事件是指从顶部元素传递到事件源,也就是在包含层次中向下传递的事件,比 如previewkeydown就是一个隧道路由事件。在一个窗口上按下某个键,首先是窗口,然后是窗口下面的元素,最后到达按下键盘上面的按键时具有焦点的元素。
- 隧道事件总是在冒泡事件之前被触发。
- 如果将隧道路由事件标记为已处理的,那么冒泡路由事件就不会触发,这是因为这两个事件共享同一 个routedeventargs类的实例。
- 隧道路由事件可以用来执行一些预处理操作,比如根据键盘上特定的键执行特定的操作,或过滤掉特定的鼠标操作,都可以在隧道路由事件处理程序中进行处理。
阻止事件传播
- 在设置e.handled=true的时候,不管是冒泡事件还是隧道事件,它还是会继续传播的,只是对应的事 件不会在被处理了。
- 如果想继续响应相应的事件,可以通过addhandler方法进行注册。
- 每当触发事件处理程序之前,都会检查routedeventargs的handled属性和_handleeventstoo字段。当handle=true时,其实路由事件还是一样会传递,传递到对应事件的处理程序中时,只是因为 handle为true和_handleeventstoo为false,从而导致事件处理程序没有运行。
- 如果通过addhandler(routedevent,delegate,boolean)注册事件处理程序,把_handleeventtoo显示设置为true,所以即使handle为true,该元素的事件处理程序照样会被执行,因为此时的if条件一样会 为true。
自定义路由事件
路由事件由只读的静态字段表示,在一个静态构造函数通过
eventmanager.registerroutedevent函数注册,然后定义一个事件进行包装。
共享路由事件
- 可以在类之间共享路由事件的定义,实现路由事件的继承。
- 比如uielement类和contentelement类都使用了mouseup事件,但是mouseup事件是由mouse类定 义的。
- 所以uielement类和contentelement类只是通过routeevent.addowner方法重用了mouseup事件。
引发和处理路由事件
路由事件通过raiseevent方法触发,所有的元素都从uielement类继承了该方法。
附加事件
- 比如stackpanel面板中包含了一堆按钮,现在希望在一个事件处理程序中处理所有这些按钮的单击事 件。
- 可以将每个按钮的click事件关联到同一个事件处理程序中,但是click事件支持事件冒泡,所以可以 通过更高层次的元素来关联click事件处理所有按钮的单击事件。
生命周期
- sourceinitialized事件在取得窗口句柄属性时触发。
- activated事件在窗口获取焦点时触发。
- loaded事件在窗口加载时触发。
- contentrendered事件在窗口第一次呈现结束后立即触发。
- activated事件在窗口获取焦点时触发。
- deactivate事件在窗口失去焦点时触发。
- closing事件在窗口关闭过程中触发。
- unloaded事件在窗口卸载时触发。
- closed事件在窗口关闭完成后触发。
devexpress
mvvm
pocoviewmodel
- pocoviewmodel特性:不用在view层中指定datacontext,就可以指定对应的viewmodel。
- 属性标记为virtual进行数据双向绑定。
- 方法在view层绑定的时候用command结尾,而viewmodel层不需要command结尾来进行命令绑定。
dependson
- dependson表示该属性依赖于其它属性,当其它属性的值发生变化时,该属性的值会重新计算。
- 下面实例中,当fontsize属性的值发生变化时,fontcolor属性也会相应的更新。
依赖注入
- 依赖注入通过servicecontainer.default.registerservice()进行注入。
- 依赖注入获取通过servicecontainer.default.getrequiredservice获取。
转换器
- booleannegationconverter
- booleantoobjectconverter
- booleantovisibility
- objecttobooleanconvert
- stringtobooleanconvert
- stringtovisibiltyconverter
布局
x:name
x:name:实例类型不是派生在frameworkelement上时,用x:name来设置别名。
wpf中viewmodel层弹出新窗口
- viewmodel定义eventhandler事件,view层用eventhandler事件打开委托,viewmodel中通过按钮的 command触发eventhandler。
- dictonary注册窗体的type和key,反射创建窗体对象打开窗体。
- dictonary注册窗体的type和委托(action,func),执行委托打开窗体,委托包装的方法,在窗体内部执 行打开窗体的逻辑。
wpf和winform区别
生态方面的区别
- 现在西安很多公司,尤其是传统行业大部分用的还是winform。
- 因为很多公司的用户对界面的美观性要求不高,你只要给我把功能实现了就可以了,所以用winfrom 就非常合适。winfrom就是拖拉拽,能非常快速的开发出一个功能不复杂的程序,并且用起来还比较 流畅。对于大多数公司来说成本低,不需要那么多研发,而且公司也养不了那么研发,一般最多2到 3个人用winfrom开发程序,然后维护,甚至有时候就是一个人。
- 如果用户对界面的美观性要求非常高,并且任何按钮,组件都需要按照要求定制化开发,里面还包含 了各种动画效果以及各种3d显示效果,这个时候就必须考虑使用wpf。如果用了wpf但是又没有那 么多人去做,基本上做的人就相当于全栈开发。
- 首先wpf的学习成本比winfrom高的多,wpf不是拖拉拽就能完成开发,定制化高的软件都需要程 序员去写xmal来实现,xmal包含了各种样式和各种触发器,以及各种各样五花八门非常灵活的数据 绑定。
- 而且用wpf就得考虑视图和数据分离,前后端分离,这就相当于程序员既要写xaml还要写业务,甚 至还要写接口,工作量会非常大。当然wpf也可以像winfrom那样不使用mvvm,不进行视图和数 据的分离,所有的事件和业务都写到xaml对应的cs文件中,然后写个dbhelper啥的直接访问数据库, 这样做如果公司研发团队就几个开发为了提高效率没啥问题。如果团队比较大,人比较多,像某些公 司研发加起来50多个人,就得分工明确,让专门写xaml的去写xaml,专门写业务的去写viewmodel, 专门写接口的去写grpc接口,这么做最大的好处就是可以降低系统的耦合度,后面维护起来也方便, 专人专职去做自己擅长的事情。
技术方面的区别
- winform本身的开发模式,存在天然的缺陷。给一个winform控件进行数据绑定操作,然后按照事件 驱动的模式,根据控件名来获取原始绑定的数据,界面和数据是完全耦合。
- wpf是mvvm模式,数据和视图分离,不再为每个元素添加固定的名称,通过数据驱动进行业务 代码编写。
- winform的设计器和cs文件的代码耦合度是非常高的,不能独立进行页面设计。
- wpf是数据驱动ui,数据是核心,处于主动地位。ui从属于数据,并且表达数据,处于被动地位。
- winform中,每个ui控件的属性都被赋予了初始值,每个相同的控件在内存中都会保存一份初始值。
- wpf依靠依赖属性解决了在传统oop多级继承中,大多数字段值不改变的情况,减少了内存占比。
- wpf底层使用direct x接口,加强了3d图形和声音效果。
- winform底层使用gdi+接口,主要是负责绘图程序之间的信息交换和处理,以及所有windows程序的 图形输出。
如何在wpf应用程序中全局捕获异常
application.dispatcherunhandledexception
发表评论