↓ 跳过正文

C#(WPF)-八股文

作者
Hexin
在确定的逻辑与不确定的现实之间,做一名耐心的构建者。
目录

第一部分:WPF 核心知识
#


1. 什么是 WPF?和 WinForms 有什么区别?
#

WPF 是基于 DirectX 的桌面 UI 框架,使用 XAML 构建界面。

对比项 WPF WinForms
渲染引擎 DirectX GDI/GDI+
界面描述 XAML + C# 纯 C# / 设计器
数据绑定 强大 较弱
样式模板 支持 基本不支持
动画 支持 基本不支持
架构模式 适合 MVVM 事件驱动

2. WPF 的核心特点
#

  • XAML
  • 数据绑定
  • 依赖属性
  • 路由事件
  • 样式与模板
  • 动画
  • MVVM

3. 什么是 XAML?
#

  • XAML 是一种声明式标记语言,用来描述 UI。
  • 本质上会被编译成 BAML,再由 WPF 加载生成对象树。
  • 优点是 界面和业务逻辑分离。

4. 什么是逻辑树(Logical Tree)和视觉树(Visual Tree)?
#

  • 逻辑树:描述控件之间的逻辑包含关系,比如 Window -> Grid -> Button。
  • 视觉树:描述控件最终渲染出来的完整结构,包含模板生成的内部元素。
  • 查找控件、事件路由、样式应用时常会涉及这两个概念。

5. 什么是依赖属性(DependencyProperty)?
#

WPF 特有属性系统,不只是普通 CLR 属性。

支持:

  • 数据绑定
  • 样式
  • 动画
  • 默认值
  • 属性值继承
  • 变更通知

常用于自定义控件。


6. 依赖属性和普通属性有什么区别?
#

  • 普通属性:只是字段封装。
  • 依赖属性:由 WPF 属性系统管理,可参与绑定、动画、样式等。
  • 一般控件公开可绑定的属性,优先考虑依赖属性。

7. 如何注册一个依赖属性?
#

public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register(
        "Title",
        typeof(string),
        typeof(MyControl),
        new PropertyMetadata("默认值"));

public string Title
{
    get => (string)GetValue(TitleProperty);
    set => SetValue(TitleProperty, value);
}

8. 什么是附加属性(Attached Property)?
#

  • 某个类定义的属性,可以"附加"到别的对象上使用。
  • 典型例子:Grid.Row、Canvas.Left
  • 本质上也是依赖属性。

9. 什么是路由事件(RoutedEvent)?
#

事件可以在元素树中传播,不只是当前控件自己处理。

三种类型:

  • 冒泡(Bubbling):从源控件向父级传播,如 Click
  • 隧道(Tunneling):从根向源控件传播,一般以 Preview 开头,如 PreviewMouseDown
  • 直接(Direct):只在当前控件触发

10. 什么是数据绑定(Binding)?
#

  • 将 UI 和数据对象连接起来。
  • UI 显示数据、用户修改数据时可同步到对象。
  • 是 WPF 和 MVVM 的核心。

11. 常见 Binding Mode 有哪些?
#

模式 说明
OneWay 数据源 -> UI
TwoWay 双向同步
OneTime 只绑定一次
OneWayToSource UI -> 数据源
Default 使用控件默认模式

常见追问:

  • TextBox.Text 默认是 TwoWay
  • 但 UpdateSourceTrigger 默认通常是 LostFocus

12. 什么是 DataContext?
#

  • DataContext 是绑定时默认的数据源。
  • 它会沿着视觉/逻辑树向下继承。
  • 子元素没显式指定 Source 时,会自动使用 DataContext。

13. Binding 中 Source、ElementName、RelativeSource 的区别?
#

属性 说明
Source 手动指定数据源对象
ElementName 绑定到某个控件
RelativeSource 绑定到相对位置对象,如自己、父元素、TemplatedParent

14. UpdateSourceTrigger 有哪些?
#

值 说明
PropertyChanged 属性变化立即更新
LostFocus 失去焦点更新
Explicit 手动更新

15. 什么是 INotifyPropertyChanged?
#

当对象属性变化时通知 UI 刷新。ViewModel 基本都会实现它。

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

16. ObservableCollection 和 List 的区别?
#

类型 特点
List<T> 集合变化不会自动通知 UI
ObservableCollection<T> 增删集合项时会通知 UI 刷新

注意: ObservableCollection 只通知集合变化,不通知集合中对象属性变化。对象属性变化还要靠 INotifyPropertyChanged。


17. 什么是 ICommand?
#

用来替代按钮点击事件,适合 MVVM。

核心成员:

  • Execute
  • CanExecute
  • CanExecuteChanged

18. 为什么 MVVM 中推荐用 Command,而不是 Click 事件?
#

  • 事件会让 View 和代码后置耦合
  • Command 更符合 MVVM,便于测试和维护
  • 按钮是否可用可以通过 CanExecute 自动控制

19. 什么是 MVVM?
#

层 职责
Model 数据模型
View 界面
ViewModel 界面逻辑和状态

通过绑定和命令连接 View 与 ViewModel,减少 UI 和业务耦合。


20. MVVM 的优点是什么?
#

  • 界面和逻辑解耦
  • 更易测试
  • 更易维护
  • 更适合多人协作
  • 符合 WPF 的绑定机制

21. Style、ControlTemplate、DataTemplate 的区别?
#

类型 作用
Style 设置控件属性、统一外观
ControlTemplate 重定义控件外观结构,不改变数据
DataTemplate 定义数据对象如何显示

一句话记忆:

  • Style 改属性
  • ControlTemplate 改控件长相
  • DataTemplate 改数据展示

22. StaticResource 和 DynamicResource 的区别?
#

类型 特点
StaticResource 加载时解析,性能更好
DynamicResource 运行时查找,资源变化后可动态更新

一般静态资源优先用 StaticResource。


23. Trigger、DataTrigger、EventTrigger 的区别?
#

类型 触发条件
Trigger 基于控件属性值
DataTrigger 基于绑定数据值
EventTrigger 基于事件,常配合动画

24. Converter 有什么用?
#

在绑定过程中进行数据转换。

例如:

  • bool -> Visibility
  • 数字 -> 颜色
  • 枚举 -> 文本

接口:

  • IValueConverter
  • IMultiValueConverter

25. ItemsControl、ListBox、ListView 的区别?
#

控件 特点
ItemsControl 最基础的项控件,只负责显示项
ListBox 支持选择
ListView 更强展示能力,常配合 GridView

26. UserControl 和 CustomControl 的区别?
#

类型 适用场景
UserControl 快速组合现有控件,适合业务界面
CustomControl 适合做可复用控件库,支持模板和主题

面试标准答法:

  • 业务页面用 UserControl
  • 通用控件库用 CustomControl

27. 什么是模板绑定(TemplateBinding)?
#

  • 在 ControlTemplate 中绑定到控件自身属性。
  • 比普通绑定更轻量。
  • 常见于自定义控件模板中。

28. WPF 中 UI 线程问题怎么处理?
#

WPF 大多数 UI 对象只能在创建它的线程访问,通常是主线程。后台线程更新 UI,要通过 Dispatcher 切回 UI 线程。

Dispatcher.Invoke(() =>
{
    txtMessage.Text = "更新UI";
});

29. Dispatcher.Invoke 和 BeginInvoke 的区别?
#

方法 特点
Invoke 同步执行,会阻塞当前线程
BeginInvoke 异步执行,不阻塞

30. async/await 在 WPF 中有什么注意点?
#

  • 不要在 UI 线程上用 .Result 或 .Wait(),容易死锁
  • 耗时操作放后台线程
  • await 后默认会回到 UI 同步上下文,所以可以继续更新 UI

31. WPF 中常见内存泄漏原因有哪些?
#

  • 事件注册后没取消
  • 静态事件
  • 长生命周期对象持有短生命周期对象引用
  • 绑定、计时器、消息订阅没释放
  • 可以用 WeakEventManager 降低事件引用问题

32. WPF 中如何做输入校验?
#

常见方式:

  • ValidationRule
  • IDataErrorInfo
  • INotifyDataErrorInfo
  • 异常校验 ValidatesOnExceptions=True

现在更推荐 INotifyDataErrorInfo,支持异步和多错误。


33. 什么是资源字典(ResourceDictionary)?
#

用来存放样式、模板、画刷、字符串等资源。

可放在:

  • App.xaml
  • Window / UserControl
  • 单独 xaml 文件

可通过 MergedDictionaries 合并多个资源文件。


34. WPF 中常见布局控件有哪些?
#

控件 特点
Grid 最常用,行列布局
StackPanel 横向/纵向堆叠
DockPanel 停靠布局
WrapPanel 自动换行
Canvas 绝对定位
UniformGrid 等分网格

35. Grid 和 StackPanel 怎么选?
#

  • 复杂界面优先 Grid
  • 简单纵向/横向排列用 StackPanel
  • StackPanel 在滚动、拉伸场景下有时不如 Grid 灵活

36. 什么是视觉虚拟化(UI Virtualization)?
#

  • 只创建当前可见项的 UI 元素,提升性能。
  • 大数据列表很重要。
  • 常见依赖 VirtualizingStackPanel。

37. 如何提高 WPF 性能?
#

  • 使用 UI 虚拟化
  • 减少视觉树层级
  • 优先 StaticResource
  • 避免频繁刷新整个 UI
  • 大量数据时分页/懒加载
  • 耗时操作异步处理
  • 少用不必要动画和复杂绑定

38. Show 和 ShowDialog 的区别?
#

方法 特点
Show() 非模态窗口
ShowDialog() 模态窗口,会阻塞当前窗口交互,直到关闭

39. 如何在 WPF 中调试绑定错误?
#

  • 先看 Output 输出窗口
  • 绑定错误通常会直接输出
  • 常见问题:
    • 属性名拼错
    • DataContext 不对
    • 路径错误
    • 转换器异常

40. WPF 中 Loaded、Initialized、Unloaded 的理解?
#

事件 说明
Initialized 对象初始化完成
Loaded 控件已加载到可视树,可开始交互
Unloaded 从界面移除时触发

第二部分:C# 核心知识
#


41. 值类型和引用类型的区别?
#

类型 特点 举例
值类型 直接存值 int、struct、bool、enum
引用类型 存对象引用 class、string、数组

值类型通常分配在栈/内联,引用类型对象通常在堆上。


42. string 是值类型还是引用类型?
#

  • string 是 引用类型
  • 但它是不可变的(immutable)

43. string 和 StringBuilder 的区别?
#

类型 特点
string 不可变,频繁拼接性能差
StringBuilder 适合大量字符串拼接

44. abstract 和 interface 的区别?
#

对比项 abstract interface
是否可有实现 可以 C# 8.0 前不行
字段 可以有 不可以
构造函数 可以有 不可以
继承 单继承 多实现
语义 “是什么” “能做什么”

45. virtual、override、new 的区别?
#

关键字 说明
virtual 父类声明可重写
override 子类真正重写
new 隐藏父类成员,不是重写

46. ref 和 out 的区别?
#

关键字 说明
ref 传入前必须赋值
out 传入前不用赋值,方法内必须赋值

47. 委托和事件的区别?
#

类型 特点
委托 方法引用类型
事件 对委托的封装,只能订阅/取消,不能直接外部触发

事件更安全,适合发布订阅模式。


48. Func、Action、Predicate 是什么?
#

类型 说明
Action 无返回值委托
Func 有返回值委托
Predicate<T> 返回 bool 的委托

49. 什么是装箱和拆箱?
#

  • 装箱:值类型 -> object
  • 拆箱:object -> 值类型
  • 会有性能开销,应尽量避免频繁装拆箱

50. 什么是泛型?有什么好处?
#

让代码支持多种类型而不牺牲类型安全。

好处:

  • 复用
  • 类型安全
  • 减少装箱拆箱
  • 性能更好

51. using 的作用是什么?
#

  • 用于命名空间导入
  • 也可用于资源释放,确保调用 Dispose()

52. IDisposable 有什么用?
#

用来释放非托管资源或重要托管资源。常见如文件流、数据库连接、定时器等。


53. finalizer(析构函数)和 Dispose 的区别?
#

类型 特点
Dispose 手动、确定性释放
析构函数 GC 不确定时间调用,成本高

推荐优先 Dispose。


54. Thread、Task、async/await 的区别?
#

类型 特点
Thread 底层线程
Task 对异步操作的更高层封装
async/await 简化异步编程语法

现代开发更常用 Task + async/await。


55. 什么是死锁?在 UI 中怎么出现?
#

两个或多个操作互相等待,导致永远卡住。

WPF 常见是 UI 线程里调用异步任务的 .Result/.Wait() 导致死锁。


56. LINQ 的延迟执行是什么意思?
#

  • 查询语句定义后不立即执行,真正枚举时才执行。
  • 如 Where、Select 常是延迟执行。
  • ToList()、ToArray() 会立即执行。

57. var、dynamic、object 的区别?
#

类型 特点
var 编译期推断类型,本质仍是强类型
object 所有类型基类,调用成员需强转
dynamic 运行时解析,编译器不过多检查,灵活但不安全

58. == 和 Equals 的区别?
#

  • ==:默认比较引用,部分类型会重载成值比较
  • Equals:一般用于比较对象逻辑相等性
  • 面试回答要看具体类型实现

第三部分:WPF 高频场景题
#


59. 为什么界面不刷新?
#

常见原因:

  • 属性没实现 INotifyPropertyChanged
  • 集合用了 List 而不是 ObservableCollection
  • DataContext 不对
  • 绑定路径写错
  • 后台线程直接更新 UI 导致异常

60. 为什么按钮 CanExecute 改了,但界面没更新?
#

  • 没触发 CanExecuteChanged
  • 或没调用命令重查询逻辑
  • 若用 RelayCommand,需要主动 RaiseCanExecuteChanged

61. DataGrid/ListBox 数据很多卡顿怎么办?
#

  • 开启虚拟化
  • 分页加载
  • 减少复杂模板
  • 避免每项都做重计算
  • 不要频繁重设 ItemsSource

62. 为什么 TextBox 改值后,ViewModel 没更新?
#

  • 绑定模式可能不是 TwoWay
  • UpdateSourceTrigger 可能是 LostFocus
  • 属性没有 set
  • DataContext 不对

63. ObservableCollection 为什么能更新列表,但项内容变化不刷新?
#

因为它只通知"集合变化",不通知"项属性变化"。每个项对象还需要实现 INotifyPropertyChanged。


64. UserControl 中 DataContext 为什么容易出问题?
#

因为 UserControl 里如果自己设置 DataContext = this,会覆盖外部传入的 DataContext。正确做法:谨慎设置,必要时用 RelativeSource 或依赖属性传值。


65. 什么时候用 DependencyProperty,什么时候用 INotifyPropertyChanged?
#

场景 选择
控件开发、需要样式/动画/绑定支持 DependencyProperty
ViewModel 属性通知 INotifyPropertyChanged

66. 什么时候用事件,什么时候用命令?
#

  • MVVM 中优先用 命令
  • 控件内部行为、底层交互、复杂路由事件可用 事件

67. StaticResource 用得好好的,什么时候必须用 DynamicResource?
#

主题切换、运行时资源变更、皮肤切换等需要动态刷新的场景。


68. 为什么会选择 MVVM?
#

为了降低 View 和业务逻辑耦合,提高可维护性、可测试性和复用性。


第四部分:面试高频短答速记
#


69. WPF 绑定失败首先看什么?
#

看 Output 输出窗口。

70. TextBox.Text 默认绑定模式是什么?
#

默认 TwoWay,默认 UpdateSourceTrigger 通常是 LostFocus。

71. Grid.Row 是什么?
#

附加属性。

72. Button.Click 属于什么事件?
#

路由事件,一般是 冒泡事件。

73. PreviewMouseDown 属于什么事件?
#

隧道事件(Tunneling)。

74. DataTemplate 用于什么?
#

定义"数据对象怎么显示"。

75. ControlTemplate 用于什么?
#

定义"控件自己长什么样"。

76. ObservableCollection 是否线程安全?
#

不是线程安全的。跨线程修改常会报错,需要切回 UI 线程或做同步处理。

77. WPF 中跨线程更新 UI 怎么办?
#

用 Dispatcher。

78. WPF 中最常见架构模式?
#

MVVM。


第五部分:面试官最爱听的标准短句
#


1. 为什么用 MVVM?
#

为了降低 View 和业务逻辑的耦合,提高可维护性、可测试性和复用性。

2. WPF 核心机制有哪些?
#

数据绑定、依赖属性、路由事件、样式模板、命令机制。

3. 依赖属性有什么用?
#

让属性能参与绑定、样式、动画和 WPF 属性系统。

4. ObservableCollection 为什么常用?
#

因为集合增删变化时能自动通知 UI 刷新。

5. WPF 跨线程更新 UI 怎么做?
#

通过 Dispatcher 切回 UI 线程。

6. 样式和模板区别?
#

Style 改属性,Template 改结构和外观。

7. 绑定失败怎么看?
#

先看 Output 窗口的绑定错误信息。


第六部分:15 个必背关键词
#

  1. MVVM
  2. DataContext
  3. Binding
  4. TwoWay
  5. INotifyPropertyChanged
  6. ObservableCollection
  7. ICommand
  8. DependencyProperty
  9. AttachedProperty
  10. RoutedEvent
  11. Style
  12. ControlTemplate
  13. DataTemplate
  14. Dispatcher
  15. Validation

第七部分:1 分钟自我介绍模板
#

我主要做 C# 和 WPF 桌面端开发,平时开发中比较常用 MVVM 架构,熟悉数据绑定、命令、依赖属性、路由事件、样式模板、资源字典和异步更新 UI 等内容。项目里也处理过列表性能优化、用户控件封装、输入校验、跨线程 UI 更新等问题。我比较关注代码解耦和可维护性,通常会通过 ViewModel、Command、Converter、ResourceDictionary 等方式优化项目结构。