目录

特点

MVVM

特点

是什么

理解一

理解二

优势

ViewModel和View的通信

理解

示意图

RaiseCanExecuteChanged

RaisePropertyChanged

双向绑定的情景

XAML

XAML是什么

XAML应用场景

样式

BasedOn

绑定

Binding

MultiBinding

应用场景

MultiBinding+StringFormat

 MultiBinding+IMultiValueConverter

UpdateSourceTrigger

BindingMode

RelativeSource

Static Resources/Dynamic Resources

触发器

应用场景

Trigger

MultiTrigger

EventTrigger

 ControlTemplate中使用Trigger

DataTrigger

MultiDataTrigger

区别

控件

Page/UserControl/Window

DataTemplate/ControlTemplate/ItemsPanelTemplate

常用控件

常用的九种布局

Gird

StackPanel

WrapPanel

DockPanel

UniformGrid

Canvas

理解

示意图

ScrollViewer

ViewBox

​编辑

Border

子元素水平(Horizontal)/垂直(Vertical)对齐方式失效问题

Canvas/WrapPanel

Gird

StackPanel

DockPanel

VisualTreeHelper/LogicalTreeHelper

区别

获取控件的子元素

获取控件指定类型的子元素

VisualTreeHelper

逻辑树遍历和判断类型

逻辑树扩展和判断类型

VisualTreeHelper类和判断类型

LogicalTreeHelper

UpdateLayout

焦点

键盘焦点/逻辑焦点

FocusManager的FocusedElement/IsFocusScope

IsTabStop/TabIndex

IsKeyboardFocused/IsKeyboardFocusWithin

清除焦点/获取焦点

获取单元格焦点

模板

控件模板

是什么

示意图

数据模板

是什么

示意图

面板模板

是什么

示意图

区别

Dispatcher

是什么

总结

依赖属性

是什么

为什么要有依赖属性

如何添加依赖属性

依赖属性的优势

依赖属性继承

只读依赖属性

附加属性

依赖属性验证

依赖属性的监听

依赖对象

事件

直接路由事件

冒泡事件

隧道事件

阻止事件传播

自定义路由事件

共享路由事件

引发和处理路由事件

附加事件

生命周期

DevExpress

MVVM

POCOViewModel

DependsOn

依赖注入

转换器

布局

X:Name

WPF中ViewModel层弹出新窗口

WPF和WinForm区别

生态方面的区别

技术方面的区别

如何在WPF应用程序中全局捕获异常

特点

  1. WPF的特点是数据驱动UI,界面上所有的变化都是通过数据模型来推动的。
  2. 以数据为核心,WPF提供数据绑定的机制,当数据发生变化时,WPF自动发出通知并更新UI。

MVVM

特点

MVVM的特点就是降低了xaml文件和cs文件的耦合度。

是什么

理解一

  1. View就是用xaml实现的界面,负责与用户交互,接受用户输入,把数据展现给用户。
  2. ViewModel就是C#类,负责组装需要绑定的数据和命令,聚合Model对象,通过View类的DataContext 属性绑定到View上面。
  3. Model就是系统中的对象。
  4. View对应一个ViewModel,ViewModel可以聚合多个Model,ViewModel可以对应多View。

理解二

  1. Model就是现实世界中的对象。
  2. View就是UI。
  3. ViewModel就是对View的抽象。

优势

MVVM的优势就是把UI层和业务层进行分离,View就是负责如何显示数据和发送命令,ViewModel就是如何提供数据和执行命令。

ViewModel和View的通信

理解

  1. 传递数据通过数据属性,需要实现INotifyPropertyChanged接口。
  2. 传递操作通过命令属性,需要实现ICommand接口。

示意图

RaiseCanExecuteChanged

RaiseCanExecuteChanged用于重新判断Command是否能够执行。

RaisePropertyChanged

  1. RaisePropertyChanged用于当属性发生变化通过set访问器更新字段的值然后通知界面的元素做 出相应的更新。
  2. CallerMemberName特性用于自动获取属性的名称。

ObservableCollection

  1. ObservableCollection实现了INotifyCollectionChanged接口,使得在集合发生变化的时候能够通知绑定到该集合的UI元素进行更新。
  2. 在ObservableCollection集合中动态添加,删除或者重新排序,UI界面会及时更新以显示相应的更改。

双向绑定的情景

  1. ObservableCollection中的对象发生改变,需要提供通知机制。
  2. 对象属性发生改变,需要提供通知机制。
  3. 集合的地址指向发生改变,也需要提供通知机制。

XAML

XAML是什么

XAML语言是一种声明性语言,每见到一个标签就声明一个实例。

  1. 定义:构建应用程序用户界面而创建的一种新的”可扩展应用程序标记语言”,提供一种便于扩展和定 位的语法来定义和程序业务逻辑分离的用户界面。
  2. 特点:
    1. 定义应用程序的界面元素
    2. 显式声明WPF资源(样式,模板,动画等)
    3. 集中关注界面设计
  3. 命名空间:xaml与.net程序语言一样,通过命名空间有效组织xaml内部的相关元素类。
  4. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 默认命名空间
  5. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xaml语法和编译相关的clr命名空间。
  6. 一个xmal文件至少要有两个命名空间。1.带x前缀。2.默认命名空间。
  7. 区分:应用时,不带前缀,来自于默认命名空间。否则来自于带前缀的命名空间。

XAML应用场景

  1. App.xaml:设置应用程序起始文件,系统及资源
  2. App.xaml.cs: App.xaml文件的后台类文件。
  3. StartupUri 指定起始文件
  4. <Application.Resources>定义整个WPF应用程序的相关资源
  5. MainWindow.xaml:WPF应用程序界面与xaml设计文件。
  6. MainWindow.xmal.cs:xaml窗口文件的后台代码文件。

样式

BasedOn

指定当前样式的父样式,可以用来进行样式继承。

绑定

Binding

Binding是用来给UI界面绑定ViewMode的数据。

MultiBinding

应用场景

  1. MultiBinding可以进行联合绑定。
  2. 当在WPF中进行数据绑定时,比如TextBlock的Text属性,希望绑定两个或者两个以上的数据源,最 后得到的Text是由这几个数据源按照自己的设计组合而成,就要用到MultiBinding。

MultiBinding+StringFormat

 MultiBinding+IMultiValueConverter

 

UpdateSourceTrigger

  1. Default:对于控件属性的双向绑定,会在失去焦点或者按回车键时更新数据源,对于非控件属性,比如 依赖属性,会立即更新数据源。
  2. Explicit表示手动更新,需要明确指定更新时机,来更新数据源。
  3. LostFocus表示界面上绑定的属性值发生更改并且失去焦点时更新数据源。
  4. PropertyChanged表示界面上绑定的属性值发生改变时就立即更新数据源,对于控件属性的双向绑定,默认绑定模式就是TwoWay。

BindingMode

  1. OneWay是指源变更新目标。
  2. TwoWay是指源变更新目标并且目标变更新源,对于控件属性的双向绑定,默认绑定模式就是TwoWay, 但是只有在失去焦点或者按回车键时才更新数据源,如果想立即更新数据源的话,那么需要指定 UpdateSourceTrigger=PropertyChanged。
  3. OneTime是指只根据源设置目标,以后都不变。
  4. OneWayToSoure是指目标变更新源。
  5. Default是指绑定模式由系统自动确定,通常情况下,对于大多数属性,如果数据源属性是可读可写的, 那么默认的绑定模式为TwoWay,如果数据源属性是只读的,那么默认的绑定模式为OneWay。

RelativeSource

  1. RelativeSource常用的有五种查找模式。
  2. Self表示查找自身。
  3. FindAncestor表示查找父级,AncestorLevel表示父级级别,AncestorType表示父级类型。
  4. TemplateParent表示查找控件模板。
  5. Source表示指定数据源。
  6. Path表示指定属性。

Static Resources/Dynamic Resources

  1. Static Resources是静态资源,编译时就确定。
  2. Dynamic Resources是动态资源,在运行时确定。可以动态修改,比如主题切换,多语言支持。

触发器

应用场景

触发器的主要作用就是根据Trigger的不同条件来自动更改外观的属性,或者执行一些动画操作。

Trigger

当鼠标滑过时字体变成红色。

MultiTrigger

当checkbox勾选并且鼠标滑过时字体变绿色。

EventTrigger

鼠标划入长度变长,鼠标移除长度变短。

 ControlTemplate中使用Trigger

DataTrigger

  1. 在ListBox中,当选中的Item为陕西省时,将Item项的文字颜色设置为红色。
  2. 当选中的Item为陕西省西安市时,将Item项的背景色设置为绿色。

MultiDataTrigger

  1. HierarchicalDataTemplate:分层数据模板。
  2. 在TreeView中,当TreeViewItem没有展开并且TreeViewItem是一个目录时,显示目录图片。否则当 该TreeViewItem展开时,显示目录打开的图片。
  3. 当所有的RadioButton都没有选中时,按钮不可用,否则按钮可用。

区别

  1. Trigger和MultiTrigger都是触发器,只不过MultiTrigger是满足多个条件时才触发。
  2. DataTrigger和MultiDataTrigger也是触发器,MultiDataTrigger也是满足多个条件时才触发。
  3. Trigger和MultiTigger仅适用于同一控件中的属性,可以简单理解为面向控件的Property。
  4. DataTrigger和MultiDataTrigger的条件是基于绑定数据的属性值而不是UIElement的属性值,可以简单 理解为面向数据的Binding。
  5. MultiTrigger和MultiDataTrigger的条件都是在Conditions中编写的。

控件

Page/UserControl/Window

  1. Page通常用于承载网页。
  2. UserControl是用户控件,如果控件需要被重复使用时就可以使用用户控件,比如在很多窗口中,用同 一个自定义的日期控件。
  3. Window是主窗口,通常一个windows程序中只有一个主窗口。

DataTemplate/ControlTemplate/ItemsPanelTemplate

  1. DataTemplate是指数据模板。
  2. ControlTemplate是指控件模板。
  3. ItemsPanelTemplate是指项布局模板。

常用控件

  1. ShowInTaskbar 窗口是否具有任务栏按钮
  2. 内容控件:只能有一个子元素作为它的内容。
  3. WPF允许控件没有Name属性值,当后台代码需要引用对象的时候需要设置Name。
  4. RadioButton:同一组单选按钮,它们是互斥的关系。
  5. Border:边框,围绕在其它元素周围。
    1. 和布局面板一起使用,作为布局面板的边框。
    2. 作为任意控件的边框显示。
    3. Border只能有一个元素作为它的子元素。Border作为布局面板边框,布局面板内显示多个子元素。
  6. TextBlock和Lable区别:加载Labe比TextBlock耗费更多时间,label其实就是一个个性化的TextBlock, TextBlock比较底层只能显示文本。
  7. Run:是一个内联元素,用于在TextBlock或者FlowDocument中显示一段文本,通常用于控制一段文本的样式,比如对一部分文本应用不同的样式,辅助TextBlock或者FlowDocument完成文本的格式化和排版。

  8. StackPanel:堆栈面板,子元素超出的部分会被隐藏。
  9. WrapPanel:流面板,子元素超出的部分会自动换行。
  10. DockPanel:停靠面板。特点:先添加的子元素,优先占用边角(优先占有权),所有子元素区域不会重叠。
  11. Canvas:画布面板(坐标面板),定义区域子元素的显示位置,指定相对于面板的坐标来定 位子元素显示 的位置。
    1. 附加属性:Canvas.Left Canvas.Right Canvas.Top Canvas.Bottom
    2. 坐标:(left,top) (left bottom) (right,top) (right,bottom)
    3. 不能子元素指定两个以上的附加属性,如果制定了,忽略后者。
    4. 当窗口大小变化,Canvas的尺寸就随之变动,子元素的位置也变化,但是子元素的坐标相对于 Canvas的位置没有变化。
    5. ClipToBounds 默认值false,溢出不裁剪。True,溢出裁剪。
    6. 应用:精确定位,画图,最简单的布局。
  12. Grid:网格面板,类似于WinForm中TableLayoutPanel,行和列方式布局页面或页面中某一块区域。每 个单元格可以包含一个元素或多个元素。
    1. Expander:折叠控件。
    2. Fram:支持导航,可以将一个页面导航到另一个页面,可能承载Page页。
    3. Page页:封装一页的内容。
    4. ListView:数据列表控件。用于显示数据项的列表。以列(GridViewColumn)形式显示数据项的视图模式。
  13. DataGrid:网格控件,可以自定义网格显示数据的控件。
    1.  DataGrid属性:

      1. RowHeaderTemplate:行标题模板

      2. CanUserAddRows:是否添加新行

      3.  IsReadOnly:是否可以编辑其中的值

      4. VerticalScrollBarVisibility/HorizontalScrollBarVisibility 垂直/水平滚动条的显示

      5. CurrentItem:当前单元格的行绑定的数据项

      6.  CanUserDeleteRows:是否可以删除行

      7.  RowStyle/CellStyle:行/单元格 样式

      8. HeaderVisibility:行和列头的可见性

      9. AlternatingRowsBAckground:交替行上使用的背景画笔

      10. GridLinesVisibility:显示哪些网格线

      11. VerticalGridLinesBrush/HorizontalGridLinesBrush 垂直/水平网格线画笔

      12. RowHeaderWidth行标题宽度,ColumnHeaderHeight列标题高度,RowHeight行高

      13. AutoGenerateColumns:是否自动创建列

      14. SelectionUnit/SelectionMode:选择单元(单元格,行或者两者) /单选或多选

    2.  DataGrid中的列:

      1. DataGridTextColum:文本显示内容,数据类型为String

      2.  DataGridCheckBoxColumn:复选框的形式显示内容,数据类型为Boolean

      3. DataGridComboBoxColumn:下拉列表的形式显示内容,数据类型为Enum

      4. DataGridHyperlinkColumn:超链接的形式显示内容,数据类型为Uri

      5.  DataGridTemplateColumn:模板列,自定义显示样式

  14. UniformGrid:界面均等份布局。

  15. Menu:Windows菜单控件。
    1. Menu属性:
      1. IsMainMenu:是否接受主菜单激活通知,alt或F10激活。
      2. MenuItem:Menu控件中的可选项,带标题的条目控件。
      3. ContextMenu:特定于某个元素之上的功能菜单。右键菜单,上下文菜单。
    2. ContextMenu属性:HorizontalOffset,VertiCalOffset 右键菜单控件相对于点击位置的水平,垂直距离点。
    3. TreeView:树形控件,以节点的形式显示数据。节点对应树形控件的项,项可以展开与折叠。
      1. SelectedItem:选择的项
      2. SelectedValue:选择项的值
      3. ItemSource:数据源
      4. ToolBar:工具栏控件。为一组命令或控件提供的容器。
  16. ToolBar属性
    1. Orientation:指示内部项的布局方向,只读属性。
    2. ToolBarTray:布局ToolBar的容器,呈放多个ToolBar。
  17. StatusBar:状态栏控件。
  18. MediaElement:媒体播放控件,音频或视频文件。
  19. RichTextBox:对流文档(FlowDocument)对象进行操作的丰富编辑控件。

常用的九种布局

Gird

  1. Grid是网格面板,最常用的布局容器,就是整体的页面布局。
  2. 注意:
    1. 固定长度:值为一个确定的数字。
    2. 自动长度:值为Auto,就是取实际控件所需要的最小值。
    3. 比例长度:*表示占用剩余的全部长度。一个长度为2*,一个长度为*,2*表示占剩余全部长度的2/3,*表示占剩余全部长度的1/3。

StackPanel

StackPanel是堆栈面板,按照行或者列进行顺序排列,不会换行。

WrapPanel

WrapPanel是流面板,在有限的容器范围内,可以自动换行或者换列。

DockPanel

DockPanel是停靠面板,让元素停靠在整个面板的某一条边上,然后拉伸元素填满全部的宽度或者高度。

UniformGrid

UniformGrid是Grid的简化版,可以进行界面均等份布局,每个单元格大小相同。

Canvas

理解

Canvas类似于坐标系的面板,所有的元素通过设置坐标来决定其在坐标系中的位置。

示意图

ScrollViewer

ScrollViewer是带有滚动条的面板,在ScrollViewer中只能有一个子控件,如果要显示多个子控件,需要通过Panel控件进行包裹。

ViewBox

  1. ViewBox的作用是拉伸或者延展位于其中的组件,用来填满可用的控件。ViewBox中只能有一个子控件, 如果要显示多个子控件,需要通过Panel控件进行包裹。
  2. 常用属性:
    1. Stretch:获取或者设置拉伸模式,用来决定该组件中的内容应该用怎样的形式填充该组件的已有空间,默认值为Uniform。

Border

Border是一个装饰控件,用来绘制边框和背景。Border中只能有一个子控件,如果要显示多个子控件,需要通过Panel控件进行包裹。

子元素水平(Horizontal)/垂直(Vertical)对齐方式失效问题

Canvas/WrapPanel

Canvas/WrapPanel子元素HorizontalAlignment,VerticalAlignment属性无效。

Gird

Grid子元素HorizontalAlignment,VerticalAlignment属性有效。

StackPanel
  1. StackPanel当Orientation为Horizontal时,子元素HorizontalAlignment属性无效,VerticalAlignment属性有效。
  2. 当Orientation为Vertical时,子元素HorizontalAlignment属性有效,VerticalAlignment属性无效。
DockPanel
  1. DockPanel子元素设置为DockPanel.Dock=Left/Right,子元素的HorizontalAlignment属性无效,VerticalAlignment属性有效。
  2. 子元素设置为DockPanel.Dock=Top/Bottom,子元素的HorizontalAlignment属性有效,VerticalAlignment属性无效。
  3. 子元素LastChildFill设置为true时,DockPanel.Dock无效,HorizontalAlignment,VerticalAlignment属性有效。

VisualTreeHelper/LogicalTreeHelper

区别
  1. VisualTreeHelper用于遍历可视化树,可视化树表示在UI上呈现的元素及其关系,包括控件, 容器,布局等。
  2. LogicalTreeHelper用于遍历逻辑树,逻辑树表示了元素之间的逻辑关系,如控件的父子关系,嵌套关系 等。
获取控件的子元素

获取控件指定类型的子元素
VisualTreeHelper
逻辑树遍历和判断类型

逻辑树扩展和判断类型

VisualTreeHelper类和判断类型

LogicalTreeHelper

UpdateLayout

  1. UpdateLayout是一个用于强制UI元素更新布局的方法。
  2. 比如,在代码中修改了某个UI元素的属性或者数据源,然后希望立即看到这些变化反映在界面上,就可以调用UpdateLayout方法来触发布局更新。
  3. 频繁调用UpdateLayout可能会影响应用程序性能,因此建议只在确实需要立即刷新布局时才使用该方法,避免滥用。

焦点

键盘焦点/逻辑焦点
  1. 键盘焦点指接收键盘输入的元素。
  2. 逻辑焦点指焦点范围中具有焦点的元素。
FocusManager的FocusedElement/IsFocusScope
  1. FocusedElement可以直接指定具有键盘焦点的元素,只有FocusScope中的元素才能成为焦点元素。
  2. IsFocusScope用于标识元素是否作为焦点范围,默认焦点范围是Window,多个FocusScope嵌套的情况下,焦点会在各个焦点范围之间传递。
IsTabStop/TabIndex
  1. IsTabStop决定了元素是否可以通过Tab键来获取焦点,默认是true。
  2. TabIndex决定了元素在Tab键焦点顺序中的位置,具有较小TabIndex值的元素将先获得焦点,而具有 较大TabIndex值的元素将后获得焦点。如果多个元素的TabIndex值相同,则它们按照其在XAML中的 出现顺序来确定焦点顺序。
IsKeyboardFocused/IsKeyboardFocusWithin
  1. IsKeyboardFocused判断元素是否具有键盘焦点。
  2. IsKeyboardFocusWithin判断元素或其子元素是否具有键盘焦点。
清除焦点/获取焦点

获取单元格焦点

模板

控件模板

是什么

控件模板就是控件的外衣,通过修改控件模板来定义控件的外观。

示意图

数据模板

是什么

数据模板就是数据的外衣,通常用于在内容控件或者列表控件中显示数据。

示意图

面板模板

是什么

面板模板就是面板的外衣,通常用于自定义控件的布局。

示意图

区别

  1. 控件模板针对的是控件的本身,决定控件外观的是ControlTemplate,可以改变控件本身的样子。
  2. 数据模板针对的是控件的数据,决定数据外观的是DataTemplate,可以改变控件绑定数据的表现形式。
  3. 面板模板应用的是ItemsPanelTemplate,针对的是控件的布局,可以改变控件的布局方式。

Dispatcher

是什么

Dispatcher属性可以将其它线程投放到UI线程,让UI线程去执行。

总结

  1. 在WPF中,所有的对象都派生自DispatcherObject对象,DispatcherObject对象通过Dispatcher属性用 来获取创建对象线程对应的Dispatcher属性。
  2. DispatcherObject对象只能被创建它的线程所访问,其它线程修改DispatcherObject对象时需要取得对 应的Dispatcher属性,调用Invoke方法或者BeginInvoke方法来投入任务。
  3. Invoke方法和BeginInvoke方法从WinForm时代就是一直存在的,只是在WPF中使用了Dispatcher属 性来封装这些线程级的操作。

依赖属性

是什么

  1. 依赖属性是自己没有值,需要通过绑定从其它数据源获取值的属性。
  2. 只有依赖属性才能进行绑定。

为什么要有依赖属性

  1. 在传统的OOP中,多级继承的时候,父类的字段都被继承,子类占用内存空间不可避免的膨胀。
  2. 而且在多级继承中,大多数字段并没有被修改,为了减少对象的体积,从而需要依赖属性。
  3. 在WinForm中,每个UI控件的属性都被赋予了初始值,每个相同的控件在内存中都会保存一份初始值。
  4. WPF的依赖属性在内部使用哈希表的存储机制,对多个相同控件的相同属性值只保存一份。

如何添加依赖属性

依赖属性的优势

  1. 依赖属性主要解决了传统OOP多级继承中,大多数字段值不改变的情况,减少了内存占比。
  2. 依赖属性是通过调用DependencyObject对象的GetValue方法和SetValue方法来对依赖属性进行读写 的。
  3. DependencyObject对象使用了哈希表的存储机制,对应的Key就是属性的HashCode值,而值就是注 册的DependencyProperty属性。
  4. 依赖属性是以数据为中心,当数据源发生改变时,关联的UI数据也会改变。
  5. 依赖属性的值可以通过Binding依赖于其它对象上,这就使得数据源一变动,依赖于此数据源的依赖属 性全部进行更新。

依赖属性继承

通过AddOwer方法可以继承其它控件的依赖属性。

只读依赖属性

只读依赖属性是用

DependencyProperty.RegisterReadonly方法来替换DependencyProperty.Register方法。

附加属性

附加属性最常见的场景就是布局容器中DockPanel和Grid的附加属性。

 

 附加属性是用RegisterAttached方法替代了Register方法。

依赖属性验证

  1. ValidateValueCallback函数可以接受或拒绝新值,验证值是否合法。
  2. CoerceValueCallback函数可以将新值强制修改为可被接受的值。
  3. PropertyChangedCallback函数可以触发依赖属性值的更改,当值发生改变时,可以做一些操作。

依赖属性的监听

  1. 第一种方法是使用PropertyChangedCallback函数进行监听。
  2. 第二种方法是获取DependencyPropertyDescriptor对象,并调用AddValueChange方法为其绑定一个回 调函数进行监听。

依赖对象

  1. 对象创建时不包含字段所占用的空间,在使用这个字段时通过其它对象的数据来分配空间,这种对象 就是依赖对象。
  2. 这种分配空间的能力就是依靠依赖属性来实现的。

事件

直接路由事件

直接路由事件,它来自一个元素,并且不传递给其它的元素,比如MouseEnter事件就是当鼠标移动到一个元素上面时触发的事件,它就是一个直接路由事件。

冒泡事件

冒泡事件是指从事件源传递到顶部元素,也就是在包含层次中向上传递的事件,比如MouseDown事件就是一个冒泡路由事件。它首先被单击的元素触发,然后就是该元素的父元素触发,以此类推,最后到达WPF元素树的顶部为止。

隧道事件

  1. 隧道(Preview)事件是指从顶部元素传递到事件源,也就是在包含层次中向下传递的事件,比 如PreviewKeyDown就是一个隧道路由事件。在一个窗口上按下某个键,首先是窗口,然后是窗口下面的元素,最后到达按下键盘上面的按键时具有焦点的元素。
  2. 隧道事件总是在冒泡事件之前被触发。
  3. 如果将隧道路由事件标记为已处理的,那么冒泡路由事件就不会触发,这是因为这两个事件共享同一 个RoutedEventArgs类的实例。
  4. 隧道路由事件可以用来执行一些预处理操作,比如根据键盘上特定的键执行特定的操作,或过滤掉特定的鼠标操作,都可以在隧道路由事件处理程序中进行处理。

阻止事件传播

  1. 在设置e.Handled=true的时候,不管是冒泡事件还是隧道事件,它还是会继续传播的,只是对应的事 件不会在被处理了。
  2. 如果想继续响应相应的事件,可以通过AddHandler方法进行注册。
  3. 每当触发事件处理程序之前,都会检查RoutedEventArgs的Handled属性和_handleEventsToo字段。当Handle=true时,其实路由事件还是一样会传递,传递到对应事件的处理程序中时,只是因为 Handle为true和_handleEventsToo为false,从而导致事件处理程序没有运行。
  4. 如果通过AddHandler(RoutedEvent,Delegate,Boolean)注册事件处理程序,把_handleEventToo显示设置为true,所以即使Handle为true,该元素的事件处理程序照样会被执行,因为此时的if条件一样会 为true。

自定义路由事件

路由事件由只读的静态字段表示,在一个静态构造函数通过

EventManager.RegisterRoutedEvent函数注册,然后定义一个事件进行包装。

共享路由事件

  1. 可以在类之间共享路由事件的定义,实现路由事件的继承。
  2. 比如UIElement类和ContentElement类都使用了MouseUp事件,但是MouseUp事件是由Mouse类定 义的。
  3. 所以UIElement类和ContentElement类只是通过RouteEvent.AddOwner方法重用了MouseUp事件。

引发和处理路由事件

路由事件通过RaiseEvent方法触发,所有的元素都从UIElement类继承了该方法。

附加事件

  1. 比如StackPanel面板中包含了一堆按钮,现在希望在一个事件处理程序中处理所有这些按钮的单击事 件。
  2. 可以将每个按钮的Click事件关联到同一个事件处理程序中,但是Click事件支持事件冒泡,所以可以 通过更高层次的元素来关联Click事件处理所有按钮的单击事件。

生命周期

  1. SourceInitialized事件在取得窗口句柄属性时触发。
  2. Activated事件在窗口获取焦点时触发。
  3. Loaded事件在窗口加载时触发。
  4. ContentRendered事件在窗口第一次呈现结束后立即触发。
  5. Activated事件在窗口获取焦点时触发。
  6. Deactivate事件在窗口失去焦点时触发。
  7. Closing事件在窗口关闭过程中触发。
  8. UnLoaded事件在窗口卸载时触发。
  9. Closed事件在窗口关闭完成后触发。

DevExpress

MVVM

POCOViewModel

  1. POCOViewModel特性:不用在View层中指定DataContext,就可以指定对应的ViewModel。
  2. 属性标记为Virtual进行数据双向绑定。
  3. 方法在View层绑定的时候用Command结尾,而ViewModel层不需要Command结尾来进行命令绑定。

DependsOn

  1. DependsOn表示该属性依赖于其它属性,当其它属性的值发生变化时,该属性的值会重新计算。
  2. 下面实例中,当FontSize属性的值发生变化时,FontColor属性也会相应的更新。

依赖注入

  1. 依赖注入通过ServiceContainer.Default.RegisterService()进行注入。
  2. 依赖注入获取通过ServiceContainer.Default.GetRequiredService获取。

转换器

  1. BooleanNegationConverter
  2. BooleanToObjectConverter
  3. BooleanToVisibility
  4. ObjectToBooleanConvert
  5. StringToBooleanConvert
  6. StringToVisibiltyConverter

布局

X:Name

X:Name:实例类型不是派生在FrameworkElement上时,用x:Name来设置别名。

WPF中ViewModel层弹出新窗口

  1. ViewModel定义EventHandler事件,View层用EventHandler事件打开委托,ViewModel中通过按钮的 Command触发EventHandler。
  2. Dictonary注册窗体的Type和key,反射创建窗体对象打开窗体。
  3. Dictonary注册窗体的Type和委托(Action,Func),执行委托打开窗体,委托包装的方法,在窗体内部执 行打开窗体的逻辑。

WPF和WinForm区别

生态方面的区别

  1. 现在西安很多公司,尤其是传统行业大部分用的还是WinForm。
  2. 因为很多公司的用户对界面的美观性要求不高,你只要给我把功能实现了就可以了,所以用WinFrom 就非常合适。WinFrom就是拖拉拽,能非常快速的开发出一个功能不复杂的程序,并且用起来还比较 流畅。对于大多数公司来说成本低,不需要那么多研发,而且公司也养不了那么研发,一般最多2到 3个人用WinFrom开发程序,然后维护,甚至有时候就是一个人。
  3. 如果用户对界面的美观性要求非常高,并且任何按钮,组件都需要按照要求定制化开发,里面还包含 了各种动画效果以及各种3D显示效果,这个时候就必须考虑使用WPF。如果用了WPF但是又没有那 么多人去做,基本上做的人就相当于全栈开发。
  4. 首先WPF的学习成本比WinFrom高的多,WPF不是拖拉拽就能完成开发,定制化高的软件都需要程 序员去写xmal来实现,xmal包含了各种样式和各种触发器,以及各种各样五花八门非常灵活的数据 绑定。
  5. 而且用WPF就得考虑视图和数据分离,前后端分离,这就相当于程序员既要写xaml还要写业务,甚 至还要写接口,工作量会非常大。当然WPF也可以像WinFrom那样不使用MVVM,不进行视图和数 据的分离,所有的事件和业务都写到xaml对应的cs文件中,然后写个DBHelper啥的直接访问数据库, 这样做如果公司研发团队就几个开发为了提高效率没啥问题。如果团队比较大,人比较多,像某些公 司研发加起来50多个人,就得分工明确,让专门写xaml的去写xaml,专门写业务的去写ViewModel, 专门写接口的去写gRPC接口,这么做最大的好处就是可以降低系统的耦合度,后面维护起来也方便, 专人专职去做自己擅长的事情。

技术方面的区别

  1. WinForm本身的开发模式,存在天然的缺陷。给一个WinForm控件进行数据绑定操作,然后按照事件 驱动的模式,根据控件名来获取原始绑定的数据,界面和数据是完全耦合。
  2. WPF是MVVM模式,数据和视图分离,不再为每个元素添加固定的名称,通过数据驱动进行业务 代码编写。
  3. WinForm的设计器和cs文件的代码耦合度是非常高的,不能独立进行页面设计。
  4. WPF是数据驱动UI,数据是核心,处于主动地位。UI从属于数据,并且表达数据,处于被动地位。
  5. WinForm中,每个UI控件的属性都被赋予了初始值,每个相同的控件在内存中都会保存一份初始值。
  6. WPF依靠依赖属性解决了在传统OOP多级继承中,大多数字段值不改变的情况,减少了内存占比。
  7. WPF底层使用Direct X接口,加强了3D图形和声音效果。
  8. WinForm底层使用GDI+接口,主要是负责绘图程序之间的信息交换和处理,以及所有windows程序的 图形输出。

如何在WPF应用程序中全局捕获异常

Application.DispatcherUnhandledException

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐