C#(WPF)-回调
目录
一、什么是回调(Callback)
回调(Callback) 指的是:
把一个方法作为参数传递给另一个方法,在特定时机由被调用方反向调用该方法。
换句话说:
调用者 → 把函数传给被调用者 → 被调用者在合适时机执行这个函数
核心思想:
A 调用 B
B 在未来某个时间点 再调用 A 提供的方法简单流程:
Main
└── 调用 Process()
└── 执行逻辑
└── 调用 Callback()二、回调的主要作用
| 作用 | 说明 |
|---|---|
| 异步通知 | 异步操作完成后通知调用者 |
| 事件驱动 | 响应事件(按钮点击、状态变化) |
| 解耦合 | 调用者与执行逻辑分离 |
| 扩展性 | 不修改原代码即可扩展 |
| 自定义行为 | 把行为作为参数传递 |
| 管道处理 | 多个步骤连续处理数据 |
三、C#回调的实现方式
C#提供多种实现方式,本质都是函数引用。
主要方式:
委托 Delegate
Action / Func
事件 Event
接口回调
传统异步 AsyncCallback
Task + async/await
回调链四、委托(Delagate)回调
委托是C#回调的基础机制
1.定义委托
public delegate void ProcessCallback(string result);含义:
一个指向方法的类型
要求方法签名:
void Method(string)2.使用委托回调
public class Processor
{
public void ProcessDate(string data, ProcessCallback callback)
{
Console.WriteLine($"处理数据:{data}");
string result = $"已处理:{data}";
callback?.Invoke(result);
}
}调用:
class Program
{
static void Main()
{
var processor = new Processor();
processor.ProcessData("测试数据", OnProcessComplete);
}
static void OnProcessComplete(string result)
{
Console.WriteLine($"回调结果");
}
}执行流程:
Main
↓
ProcessData()
↓
callback.Invoke()
↓
OnProcessComplete()五、Action / Func 泛型委托
.NET内置委托
优点:
- 不需要自定义 delegate
- 更简洁
1.Action(无返回值)
public void Process(string data, Action<string> callback)
{
string result = $"$处理问题:{data}";
callback?.Invoke(result);
}调用:
processor.Process("数据", result =>
{
Console.WriteLine(result);
});2.Func(有返回值)
public int Transform(int x, Func<int, int> transform)
{
return transform(x);
}调用:
int result = Transform(5, x => x * 2);3.Action / Func 规则
Action
Action
Action<T>
Action<T1, T2>返回值:
voidFunc
Func<T>
Func<T, TResult>
Func<T1, T2, TResult>最后一个是返回值
例:
Func<int, int>
输入 int
返回 int六、事件(Event) 回调
事件是基于委托的发布-订阅模式
常用于:
UI
状态通知
系统事件定义事件
public class TemperatureMonitor
{
public event Action<double> OnTemperatureChanged;
private double _temperature;
public double Temperature
{
get => _temperature;
set
{
if (Math.Abs(_temperature - value) > 0.1)
{
_temperature = value;
OnTemperatureChanged?.Invoke(value);
}
}
}
}订阅事件
monitor.OnTemperatureChanged += HandleTemperature;或
monitor.OnTemperatureChanged += temp =>
{
Console.WirteLine($"温度变化{temp}");
};触发事件
monitor.Temperature = 25.5执行:
OnTemperatureChanged
├── HandleTemperature
└── Lambda七、接口回调(Interface Callback)
适用于:
-
回调方法很多
-
需要回调协议
-
需要扩展
定义接口
public interface IProcessCallback
{
void OnComplete(string result);
void OnError(Exception ex);
}实现接口
public class LoggerCallback : IProcessCallback
{
public void OnComplete(string result)
{
Console.WriteLine($"完成:{result}");
}
public void OnError(Exception ex)
{
Console.WriteLine($"错误:{ex.Message}");
}
}使用
public void Process(string data, IProcessCallback callback)
{
try
{
callback.OnComplete("成功");
}
catch (Exception ex)
{
callback.OnError(ex);
}
}优点
结构清晰
支持多个回调方法
可扩展八、传统异步回调(AsyncCallback)
旧版 .NET异步模式:
Asynchronous Programming Model核心:
BeginXXX
EndXXX
AsyncCallback示例:
processor.BeginProcess(data, callback, state);回调:
void Callback(IAsyncResult ar)
{
processor.EndProcess(ar);
}但现在基本 已被 Task 替代。
九、Task + async/await(现代异步)
异步方法
public async Task<string> ProcessAsync(string data)
{
await Task.Delay(1000);
return $"处理完成{data}";
}ContinueWith回调
processor.ProcessAsync("数据")
.ContinueWith(t =>
{
Console.WriteLine(t.Result);
});async回调
await processor.ProcessWithCallbackAsync("数据", async result =>
{
Console.WriteLine(result);
});十、回调链(Callback Chain)
类似管道处理Pipeline。
public void ProcessChain(string data, params Action<string>[] callbacks)
{
string current = data;
foreach (var cb in callbacks)
{
cb(current);
current = $"处理:{current}";
}
}调用:
chain.ProcessChain("原始",
x => Console.WriteLine($"步骤1 {x}"),
x => Console.WriteLine($"步骤2 {x}"),
x => Console.WriteLine($"步骤3 {x}")
);十一、实际开发选择
| 场景 | 推荐 |
|---|---|
| 简单回调 | Action / Func |
| 事件通知 | event |
| 复杂回调协议 | interface |
| 异步操作 | async / await |
| 链式处理 | 回调链 |
| 旧代码维护 | AsynCallback |
Demo:模拟一个大文件分析工具
功能:
- 用户点击 开始分析
- 后台线程 异步处理数据
- 进度回调
- 日志回调
- 完成回调
- 错误回调
- UI自动更新(MVVM + INotifyPropertyChanged)
- 取消操作
- 事件回调 + 委托回调 + async/await 混合
项目结构:
WpfCallbackDemo
│
├── MainWindow.xaml
├── MainWindow.xaml.cs
│
├── ViewModels
│ └── MainViewModel.cs
│
├── Services
│ └── DataAnalyzer.cs
│
├── Callbacks
│ └── IAnalyzerCallback.cs
│
├── Utils
│ └── RelayCommand.cs架构关系:
UI (WPF)
│
▼
ViewModel
│
▼
Service (DataAnalyzer)
│
├── 事件回调 Event
├── 委托回调 Action
├── 接口回调 Interface
└── async/await<Window
x:Class="WpfCallbackDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfCallbackDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:WpfCallbackDemo.ViewModels"
Title="Callback Analyzer"
Width="500"
Height="350"
mc:Ignorable="d">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<Grid Margin="20">
<StackPanel>
<Button
Height="40"
Command="{Binding StartCommand}"
Content="Start Analysis" />
<Button
Height="40"
Margin="0,10,0,0"
Command="{Binding CancelCommand}"
Content="Cancel" />
<ProgressBar
Height="25"
Margin="0,10,0,0"
Maximum="100"
Value="{Binding Progress}" />
<ListBox
Height="150"
Margin="0,10,0,0"
ItemsSource="{Binding Logs}" />
</StackPanel>
</Grid>
</Window>using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using WpfCallbackDemo.Callbacks;
using WpfCallbackDemo.Services;
using WpfCallbackDemo.Utils;
namespace WpfCallbackDemo.ViewModels
{
public class MainViewModel : INotifyPropertyChanged, IAnalyzerCallback
{
private readonly DataAnalyzer analyzer = new DataAnalyzer();
private CancellationTokenSource cts;
public ObservableCollection<string> Logs { get; } = new();
private int progress;
public int Progress
{
get => progress;
set
{
if (progress != value)
{
progress = value;
OnPropertyChanged();
}
}
}
private string status;
public string Status
{
get => status;
set
{
if (status != value)
{
status = value;
OnPropertyChanged();
}
}
}
public RelayCommand StartCommand { get; }
public RelayCommand CancelCommand { get; }
public MainViewModel()
{
StartCommand = new RelayCommand(async _ => await Start());
CancelCommand = new RelayCommand(_ => Cancel());
analyzer.ProgressChanged += OnProgressChanged;
}
private async Task Start()
{
Logs.Clear();
cts = new CancellationTokenSource();
await analyzer.AnalyzeAsync(
"datafile.txt",
log => Logs.Add(log), // 委托回调
this, // 接口回调
cts.Token);
}
private void Cancel()
{
cts?.Cancel();
}
// Event 回调
private void OnProgressChanged(int value)
{
Progress = value;
Logs.Add($"Progress: {value}%");
}
// 接口回调
public void OnCompleted(string result)
{
Status = result;
Logs.Add("Analysis completed successfully.");
}
public void OnError(string error)
{
Status = error;
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}using WpfCallbackDemo.Callbacks;
namespace WpfCallbackDemo.Services
{
public class DataAnalyzer
{
// Event 回调
public event Action<int> ProgressChanged;
public async Task AnalyzeAsync(
string file,
Action<string> logCallback,
IAnalyzerCallback callback,
CancellationToken token)
{
try
{
for (int i = 0; i <= 10; i++)
{
token.ThrowIfCancellationRequested();
await Task.Delay(500);
ProgressChanged?.Invoke(i * 10);
logCallback?.Invoke($"Processing block {i}");
}
string result = $"Analysis Completed: {file}";
callback.OnCompleted(result);
}
catch (OperationCanceledException)
{
callback.OnError("Operation cancelled");
}
catch (Exception ex)
{
callback.OnError(ex.Message);
}
}
}
}namespace WpfCallbackDemo.Callbacks
{
public interface IAnalyzerCallback
{
void OnCompleted (string result);
void OnError (string ex);
}
}执行流程:
Button
↓
Command
↓
ViewModel.Start()
↓
DataAnalyzer.AnalyzeAsync()产生三种回调
1. 事件回调 Event
Service
↓
ProgressChanged Event
↓
ViewModel.OnProgressChanged
↓
UI ProgressBar 更新2. 委托回调 Action
Service
↓
logCallback.Invoke()
↓
ViewModel Logs.Add()
↓
UI ListBox 更新3. 接口回调 Interface
Service
↓
callback.OnCompleted()
↓
ViewModel.OnCompleted()
↓
UI Status 更新为什么WPF非常依赖回调?
WPF本质是 事件驱动 + 异步架构
UI不能阻塞:必须保持流程
所以必须:后台线程处理,回调通知UI.