欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF MVVM UI分离之《交互与数据分离》

程序员文章站 2022-05-11 16:17:52
在我们使用WPF过程中,不可避免并且超级喜欢使用MVVM框架。 那么,使用MVVM的出发点是视觉与业务逻辑分离,即UI与数据分离 诸如下面的问题: 删除操作,假如需要先执行一部分数据的处理,然后删除界面列表中的子项,之后再执行其它数据的处理。请问此业务该放置于Xaml.cs文件,还是ViewMode ......

在我们使用WPF过程中,不可避免并且超级喜欢使用MVVM框架。

那么,使用MVVM的出发点是视觉与业务逻辑分离,即UI与数据分离

诸如下面的问题:

删除操作,假如需要先执行一部分数据的处理,然后删除界面列表中的子项,之后再执行其它数据的处理。请问此业务该放置于Xaml.cs文件,还是ViewModel中呢?

再如弹窗,提示框,设置列表的滚动等等。

此上一些操作,我们不应该把业务代码直接挪到cs文件中,因为删除操作绝大部分的代码都是数据的处理。所以,数据的部分放置在ViewModel中,一些交互放在cs文件中,就是很合理及有必要了。

单元测试,UI与交互的那部分mock模拟有点难度,也没必要去模拟。那么,我们是应该把数据与交互拆开,减少之间的耦合性。这样添加单元测试则更容易。

交互与数据分离 - 描述

首先MVVM,通过View与ViewModel的绑定,我们实现了UI与业务逻辑的分离。通俗一点,我们熟悉的Xaml与ViewModel文件中,代码之间的隔离。在此不详述~

而MVVM,不只是界面与逻辑,其实逻辑还可以拆分成交互与数据

即:Xaml 》Xaml.cs 》ViewModel

WPF MVVM  UI分离之《交互与数据分离》

是的,按照上面的结构图,我们分成三部分:

  • 界面 用于界面呈现 ---- 如页面/控件/样式/模板等其它资源的初始化,动画的触发等。
  • 交互 用于与用户确认的交互或者界面复杂逻辑的处理 ---- 如弹窗/提示框/复杂动画的处理/设置列表的滚动等其它界面元素的视觉处理。
  • 数据 只是数据的处理 ---- 增删改查导入导出保存等只针对数据的操作,界面状态属性的保存与触发更改(绑定)。

交互与数据分离是怎样的?比如删除:

1. 界面删除按钮,绑定ViewModel中的DeleteCommand,当我们点击删除时,触发DeleteCommand.Execute

2. ViewModel中,先执行数据状态的判断,然后执行交互通知ShowDeleteWaringAction,调用xaml.cs文件中的确认提示框

3. 在Xaml.cs中添加依赖属性ShowDeleteWaring,绑定ViewModel中的ShowDeleteWaringAction.Progress。在属性更改中,处理提示框确认逻辑。

4. ViewModel中,等待ShowDeleteWaring弹框完成后,继续执行下面的业务。

5. 还有类似上面步骤的删除动画。。。

 

交互与数据分离 - 实现

使用场景:在WPF框架下开发时,一种基于MVVM的UI分离方案

解决方案:在业务逻辑处理过程中,新建一个交互处理线程,通知界面完成交互处理,同时后台逻辑保持同步等待。界面完成交互处理后,回调并执行后续的业务逻辑。

实现方案:

  • View中的依赖属性DependencyProperty,绑定ViewModel中属性“UIDelegateOperation”中的交互处理进度“UIDelegateProress”
  • 每次在ViewModel执行业务逻辑需要调用交互处理时,由UIDelegateOperation创建一个新的交互进度“UIDelegateProress”,触发属性变更,并设置“UIDelegateOperation”同步等待。
  • 当View中的属性变更事件执行完成后,回调并唤醒”UIDelegateOperation“,继续完成后面的业务逻辑。

1. 界面

在Xaml中添加附加属性,删除动画DeleteCoursewaresAnimation,删除确认框ShowDeleteWaring。并绑定ViewModel中对应的属性

1 <UserControl.Style>
2  <Style TargetType="editing:CloudListView">
3      <Setter Property="DeleteCoursewaresAnimation" Value="{Binding DeleteCoursewaresAnimation.DelegateProgress}" />
4      <Setter Property="ShowDeleteWaringShow" Value="{Binding ShowDeleteWaring.DelegateProgress}" />
5  </Style>
6 </UserControl.Style>

界面ListBox,列表子项ListBoxItemr的DataTemplate模板中,删除按钮绑定ViewModel中的DeleteCommand

1 <Button x:Name="DeleteButton" 
2         Command="{Binding ElementName=TheCloudDocsList,Path=DataContext.DeleteCommand}"
3         CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent},Path=DataContext }"
4         Content="删除" Style="{StaticResource Style.Button}" />

 2. ViewModel

ViewModel调用UIDelegateOperation交互处理时,根据是否需要同步等待,调用不同的函数 Start(),StartAsync(),StartWithResult(),StartWithResultAsync();

删除业务中,除了数据处理,还有俩个交互(删除确认框,删除元素动画)。

通过在同步调用删除确认框/删除元素动画后,再继续往下执行业务。

属性和字段字义:

定义命令

自定义命令,可以详细之前写的博客:

 1 private DelegateCommand<CoursewareListItem> _deleteCommand = null;
 2 /// <summary>
 3 /// 删除
 4 /// </summary>
 5 public DelegateCommand<CoursewareListItem> DeleteCommand
 6 {
 7     get
 8     {
 9         if (_deleteCommand == null)
10         {
11             _deleteCommand = new DelegateCommand<CoursewareListItem>(DeleteCourseware_OnExecute);
12 
13         }
14         return _deleteCommand;
15     } 
16 }

提示框确认交互/删除动画交互

1 /// <summary>
2 /// 弹出删除确认窗口 
3 /// </summary>
4 public IUIDelegateOperation<List<CoursewareListItem>, MessageResult> ShowDeleteWaring { get; set; } = new IUIDelegateOperation<List<CoursewareListItem>, MessageResult>();
5 
6 /// <summary>
7 /// 删除动画 
8 /// </summary>
9 public IUIDelegateOperation<List<CoursewareListItem>> DeleteCoursewaresAnimation { get; set; } = new IUIDelegateOperation<List<CoursewareListItem>>();

删除逻辑:

 1 /// <summary>
 2 /// 删除
 3 /// </summary>
 4 /// <param name="item"></param>
 5 /// <returns></returns>
 6 private async void DeleteCourseware_OnExecute(CoursewareListItem item)
 7 {
 8     await DeleteCoursewares(new List<CoursewareListItem>() { item });
 9 }
10 private async Task DeleteCoursewares(List<CoursewareListItem> items)
11 {
12     if (items.Count == 0)
13     {
14         return;
15     }
16 
17     //弹出删除确认窗口
18     var messageResult = await ShowDeleteWaringShow.ExecuteWithResultAsync(items);
19     if (messageResult == MessageResult.Positive)
20     {
21         //删除服务器数据 
22         Response deleteResponse = await WebService.DeleteItemAsync(items);
23 
24         //删除失败
25         if (!deleteResponse.Success)
26         {
27             Notification.ShowInfo(deleteResponse.Message);
28             return;
29         }
30         //删除动画
31         await DeleteCoursewaresAnimation.ExecuteAsync(items);
32         
33         //界面删除子项
34         items.ForEach(item => ItemsSource.Remove(item));
35 
36         //退出编辑模式
37         if (DocListState == EditStatus.Editing)
38         {
39             DocListState = EditStatus.Normal;
40         }
41     }
42 }

 

3. Xaml.cs后台

  • 添加依赖属性后,通过属性变更触发,来完成弹出提示框/删除动画等交互。
  • 执行交互时,需要同步等待时,应将动画执行等转化为同步逻辑。

添加依赖属性 - 删除窗口

属性变更触发方法,应该是一个异步方法,里面的逻辑应该为同步执行。这样ViewModel中才能同步等待交互的完成,并执行之后的逻辑。

 1 /// <summary>
 2 /// 删除窗口
 3 /// </summary>
 4 public static readonly DependencyProperty ShowDeleteWaringShowProperty = DependencyProperty.Register(
 5     "ShowDeleteWaringShow", typeof(UIDelegateProgress<List<CoursewareListItem>, MessageResult>), typeof(CloudListView), new PropertyMetadata(default(UIDelegateProgress<List<CoursewareListItem>, MessageResult>),
 6         (d, e) => ((UIDelegateProgress<List<CoursewareListItem>, MessageResult>)e.NewValue)?.StartAsync(((CloudListView)d).ShowDeleteWaringShow)));
 7 
 8 private async Task<MessageResult> ShowDeleteWaringShow(List<CoursewareListItem> items)
 9 {
10     var cmd = await DeleteWaringShow(items);
11     return cmd.Result;
12 }
13 
14 public static void SetShowDeleteWaringShow(DependencyObject element, UIDelegateProgress<List<CoursewareListItem>, MessageResult> value)
15 {
16     element.SetValue(ShowDeleteWaringShowProperty, value);
17 }
18 
19 public static UIDelegateProgress<List<CoursewareListItem>, MessageResult> GetShowDeleteWaringShow(DependencyObject element)
20 {
21     return (UIDelegateProgress<List<CoursewareListItem>, MessageResult>)element.GetValue(ShowDeleteWaringShowProperty);
22 }

添加依赖属性 - 删除动画

 1 public static readonly DependencyProperty DeleteCoursewaresAnimationProperty = DependencyProperty.Register(
 2     "DeleteCoursewaresAnimation", typeof(UIDelegateProgress<List<CoursewareListItem>>), typeof(CloudListView), new PropertyMetadata(default(UIDelegateProgress<List<CoursewareListItem>>),
 3         (d, e) => ((UIDelegateProgress<List<CoursewareListItem>>)e.NewValue)?.StartAsync(((CloudListView)d).ExecuteDeleteCoursewaresAnimation)));
 4 
 5 private async Task ExecuteDeleteCoursewaresAnimation(List<CoursewareListItem> coursewares)
 6 {
 7     List<Storyboard> storyboards = new List<Storyboard>();
 8     foreach (var courseware in coursewares)
 9     {
10         var listBoxItem = DocumentsControl.ItemContainerGenerator.ContainerFromItem(courseware) as ListBoxItem;
11         var border = listBoxItem?.VisualDescendant<Border>();
12         var storyboard = (Storyboard)border?.Resources["ItemRemovedStoryboard"];
13         if (storyboard == null)
14         {
15             //如果找不到storyBoard,则中断动画的执行。因为删除多个Item,只执行一半的动画,界面会闪现俩次。
16             return;
17         }
18         storyboards.Add(storyboard);
19     }
20     //删除界面课件
21     await AsynchronousTransferHelper.ExecuteStoryboradAsync(storyboards);
22 }
23 
24 public static void SetDeleteCoursewaresAnimation(DependencyObject element, UIDelegateProgress<List<CoursewareListItem>> value)
25 {
26     element.SetValue(DeleteCoursewaresAnimationProperty, value);
27 }
28 
29 public static UIDelegateProgress<List<CoursewareListItem>> GetDeleteCoursewaresAnimation(DependencyObject element)
30 {
31     return (UIDelegateProgress<List<CoursewareListItem>>)element.GetValue(DeleteCoursewaresAnimationProperty);
32 }

动画的执行,怎么转为有同步等待呢?动画完成只有通过触发事件Completed才能确定。

如何将动画转化为同步,可参考之前写的博客:

 1 /// <summary>
 2 /// 执行动画
 3 /// </summary>
 4 /// <param name="storyboard"></param>
 5 /// <returns></returns>
 6 public static async Task ExecuteStoryboradAsync([NotNull] Storyboard storyboard)
 7 {
 8     if (storyboard == null) throw new ArgumentNullException(nameof(storyboard));
 9 
10     AutoResetEvent autoResetEvent = new AutoResetEvent(false);
11 
12     storyboard.Completed += OnStoryboardCompleted;
13     storyboard.Begin();
14 
15     void OnStoryboardCompleted(object sender, EventArgs e)
16     {
17         storyboard.Completed -= OnStoryboardCompleted;
18         autoResetEvent.Set();
19     }
20 
21     await Task.Run(() => { autoResetEvent.WaitOne(); });
22 }

4. 交互处理辅助类 UIDelegateOperation 

在UIDelegateOperation内部,每次调用时,都会新建一个UIDelegateProgress(委托进度)。委托进度,是界面交互的处理~

UIDelegateOperation:

WPF MVVM  UI分离之《交互与数据分离》
  1 /// <summary>
  2     /// UI交互处理-提供可调用UI交互的操作
  3     /// </summary>
  4     public class UIDelegateOperation : BindableObject, IUIDelegateAction
  5     {
  6         private UIDelegateProgress _delegateProgress;
  7 
  8         public UIDelegateProgress DelegateProgress
  9         {
 10             get => _delegateProgress;
 11             private set
 12             {
 13                 _delegateProgress = value;
 14                 OnPropertyChanged();
 15             }
 16         }
 17 
 18         /// <summary>
 19         /// 执行
 20         /// </summary>
 21         public void Execute()
 22         {
 23             var delegateProgress = new UIDelegateProgress();
 24             delegateProgress.ProgressCompleted += () =>
 25             {
 26                 _delegateProgress = null;
 27             };
 28             DelegateProgress = delegateProgress;
 29         }
 30 
 31         /// <summary>
 32         /// 异步执行
 33         /// 交互处理完成并回调
 34         /// </summary>
 35         public async Task ExecuteAsync()
 36         {
 37             AutoResetEvent autoResetEvent = new AutoResetEvent(false);
 38 
 39             var delegateProgress = new UIDelegateProgress();
 40             delegateProgress.ProgressCompleted += () =>
 41             {
 42                 _delegateProgress = null;
 43 
 44                 autoResetEvent.Set();
 45             };
 46             DelegateProgress = delegateProgress;
 47             await Task.Run(() => { autoResetEvent.WaitOne(); });
 48         }
 49     }
 50 
 51     /// <summary>
 52     /// UI交互处理-提供可同步调用UI交互的操作
 53     /// </summary>
 54     /// <typeparam name="T">输入/输出类型</typeparam>
 55     public class UIDelegateAction<T> : BindableObject, IUIDelegateAction<T>
 56     {
 57         private UIDelegateProgress<T> _delegateProgress;
 58 
 59         public UIDelegateProgress<T> DelegateProgress
 60         {
 61             get => _delegateProgress;
 62             private set
 63             {
 64                 _delegateProgress = value;
 65                 OnPropertyChanged();
 66             }
 67         }
 68         /// <summary>
 69         /// 执行
 70         /// </summary>
 71         public void Execute(T parameter)
 72         {
 73             var delegateProgress = new UIDelegateProgress<T>(parameter);
 74             delegateProgress.ProgressCompleted += () =>
 75             {
 76                 _delegateProgress = null;
 77             };
 78             DelegateProgress = delegateProgress;
 79         }
 80         /// <summary>
 81         /// 异步执行
 82         /// 交互处理完成并回调
 83         /// </summary>
 84         public async Task ExecuteAsync(T parameter)
 85         {
 86             AutoResetEvent autoResetEvent = new AutoResetEvent(false);
 87 
 88             var delegateProgress = new UIDelegateProgress<T>(parameter);
 89             delegateProgress.ProgressCompleted += () =>
 90             {
 91                 _delegateProgress = null;
 92 
 93                 autoResetEvent.Set();
 94             };
 95             DelegateProgress = delegateProgress;
 96 
 97             await Task.Run(() => { autoResetEvent.WaitOne(); });
 98         }
 99 
100         /// <summary>
101         /// 异步执行并返回结果
102         /// </summary>
103         public async Task<T> ExecuteWithResultAsync()
104         {
105             AutoResetEvent autoResetEvent = new AutoResetEvent(false);
106 
107             var delegateProgress = new UIDelegateProgress<T>();
108             delegateProgress.ProgressCompleted += () =>
109             {
110                 _delegateProgress = null;
111 
112                 autoResetEvent.Set();
113             };
114             DelegateProgress = delegateProgress;
115 
116             await Task.Run(() => { autoResetEvent.WaitOne(); });
117 
118             return delegateProgress.Result;
119         }
120     }
121 
122     /// <summary>
123     /// UI交互处理-提供可同步调用UI交互的操作
124     /// </summary>
125     /// <typeparam name="TInput">输入类型</typeparam>
126     /// <typeparam name="TOut">输出类型</typeparam>
127     public class UIDelegateAction<TInput, TOut> : BindableObject, IUIDelegateAction<TInput, TOut>
128     {
129         private UIDelegateProgress<TInput, TOut> _delegateProgress;
130 
131         public UIDelegateProgress<TInput, TOut> DelegateProgress
132         {
133             get => _delegateProgress;
134             private set
135             {
136                 _delegateProgress = value;
137                 OnPropertyChanged();
138             }
139         }
140         /// <summary>
141         /// 执行
142         /// </summary>
143         public void Execute(TInput parameter)
144         {
145             var delegateProgress = new UIDelegateProgress<TInput, TOut>(parameter);
146             delegateProgress.ProgressCompleted += () =>
147             {
148                 _delegateProgress = null;
149             };
150             DelegateProgress = delegateProgress;
151         }
152 
153         /// <summary>
154         /// 执行并返回结果
155         /// </summary>
156         public TOut ExecuteWithResult(TInput parameter)
157         {
158             var delegateProgress = new UIDelegateProgress<TInput, TOut>(parameter);
159             delegateProgress.ProgressCompleted += () =>
160             {
161                 _delegateProgress = null;
162             };
163             DelegateProgress = delegateProgress;
164             return delegateProgress.Result;
165         }
166 
167         /// <summary>
168         /// 异步执行并返回结果
169         /// </summary>
170         public async Task<TOut> ExecuteWithResultAsync(TInput parameter)
171         {
172             var delegateProgress = new UIDelegateProgress<TInput, TOut>(parameter);
173             await SetDelegateProgress(delegateProgress);
174             return delegateProgress.Result;
175         }
176         private async Task SetDelegateProgress(UIDelegateProgress<TInput, TOut> delegateProgress)
177         {
178             AutoResetEvent autoResetEvent = new AutoResetEvent(false);
179 
180             delegateProgress.ProgressCompleted += () =>
181             {
182                 _delegateProgress = null;
183                 autoResetEvent.Set();
184             };
185             DelegateProgress = delegateProgress;
186             await Task.Run(() => { autoResetEvent.WaitOne(); });
187         }
188     }
189 
190     /// <summary>
191     /// UI交互处理接口
192     /// </summary>
193     public interface IUIDelegateAction
194     {
195 
196         UIDelegateProgress DelegateProgress { get; }
197 
198         /// <summary>
199         /// 执行
200         /// </summary>
201         void Execute();
202 
203         /// <summary>
204         /// 异步执行
205         /// </summary>
206         Task ExecuteAsync();
207     }
208 
209     /// <summary>
210     /// UI交互处理接口
211     /// </summary>
212     /// <typeparam name="T">输入/输出类型</typeparam>
213     public interface IUIDelegateAction<T>
214     {
215         UIDelegateProgress<T> DelegateProgress { get; }
216 
217         /// <summary>
218         /// 执行
219         /// </summary>
220         void Execute(T parameter);
221 
222         /// <summary>
223         /// 异步执行
224         /// </summary>
225         Task ExecuteAsync(T parameter);
226 
227         /// <summary>
228         /// 异步执行并返回结果
229         /// </summary>
230         Task<T> ExecuteWithResultAsync();
231     }
232 
233     /// <summary>
234     /// UI交互处理接口
235     /// </summary>
236     /// <typeparam name="TInput">输入类型</typeparam>
237     /// <typeparam name="TOut">输出类型</typeparam>
238     public interface IUIDelegateAction<TInput, TOut>
239     {
240         UIDelegateProgress<TInput, TOut> DelegateProgress { get; }
241 
242         /// <summary>
243         /// 执行
244         /// </summary>
245         void Execute(TInput parameter);
246 
247         /// <summary>
248         /// 执行并返回结果
249         /// </summary>
250         TOut ExecuteWithResult(TInput parameter);
251 
252         /// <summary>
253         /// 异步执行并返回结果
254         /// </summary>
255         Task<TOut> ExecuteWithResultAsync(TInput parameter);
256     }
View Code

UIDelegateProgress:

WPF MVVM  UI分离之《交互与数据分离》
  1     /// <summary>
  2     /// 委托进度
  3     /// </summary>
  4     public class UIDelegateProgress
  5     {
  6         public event Action ProgressCompleted;
  7 
  8         /// <summary>
  9         /// UI委托处理
 10         /// </summary>
 11         /// <param name="uiTask"></param>
 12         public async void StartAsync(Func<Task> uiTask)
 13         {
 14             try
 15             {
 16                 await uiTask.Invoke();
 17             }
 18             catch (InvalidOperationException e)
 19             {
 20                 Log.Error("UI交互处理,产生异常!", e);
 21             }
 22             finally
 23             {
 24                 ProgressCompleted?.Invoke();
 25             }
 26         }
 27 
 28         /// <summary>
 29         /// UI委托处理
 30         /// </summary>
 31         /// <param name="uiTask"></param>
 32         public void Start(Action uiTask)
 33         {
 34             try
 35             {
 36                 uiTask.Invoke();
 37             }
 38             catch (InvalidOperationException e)
 39             {
 40                 Log.Error("UI交互处理,产生异常!", e);
 41             }
 42             finally
 43             {
 44                 ProgressCompleted?.Invoke();
 45             }
 46         }
 47     }
 48 
 49     /// <summary>
 50     /// 委托进度
 51     /// </summary>
 52     public class UIDelegateProgress<T>
 53     {
 54         public event Action ProgressCompleted;
 55 
 56         /// <summary>
 57         /// 输入参数
 58         /// </summary>
 59         public T Parameter { get; set; }
 60 
 61         /// <summary>
 62         /// 输出参数
 63         /// </summary>
 64         public T Result { get; set; }
 65 
 66         public UIDelegateProgress()
 67         {
 68 
 69         }
 70         public UIDelegateProgress(T parameter)
 71         {
 72             Parameter = parameter;
 73         }
 74 
 75         /// <summary>
 76         /// UI委托处理
 77         /// </summary>
 78         /// <param name="uiTask"></param>
 79         public void Start(Action<T> uiTask)
 80         {
 81             try
 82             {
 83                 uiTask.Invoke(Parameter);
 84             }
 85             catch (InvalidOperationException e)
 86             {
 87                 Log.Error("UI交互处理,产生异常!", e);
 88             }
 89             finally
 90             {
 91                 ProgressCompleted?.Invoke();
 92             }
 93         }
 94 
 95         /// <summary>
 96         /// UI委托处理
 97         /// </summary>
 98         /// <param name="uiTask"></param>
 99         public async void StartAsync(Func<T, Task> uiTask)
100         {
101             try
102             {
103                 await uiTask.Invoke(Parameter);
104             }
105             catch (InvalidOperationException e)
106             {
107                 Log.Error("UI交互处理,产生异常!", e);
108             }
109             finally
110             {
111                 ProgressCompleted?.Invoke();
112             }
113         }
114 
115         /// <summary>
116         /// UI委托处理
117         /// </summary>
118         /// <param name="uiTask"></param>
119         public void Start(Func<T> uiTask)
120         {
121             try
122             {
123                 Result = uiTask.Invoke();
124             }
125             catch (InvalidOperationException e)
126             {
127                 Log.Error("UI交互处理,产生异常!", e);
128             }
129             finally
130             {
131                 ProgressCompleted?.Invoke();
132             }
133         }
134 
135         /// <summary>
136         /// UI委托处理
137         /// </summary>
138         /// <param name="uiTask"></param>
139         public async void StartAsync(Func<Task<T>> uiTask)
140         {
141             try
142             {
143                 Result = await uiTask.Invoke();
144             }
145             catch (InvalidOperationException e)
146             {
147                 Log.Error("UI交互处理,产生异常!", e);
148             }
149             finally
150             {
151                 ProgressCompleted?.Invoke();
152             }
153         }
154     }
155 
156     /// <summary>
157     /// 委托进度
158     /// </summary>
159     public class UIDelegateProgress<TInput, TOut>
160     {
161         public event Action ProgressCompleted;
162 
163         /// <summary>
164         /// 输入参数
165         /// </summary>
166         public TInput Parameter { get; set; }
167 
168         /// <summary>
169         /// 输出参数
170         /// </summary>
171         public TOut Result { get; set; }
172 
173         public UIDelegateProgress(TInput parameter)
174         {
175             Parameter = parameter;
176         }
177 
178         /// <summary>
179         /// UI委托处理
180         /// </summary>
181         /// <param name="uiTask"></param>
182         public async void StartAsync(Func<TInput, Task<TOut>> uiTask)
183         {
184             try
185             {
186                 Result = await uiTask.Invoke(Parameter);
187             }
188             catch (InvalidOperationException e)
189             {
190                 Log.Error("UI交互处理,产生异常!", e);
191             }
192             finally
193             {
194                 ProgressCompleted?.Invoke();
195             }
196         }
197 
198         /// <summary>
199         /// UI委托处理
200         /// </summary>
201         /// <param name="uiTask"></param>
202         public void Start(Func<TOut> uiTask)
203         {
204             try
205             {
206                 uiTask.Invoke();
207             }
208             catch (InvalidOperationException e)
209             {
210                 Log.Error("UI交互处理,产生异常!", e);
211             }
212             finally
213             {
214                 ProgressCompleted?.Invoke();
215             }
216         }
217 
218         /// <summary>
219         /// UI委托处理
220         /// </summary>
221         /// <param name="uiTask"></param>
222         public void Start(Func<TInput, TOut> uiTask)
223         {
224             try
225             {
226                 Result = uiTask.Invoke(Parameter);
227             }
228             catch (InvalidOperationException e)
229             {
230                 Log.Error("UI交互处理,产生异常!", e);
231             }
232             finally
233             {
234                 ProgressCompleted?.Invoke();
235             }
236         }
237     }
View Code

 

Demo中,举例了界面的删除操作

 

InvokeCommandAction

通过InvokeCommandAction 的使用,WPF任意事件都可以绑定Command,将业务逻辑放在ViewModel中。如:

1 <TextBlock>
2     <i:Interaction.Triggers>
3         <i:EventTrigger EventName="MouseLeftButtonDown">
4             <i:InvokeCommandAction Command="{Binding MouseLeftButtonDownCommand}"/>
5         </i:EventTrigger>
6     </i:Interaction.Triggers>
7 </TextBlock>

 

 

关键字:UI分离,交互与数据分离,动画同步,单元测试