WPF MVVM UI分离之《交互与数据分离》 基础才是重中之重~delegate里的Invoke和BeginInvoke 将不确定变为确定系列~目录(“机器最能证明一切”) 爱上MVC3系列~全局异常处理与异常日志 基础才是重中之重~lock和monitor的区别 将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行 将不确定变成确定~LINQ DBML模型可以对

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

 

在我们使用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分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

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

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

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

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中对应的属性

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
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>
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

界面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();

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

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

属性和字段字义:

定义命令

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

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 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 }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

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

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
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>>();
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

删除逻辑:

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 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 }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

3. Xaml.cs后台

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

添加依赖属性 - 删除窗口

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

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 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 }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

添加依赖属性 - 删除动画

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 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 }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

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

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

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 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 }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

4. 交互处理辅助类 UIDelegateOperation 

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

UIDelegateOperation:

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
  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     }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

UIDelegateProgress:

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
  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     }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

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

基础才是重中之重~delegate里的Invoke和BeginInvoke

 

回到目录

Invoke和BeginInvoke都是调用委托实体的方法,前者是同步调用,即它运行在主线程上,当Invode处理时间长时,会出现阻塞的情况,而BeginInvod是异步操作,它会从新开启一个线程,所以不会租塞主线程,在使用BeginInvoke时,如果希望等待执行的结果 ,可以使用EndInvoke来实现,这在.net framework4.5之后,被封装成了async+await来实现,代码更简洁,更容易理解。

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
        delegate void test();
        static void Main(string[] args)
        {
            test ts = new test(TestDelegate);
            ts.Invoke(); //不会产生新线程
            Console.WriteLine("hello");
        }

        internal static void TestDelegate()
        {
            Thread.Sleep(1000);
        }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

此时,在主线程中出现了1秒的租塞,因为Invoke是同步的。

下面再来看一下BeginInvoke的实现

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
        delegate string test();
        static void Main(string[] args)
        {
            test ts = new test(TestDelegate);
           IAsyncResult result = ts.BeginInvoke(null,null); //会在新线程中执行
            string resultstr=ts.EndInvoke(result);
            Console.WriteLine(resultstr);
        }

        internal static string TestDelegate()
        {
            Thread.Sleep(1000);
            return "hello"
        }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

上面的代码会在新线程中执行,并且平会对主线程产生租塞,同时它可以获取自己的返回值,使用EndInvoke实现!

感谢阅读!小小的知识点我们也要好好理解。

将不确定变为确定系列~目录(“机器最能证明一切”)

 

回到占占推荐博客索引

本系列文章主要是我在工作中,遇到一些不能主观判断的问题,最后在电脑上去证明我的理解是否正确,这也是题目“将不确定变成确定”的由来。

记得我在上大学时,老师说过一句话:“机器最能证明一切”,这句话现在看来,确实很经典。

将不确定变为确定系列~目录(“机器最能证明一切”)

第一回 将不确定变成确定~类中的override

第二回 将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行

第三回 将不确定变成确定~frameset页面不能正确加载

第四回 将不确定变成确定~LINQ查询两种写法,性能没有影响,优化查询应该是“按需查询”

第五回 将不确定变成确定~LINQ DBML模型可以对应多个数据库吗

第六回   将不确定变为确定~程序是否真的Dispose了

第七回 将不确定变为确定~一切归总为“二”(C#中的位运算有啥用)

第八回 将不确定变为确定~接口应该是什么

第九回 将不确定变为确定~表达式树是否可以有个集合,条件过滤有了新方向

第十回 将不确定变为确定~表达式树是否可以有个集合,条件过滤有了新方向续(新增了OR和AND查询)

第十一回 将不确定变为确定~整形变量是否可以进行位运算(像枚举类型一样)

第十二回 将不确定变为确定~static被翻译成静态,你是否赞同

第十三回 将不确定变为确实~请自己搞清楚异常页面的设置方法(网上那些资料说的基本都有问题!)

第十四回 基础才是重中之重~老赵写的CodeTimer是代码性能测试的利器

第十五回 将不确定变为确定~LINQ查询包含对不同数据上下文上所定义项的引用

第十六回 将不确定变为确定~真的是SqlDataReader引起的超时?

第十七回 将不确定变为确定~SQLSERVER是否可以进行位运算?

第十八回  将不确定变为确定~从DBML文件中是否可以快速定位到指定类?

第十九回  将不确定变为确定~头压缩是否有必要,MVC如何实现头压缩

第二十回  将不确定变为确定~Linq-Distinct()方法是否可以对复杂结果集进行去重?

第二十一回 将不确定变为确定系列~Linq的批量操作靠的住吗?

第二十二回 将不确定变为确定~MVC3的ValidateInput属性失灵了

第二十三回   将不确定变为确定~异常被抛出的顺序

第二十四回   将不确定变为确定~对象被new后什么时候会抛System.NullReferenceException

第二十五回   将不确定变为确定~Linq to SQL不能随机排序吗?

第二十六回   将不确定变为确定~transactionscope何时提升为分布式事务?

第二十七回   将不确定变为确定~transactionscope何时提升为分布式事务~续

第二十八回   将不确定变为确定~transactionscope何时提升为分布式事务~再续(避免引起不必要的MSDTC)

第二十九回   将不确定变为确定~transactionscope何时提升为分布式事务~大结局

第三十回      将不确定变为确定~Flag特性的枚举是否可以得到Description信息

第三十一回 将不确定变为确定~Razor视图中是否可以嵌套JS代码

第三十二回 将不确定变为确定~DateTime.MinValue和MaxValue引发的异常

第三十四回 将不确定变为确定~Linq的Group是否可以根据多个字段进行分组

第三十五回   将不确定变为确定~感谢异或,是你让我彻底摆脱“否定式”

第三十六回   将不确定变为确定~类中的属性何时被执行

第三十七回   将不确定变为确定~transactionscope何时提升为分布式事务~SQL2005与SQL2008不同

第三十八回   将不确定变为确定~transactionscope何时提升为分布式事务?(sql2005数据库解决提升到MSDTC的办法)

第三十九回   将不确定变成确定~Uri文本文件不用浏览器自动打开,而是下载到本地

第四十回      基础才是重中之重~lock和monitor的区别

爱上MVC3系列~全局异常处理与异常日志

 

回到目录

在MVC3网站的global.asax中的Application_Start方法里,有这样一段代码 

1   RegisterGlobalFilters(GlobalFilters.Filters);

它的主要使用是将全局过滤器进行注册,而全局过滤器可以在RegisterGlobalFilters这个方法里进行设置,如代码:

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 1    /// <summary>
 2         /// 全局过滤器(特性)
 3         /// </summary>
 4         /// <param name="filters"></param>
 5         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 6         {
 7             // ExceptionLogAttribute继承自HandleError,主要作用是将异常信息写入日志系统中
 8             filters.Add(new Web.Commons.Attributes.ExceptionLogAttribute());
 9             //默认的异常记录类
10             filters.Add(new HandleErrorAttribute());
11         }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

当我们设置完上面两块后,现在如果想记异常日志,那我们需要完善一下ExceptionLogAttribute这个类,看代码:

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 1    /// <summary>
 2     /// 异常持久化类
 3     /// </summary>
 4     public class ExceptionLogAttribute : HandleErrorAttribute
 5     {
 6         /// <summary>
 7         /// 触发异常时调用的方法
 8         /// </summary>
 9         /// <param name="filterContext"></param>
10         public override void OnException(ExceptionContext filterContext)
11         {
12
13             string message = string.Format("消息类型:{0}<br>消息内容:{1}<br>引发异常的方法:{2}<br>引发异常的对象:{3}<br>异常目录:{4}<br>异常文件:{5}"
14                 , filterContext.Exception.GetType().Name
15                 , filterContext.Exception.Message
16                 , filterContext.Exception.TargetSite
17                 , filterContext.Exception.Source
18                 , filterContext.RouteData.GetRequiredString("controller")
19                 , filterContext.RouteData.GetRequiredString("action"));
20             VLog.VLogFactory.CreateVLog().ErrorLog(message); //TODO:将 ex 错误对象记录到系统日志模块
21             base.OnException(filterContext);
22         }
23     }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

大家可以看到,在上面类中,有个CreateVLog的方法,它是干什么用的呢,实事上,它就是我们的日志功能类,可以对日志进行不同类型的持久化,这我会在单独一讲中去说明它。

今天主要就是MVC3中的全局异常的记录方法,呵呵。

基础才是重中之重~lock和monitor的区别

 

回到目录

Monitor的介绍

1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取锁之后因为异常,致锁无法释放,所以需要在try{} catch(){}之后的finally{}结构体中释放锁(Monitor.Exit())。

2.Monitor的常用属性和方法:

  1. Enter(Object) 在指定对象上获取排他锁。
  2. Exit(Object) 释放指定对象上的排他锁。
  3. IsEntered 确定当前线程是否保留指定对象锁。
  4. Pulse 通知等待队列中的线程锁定对象状态的更改。
  5. PulseAll 通知所有的等待线程对象状态的更改。
  6. TryEnter(Object) 试图获取指定对象的排他锁。
  7. TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否得到了该锁。
  8. Wait(Object) 释放对象上的锁并阻止当前线程,直到它重新获取该锁。

Lock的介绍 

 1.Lock关键字实际上是一个语法糖,它将Monitor对象进行封装,给object加上一个互斥锁,A进程进入此代码段时,会给object对象加上互斥锁,此时其他B进程进入此代码段时检查object对象是否有锁?如果有锁则继续等待A进程运行完该代码段并且解锁object对象之后,B进程才能够获取object对象为其加上锁,访问代码段。

 2.Lock关键字封装的Monitor对象结构如下:

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
            try
            {
                Monitor.Enter(obj);
                dosomething();
            }
            catch(Exception ex)
            {

            }
            finally
            {
                Monitor.Exit(obj);
            }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

3. lock的对象应该是私有的静态对象

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
        private static object obj = new object();
        public void something()
        {
            lock (obj)
            {
                dosomething();
            }
        }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

Monitor和Lock的区别

  1.Lock是Monitor的语法糖。

  2.Lock只能针对引用类型加锁。

  3.Monitor能够对值类型进行加锁,实质上是Monitor.Enter(object)时对值类型装箱。

感谢各位的阅读!

回到目录

将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行

 

回到目录

名称有点饶,不是很好理解,但我喜欢这种大白话,不喜欢书所翻译过来的话,呵呵!

今天要把一个不确定的问题解决,问题是:一个程序中,有一个属性,如果它为true时,我希望把另一些方法自动运行,这是可以通过订阅事件来实现的,对吗?经过我的测试确实是这样的,呵呵。

事件一个一直叫我们头痛的话题,一个能不用就不用的东西,我们程序员为什么那么怕“事件”呢?我来分析几个原因

1 对本身的概念不是很理解

2 对它的作用不是很清晰,可能书上说不到点上,个人认为

3 平时用的少,所以对它更加陌生

今天,我就和大家一起再学习一个C#的事件

一说事件,就不行不说委托,这两者到底是什么关系呢,在我看来,委托就是一个类,而事件就是这个类的一个实例,呵呵,这样大家就容易理解了吧

事件由事件数据源,事件所发生的类和事件订阅者们组成,“事件订阅者们”就是说,一个事件可以被多个订阅都订阅。

开始写代码了,代码最能说明问题:

事件源类:


WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 1  /// <summary>
 2   /// 事件源
 3   /// </summary>
 4   internal class KeyEventArgs : EventArgs
 5   {
 6       private char keyChar;
 7       public KeyEventArgs(char keyChar)
 8           : base()
 9       {
10           this.keyChar = keyChar;
11       }
12
13       public char KeyChar
14       {
15           get
16           {
17               return keyChar;
18           }
19       }
20   }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

 

一都是以EventArgs 结尾的,其中EventArgs 本身它是所有事件源类的基类,它不提供任何事件源信息,如果有个性化的事件信息,需要去派生它

接下来看,发生事件的类,我们的事件就在这里发生,在什么时候,什么情况下发生,都来自这里。

 
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 1  /// <summary>
 2     /// 事件发生的类
 3  /// </summary>
 4     internal class KeyInputMonitor
 5     {
 6         // 创建一个委托,返回类型为avoid,两个参数
 7         public delegate void KeyDownEventHandler(object sender, KeyEventArgs e);
 8         // 将创建的委托和特定事件关联,在这里特定的事件为OnKeyDown
 9         public event KeyDownEventHandler OnKeyDown;
10
11         public void Run()
12         {
13             bool finished = false;
14             do
15             {
16                 Console.WriteLine("Input a char");
17                 string response = Console.ReadLine();
18
19                 char responseChar = (response == "") ? ' ' : char.ToUpper(response[0]);
20                 switch (responseChar)
21                 {
22                     case 'X':
23                         finished = true;
24                         break;
25                     default:
26                         // 得到按键信息的参数
27                         KeyEventArgs keyEventArgs = new KeyEventArgs(responseChar);
28                         // 触发事件
29                         OnKeyDown(this, keyEventArgs);
30                         break;
31                 }
32             } while (!finished);
33         }
34     }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

功能就是输入一个字符,当为X时,退出,当不为X时,去触发一个事件,事件源数据为“输入的字符”
到这里,这个事件还没有任何功能,就相当于,我去卖东西,东西已经摆在台上了,但还没有人来买,好,现在是时候有顾客来了
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对
 1  /// <summary>
 2     /// 显示中文的接收类
 3  /// </summary>
 4     internal class EventReceiverForChina
 5     {
 6         public EventReceiverForChina(KeyInputMonitor monitor)
 7         {
 8             // 产生一个委托实例并添加到KeyInputMonitor产生的事件列表中
 9             monitor.OnKeyDown += new KeyInputMonitor.KeyDownEventHandler(this.Echo);
10         }
11         private void Echo(object sender, KeyEventArgs e)
12         {
13           Console.WriteLine("您输入的字条是: {0}", e.KeyChar);
14         }
15     }
WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

这里订阅事件时,我们使用+=就可以了,事实上就是建立一个委托类型的新事件实例而以。

在前台调用时,可以这样:

1         // 实例化一个事件发送器,并声明一个EventReceiverForChina类型的订阅者
2   KeyInputMonitor monitor = new KeyInputMonitor();
3   EventReceiverForChina eventReceiverForChina = new EventReceiverForChina(monitor);
4  monitor.Run();


运行的结果就是当你去Run()时,eventReceiverForChina 类型时的某个方法也被执行了,怎么样,实现了我们今天的话题了吧,其实这就是事件的订阅机制,事实上在软件开发中非常有用。
需要注意的是,一般事件的返回类型都是void,当然,这也是很正常的,因为事件就是去做某些事件,它不知道管后果的。呵呵。
祝您晚——来个好梦吧!回到目录

将不确定变成确定~LINQ DBML模型可以对应多个数据库吗


 

回到目录

答案是肯定的,一个DBML模型可以对应多个数据库,只要数据库中的表与模型中定义的表结构完成相同,就可以这个技术,我们可以用来开发一些通用的功能模块,如通过后台管理模块,我们将一些通用表进行抽象,如,对用户,角色,部门,菜单等进行抽象,将它的模块建立在我们的公用项目中,然后对这个模型进行操作,在建立DBContext上下文时,我们需要保留一个连接字符串,即,真正的项目中用哪个库,我们这个串就指定哪个库就行了。

如图,后台表结构

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

然后,它个模块可以用别对应包含这几个表结构的数据库,呵呵

通用后台系统我会在之后的文章中给大家讲到,今天先看一下它的图像,呵呵

WPF MVVM UI分离之《交互与数据分离》  基础才是重中之重~delegate里的Invoke和BeginInvoke  将不确定变为确定系列~目录(“机器最能证明一切”)  爱上MVC3系列~全局异常处理与异常日志  基础才是重中之重~lock和monitor的区别  将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行  将不确定变成确定~LINQ DBML模型可以对

大家可以看到,对于每一个项目的功能和作用,今天我就不说了,我会再下一篇文章中单独说它,总之,今天要知识的就是:一个DBML可以对应多个数据库,前提是数据库的表结构好和DBML模型中存在的表结构相同。

回到目录


上一篇:基于Vue的Ui框架


下一篇:WCF/WPF公司内部订餐程序开发