C# WPF学习总结
WPF的特点,MVVM,XAML,绑定,触发器,控件,模板,Dispatcher,依赖属性,依赖对象,事件,DevExpress的应用,WPF中ViewModel层弹出新窗口,WPF和WinForm区别,如何在WPF应用程序中全局捕获异常。
目录
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
更多推荐
所有评论(0)