流水线基类
cs
public class ViewModelBase : INotifyPropertyChanged
{
protected readonly TaskScheduler _uiScheduler;
public ViewModelBase()
{
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// UI标准流水线:捕获状态→后台任务→更新UI→恢复状态
/// </summary>
protected void ExecuteWithUiPipeline<TState, TResult>(
Func<TState> captureState,
Func<TState, TResult> backgroundWork,
Action<TResult> updateUi,
Action<TState> restoreUi,
Action<bool> busyFlagSetter)
{
busyFlagSetter(true);
var state = captureState();
Task.Factory.StartNew(() => backgroundWork(state))
.ContinueWith(task =>
{
try
{
if (task.Exception != null)
{
var ex = task.Exception.InnerException ?? task.Exception;
MessageBox.Show("操作异常:" + ex.Message);
return;
}
var result = task.Result;
updateUi(result);
restoreUi(state);
}
finally
{
busyFlagSetter(false);
}
}, _uiScheduler);
}
}
子类使用示例
cs
public class TreeViewModel : ViewModelBase
{
private bool _isBusy;
public bool IsBusy { get => _isBusy; set { _isBusy = value; OnPropertyChanged(nameof(IsBusy)); } }
public void RefreshTree()
{
// 定义捕获状态
Func<TreeState> capture = () => new TreeState
{
SelectedId = FindSelectedNode(TreeRoot)?.Id ?? -1,
ExpandedIds = GetExpandedIds(TreeRoot)
};
// 后台工作
Func<TreeState, List<NodeModel>> work = state => LoadDataFromDb();
// 更新UI
Action<List<NodeModel>> update = data =>
{
TreeRoot = new ObservableCollection<NodeViewModel>(BuildTree(data));
};
// 恢复状态
Action<TreeState> restore = state =>
{
RestoreState(TreeRoot, state.SelectedId, state.ExpandedIds);
};
// 执行流水线
ExecuteWithUiPipeline(capture, work, update, restore, busy => IsBusy = busy);
}
}
🧠 总结
ViewModelBase 提供的这个流水线方法,本质上是将WPF异步编程中反复出现的"线程切换 + 状态管理"模式抽象为一个可复用的基础设施。它让子类代码更简洁、更聚焦于业务,同时保证了UI线程安全。你只需要在子类中实现具体的状态捕获、后台任务和UI恢复逻辑,框架自动帮你处理调度和异常。
如果你还想加入防重入 和版本号 功能,可以在子类中扩展,或者在ExecuteWithUiPipeline的基础上再封装一层,传入一个Func<bool>检查是否可以执行,或者集成CancellationToken。这个基类为更高级的封装提供了良好的起点。