MVVM 观察者模式
参考知乎-https://zhuanlan.zhihu.com/p/676107986
1.委托
.NET内置委托类型
- 返回一个布尔值
Predicate<int> isEven = (number) => number % 2 == 0; // 接受一个整数参数并判断是否为偶数
举例:
1
| Action<string> del = message => Console.WriteLine("你说:" + message);`
|
1 2 3 4
| void AnonymousMethod(string message) { Console.WriteLine("你说:" + message); }
|
使用Invoke
调用委托
1 2 3 4 5 6
| Action<string> showMessage = msg => Console.WriteLine(msg);
showMessage("你好"); showMessage.Invoke("你好");
|
Invoke
可能会配合空值条件运算符一起使用,例如:myAction?.Invoke("Hello");
,只有当myAction
被赋值了,即委托变量指向某个方法了”,才会调用委托。
MVVM
架构中使用委托,事件,接口解耦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MyViewModel { public Action<string> ShowMessageAction { get; set; }
public void DoSomething() { ShowMessageAction?.Invoke("处理完成"); } }
var vm = new MyViewModel(); vm.ShowMessageAction = msg => MessageBox.Show(msg); this.DataContext = vm;
|
2.事件
- 事件是对委托的封装,是用来做发布-订阅的一种通信机制。事件声明在一个类中,它需要委托类型的名称,任何注册到事件的处理程序都必须与委托类型的签名和返回类型匹配。

事件举例
- 发布者(Publisher)
定义:负责“声明”并“触发”事件的类或结构。
职责:
• 用 event 关键字声明事件。
• 在合适的业务时机“触发”事件。
示例:
1 2 3 4 5 6 7 8 9 10 11
| public class StockPrice { public event Action<string, decimal> OnPriceChanged; private decimal _price;
public void UpdatePrice(decimal newPrice) { _price = newPrice; OnPriceChanged?.Invoke("AAPL", _price); } }
|
- 订阅者(Subscriber)
定义:对某事件感兴趣,并向发布者“注册”自己的类或结构。
职责:
• 拿到发布者实例的引用。
• 使用 +=
把符合签名的方法挂到事件上。
• 必要时用 -=
取消订阅,防止内存泄漏。
示例:
1 2 3 4 5 6 7 8 9 10 11 12
| public class Investor { public void Subscribe(StockPrice stock) { stock.OnPriceChanged += HandlePriceChanged; }
private void HandlePriceChanged(string symbol, decimal price) { Console.WriteLine($"{symbol} 最新价:{price}"); } }
|
- 事件处理程序(Event Handler)
定义:订阅者提供的、与事件签名匹配的方法。
特点:
• 参数由事件声明决定(常见为 void MethodName(object? sender, EventArgs e);
)。
• 在事件被触发时,由发布者“顺序调用”。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class MyEventArgs : EventArgs { public string Message { get; set; } }
public class Button { public event EventHandler<MyEventArgs> Clicked; public void Click() { Clicked?.Invoke(this, new MyEventArgs { Message = "按钮被按下" }); } }
public class Form1 { public Form1(Button btn) { btn.Clicked += Button_Clicked; }
private void Button_Clicked(object? sender, MyEventArgs e) { MessageBox.Show(e.Message); } }
|
- 触发(Raise / Fire / Invoke)事件
定义:发布者在内部满足某条件时,执行事件委托列表中的所有方法。
关键点:
• 用 null-条件运算符 ?.
判空,避免无订阅者时抛 NullReferenceException。
• 调用顺序 = 订阅顺序(多播委托)。
• 若某处理程序抛异常,后续处理程序仍可用 try/catch 逐个保护。
3. 使用接口注入 UI 行为
定义一个接口,例如:
1 2 3 4
| public interface IMessageService { void ShowMessage(string message); }
|
ViewModel 依赖这个接口,而不关心它的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class MyViewModel { private readonly IMessageService _messageService;
public MyViewModel(IMessageService messageService) { _messageService = messageService; }
public void DoWork() { _messageService.ShowMessage("工作完成"); } }
|
在 View 层实现接口并传入:
1 2 3 4 5 6 7 8 9 10 11
| public class MessageService : IMessageService { public void ShowMessage(string message) { MessageBox.Show(message); } }
var vm = new MyViewModel(new MessageService()); this.DataContext = vm;
|