PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/ShanghaiFilmCenters-R1.2/packages/MVVM-Sidekick.1.2.0.0/src/CodeFiles/Reactive.cs

https://github.com/lulee007/WP-ShanghaiFilmCenters
C# | 406 lines | 290 code | 73 blank | 43 comment | 2 complexity | 4c213c5d45ef75556a2c02df00affe89 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel;
  6. using System.Linq.Expressions;
  7. using System.Runtime.Serialization;
  8. using System.Reflection;
  9. using System.Threading.Tasks;
  10. using System.Threading;
  11. using System.Windows.Input;
  12. using MVVMSidekick.ViewModels;
  13. using MVVMSidekick.Commands;
  14. using System.Runtime.CompilerServices;
  15. using MVVMSidekick.Reactive;
  16. using System.Reactive.Linq;
  17. using System.Reactive.Subjects;
  18. using System.Reactive;
  19. using System.Reactive.Threading.Tasks;
  20. using MVVMSidekick.EventRouting;
  21. using System.Collections.ObjectModel;
  22. using System.Collections.Specialized;
  23. using System.IO;
  24. using System.Collections;
  25. using MVVMSidekick.Utilities;
  26. #if NETFX_CORE
  27. using Windows.UI.Xaml;
  28. using Windows.UI.Xaml.Data;
  29. using Windows.UI.Xaml.Controls;
  30. using System.Collections.Concurrent;
  31. using Windows.UI.Xaml.Navigation;
  32. using Windows.UI.Xaml.Controls.Primitives;
  33. #elif WPF
  34. using System.Windows;
  35. using System.Windows.Controls;
  36. using System.Windows.Data;
  37. using System.Collections.Concurrent;
  38. using System.Windows.Navigation;
  39. using MVVMSidekick.Views;
  40. using System.Windows.Controls.Primitives;
  41. using MVVMSidekick.Utilities;
  42. #elif SILVERLIGHT_5||SILVERLIGHT_4
  43. using System.Windows;
  44. using System.Windows.Controls;
  45. using System.Windows.Data;
  46. using System.Windows.Navigation;
  47. using System.Windows.Controls.Primitives;
  48. #elif WINDOWS_PHONE_8||WINDOWS_PHONE_7
  49. using System.Windows;
  50. using System.Windows.Controls;
  51. using Microsoft.Phone.Controls;
  52. using System.Windows.Data;
  53. using System.Windows.Navigation;
  54. using System.Windows.Controls.Primitives;
  55. #endif
  56. namespace MVVMSidekick
  57. {
  58. namespace Reactive
  59. {
  60. public static class EventTuple
  61. {
  62. public static EventTuple<TSource, TEventArgs> Create<TSource, TEventArgs>(TSource source, TEventArgs eventArgs)
  63. {
  64. return new EventTuple<TSource, TEventArgs> { Source = source, EventArgs = eventArgs };
  65. }
  66. }
  67. public struct EventTuple<TSource, TEventArgs>
  68. {
  69. public TSource Source { get; set; }
  70. public TEventArgs EventArgs { get; set; }
  71. }
  72. public static class MVVMRxExtensions
  73. {
  74. //public static IDisposable SubscribeToRouter(this IObservable<Task> executionSequence, BindableBase model, string eventName, CallingCodeContext callingCodeContext)
  75. //{
  76. // EventRouting.EventRouter.Instance.GetEventObject<TaskExecutionWindowEventArg>().RaiseEvent(model, eventName, callingCodeContext);
  77. // return executionSequence.Subscribe();
  78. //}
  79. /// <summary>
  80. /// Register a Do action to the observer, Notify the value in this sequence to EventRouter
  81. /// </summary>
  82. /// <typeparam name="T">Sequence Value Type</typeparam>
  83. /// <param name="sequence">value sequence</param>
  84. /// <param name="eventRounter"> target </param>
  85. /// <param name="source">value source</param>
  86. /// <param name="registerName">log name</param>
  87. /// <returns>same value sequence inputed</returns>
  88. public static IObservable<T> DoNotifyEventRouter<T>(this IObservable<T> sequence, EventRouter eventRounter, object source = null, [CallerMemberName] string registerName = null)
  89. {
  90. return
  91. sequence.Do(
  92. v => eventRounter.RaiseEvent(source, v, registerName)
  93. );
  94. }
  95. /// <summary>
  96. /// Register a Do action to the observer, Notify the value in this sequence to EventRouter
  97. /// </summary>
  98. /// <typeparam name="T">Sequence Value Type</typeparam>
  99. /// <param name="sequence">value sequence</param>
  100. /// <param name="source">value source</param>
  101. /// <param name="registerName">log name</param>
  102. /// <returns>same value sequence inputed</returns>
  103. public static IObservable<T> DoNotifyDefaultEventRouter<T>(this IObservable<T> sequence, object source = null, [CallerMemberName] string registerName = null)
  104. {
  105. return DoNotifyEventRouter(sequence, EventRouter.Instance, source, registerName);
  106. }
  107. public static IObservable<Task<Tout>> DoExecuteUIBusyTask<Tin, Tout>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, CancellationToken, Task<Tout>> taskBody, CancellationToken cancellationToken)
  108. {
  109. return sequence.Select
  110. (
  111. inContext => vm.ExecuteTask(taskBody, inContext, cancellationToken, true)
  112. );
  113. }
  114. public static IObservable<Task<Tout>> DoExecuteUITask<Tin, Tout>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, CancellationToken, Task<Tout>> taskBody, CancellationToken cancellationToken)
  115. {
  116. return sequence.Select
  117. (
  118. inContext => vm.ExecuteTask(taskBody, inContext, cancellationToken, false)
  119. );
  120. }
  121. public static IObservable<Task> DoExecuteUIBusyTask<Tin>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, CancellationToken, Task> taskBody, CancellationToken cancellationToken)
  122. {
  123. return sequence.Select
  124. (
  125. inContext => vm.ExecuteTask(taskBody, inContext, cancellationToken, true)
  126. );
  127. }
  128. public static IObservable<Task> DoExecuteUITask<Tin>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, CancellationToken, Task> taskBody, CancellationToken cancellationToken)
  129. {
  130. return sequence.Select
  131. (
  132. inContext => vm.ExecuteTask(taskBody, inContext, cancellationToken, false)
  133. );
  134. }
  135. public static IObservable<Task<Tout>> DoExecuteUIBusyTask<Tin, Tout>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, Task<Tout>> taskBody)
  136. {
  137. return sequence.Select
  138. (
  139. inContext => vm.ExecuteTask(taskBody, inContext, true)
  140. );
  141. }
  142. public static IObservable<Task<Tout>> DoExecuteUITask<Tin, Tout>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, Task<Tout>> taskBody)
  143. {
  144. return sequence.Select
  145. (
  146. inContext => vm.ExecuteTask(taskBody, inContext, false)
  147. );
  148. }
  149. public static IObservable<Task> DoExecuteUIBusyTask<Tin>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, Task> taskBody)
  150. {
  151. return sequence.Select
  152. (
  153. inContext => vm.ExecuteTask(taskBody, inContext, true)
  154. );
  155. }
  156. public static IObservable<Task> DoExecuteUITask<Tin>(this IObservable<Tin> sequence, IViewModel vm, Func<Tin, Task> taskBody)
  157. {
  158. return sequence.Select
  159. (
  160. inContext => vm.ExecuteTask(taskBody, inContext, false)
  161. );
  162. }
  163. /// <summary>
  164. /// <para>Create a instance of IObservable that fires when property changed event is raised.</para>
  165. /// <para>创建一个监视属性变化事件观察者IObservable实例。</para>
  166. /// </summary>
  167. /// <returns></returns>
  168. public static IObservable<EventPattern<PropertyChangedEventArgs>> CreatePropertyChangedObservable(this BindableBase bindable)
  169. {
  170. return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
  171. eh => bindable.PropertyChanged += eh,
  172. eh => bindable.PropertyChanged -= eh
  173. )
  174. .Where(_ => bindable.IsNotificationActivated);
  175. }
  176. public static IObservable<EventPattern<NotifyCollectionChangedEventArgs>> GetEventObservable<T>(this ObservableCollection<T> source, BindableBase model)
  177. {
  178. var rval = Observable
  179. .FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>
  180. (
  181. ev => source.CollectionChanged += ev,
  182. ev => source.CollectionChanged -= ev
  183. ).Where(_ => model.IsNotificationActivated);
  184. return rval;
  185. }
  186. public static IObservable<EventTuple<ValueContainer<TValue>, TValue>> GetNewValueObservable<TValue>
  187. (
  188. this ValueContainer<TValue> source
  189. )
  190. {
  191. return Observable.FromEventPattern<EventHandler<ValueChangedEventArgs<TValue>>, ValueChangedEventArgs<TValue>>(
  192. eh => source.ValueChanged += eh,
  193. eh => source.ValueChanged -= eh)
  194. .Select(
  195. x => EventTuple.Create(source, x.EventArgs.NewValue)
  196. );
  197. }
  198. public static IObservable<EventTuple<ValueContainer<TValue>, ValueChangedEventArgs<TValue>>>
  199. GetEventObservable<TValue>(this ValueContainer<TValue> source)
  200. {
  201. var eventArgSeq = Observable.FromEventPattern<EventHandler<ValueChangedEventArgs<TValue>>, ValueChangedEventArgs<TValue>>(
  202. eh => source.ValueChanged += eh,
  203. eh => source.ValueChanged -= eh);
  204. return eventArgSeq.Select(
  205. x => EventTuple.Create(source, x.EventArgs)
  206. );
  207. ;
  208. }
  209. public static IObserver<TValue> AsObserver<TValue>(this ValueContainer<TValue> source)
  210. {
  211. return Observer.Create<TValue>(v => source.SetValueAndTryNotify(v));
  212. }
  213. public static IObservable<object> GetNullObservable<TValue>(this ValueContainer<TValue> source)
  214. {
  215. var eventArgSeq = Observable.FromEventPattern<EventHandler<ValueChangedEventArgs<TValue>>, ValueChangedEventArgs<TValue>>(
  216. eh => source.ValueChanged += eh,
  217. eh => source.ValueChanged -= eh);
  218. return eventArgSeq.Select(
  219. x => null as object
  220. );
  221. ;
  222. }
  223. /// <summary>
  224. /// 转化
  225. /// </summary>
  226. /// <typeparam name="TEventArgs"></typeparam>
  227. /// <param name="source"></param>
  228. /// <returns></returns>
  229. [Obsolete("The source is already IObservable<RouterEventData<TEventArgs>>")]
  230. public static IObservable<RouterEventData<TEventArgs>>
  231. GetRouterEventObservable<TEventArgs>(this MVVMSidekick.EventRouting.EventRouter.EventObject<TEventArgs> source)
  232. #if !NETFX_CORE
  233. where TEventArgs : EventArgs
  234. #endif
  235. {
  236. return source;
  237. }
  238. /// <summary>
  239. /// Bind Command to IsUIBusy property.
  240. /// </summary>
  241. /// <typeparam name="TCommand">A sub class of ReactiveCommand</typeparam>
  242. /// <typeparam name="TResource">The resource type of CommandModel</typeparam>
  243. /// <typeparam name="TViewModel">The View Model type command wanna bind to</typeparam>
  244. /// <param name="command">Command itself</param>
  245. /// <param name="model">The View Model command wanna bind to</param>
  246. /// <returns>command instance itself</returns>
  247. public static CommandModel<TCommand, TResource> ListenToIsUIBusy<TCommand, TResource, TViewModel>(this CommandModel<TCommand, TResource> command, ViewModelBase<TViewModel> model, bool canExecuteWhenBusy = false)
  248. where TViewModel : ViewModelBase<TViewModel>
  249. where TCommand : ReactiveCommand
  250. {
  251. //See Test CommandListenToUIBusy_Test
  252. model.GetValueContainer(x => x.IsUIBusy).GetNewValueObservable()
  253. .Select(e =>
  254. !(canExecuteWhenBusy ^ e.EventArgs))
  255. .Subscribe(command.CommandCore.CanExecuteObserver)
  256. .DisposeWith(model);
  257. return command;
  258. }
  259. }
  260. public class ReactiveCommand : EventCommandBase, ICommand, IObservable<EventPattern<EventCommandEventArgs>>
  261. {
  262. protected Lazy<IObservable<EventPattern<EventCommandEventArgs>>> _LazyObservableExecute;
  263. protected Lazy<IObserver<bool>> _LazyObserverCanExecute;
  264. protected bool _CurrentCanExecuteObserverValue;
  265. protected ReactiveCommand()
  266. {
  267. ConfigReactive();
  268. }
  269. public ReactiveCommand(bool canExecute = false)
  270. : this()
  271. {
  272. _CurrentCanExecuteObserverValue = canExecute;
  273. }
  274. virtual protected void ConfigReactive()
  275. {
  276. _LazyObservableExecute = new Lazy<IObservable<EventPattern<EventCommandEventArgs>>>
  277. (
  278. () =>
  279. {
  280. var ob = Observable.FromEventPattern<EventHandler<EventCommandEventArgs>, EventCommandEventArgs>
  281. (
  282. eh =>
  283. {
  284. this.CommandExecute += eh;
  285. },
  286. eh =>
  287. {
  288. this.CommandExecute -= eh;
  289. }
  290. );
  291. return ob;
  292. }
  293. );
  294. _LazyObserverCanExecute = new Lazy<IObserver<bool>>
  295. (
  296. () =>
  297. Observer.Create<bool>(
  298. canExe =>
  299. {
  300. var oldv = this._CurrentCanExecuteObserverValue;
  301. _CurrentCanExecuteObserverValue = canExe;
  302. if (oldv != canExe)
  303. {
  304. OnCanExecuteChanged();
  305. }
  306. }
  307. )
  308. );
  309. }
  310. public IObserver<bool> CanExecuteObserver { get { return _LazyObserverCanExecute.Value; } }
  311. public override bool CanExecute(object parameter)
  312. {
  313. return _CurrentCanExecuteObserverValue;
  314. }
  315. public IDisposable Subscribe(IObserver<EventPattern<EventCommandEventArgs>> observer)
  316. {
  317. return _LazyObservableExecute
  318. .Value
  319. .Subscribe(observer);
  320. }
  321. }
  322. public class TaskExecutionWindowEventArg : EventArgs
  323. {
  324. public TaskExecutionWindowEventArg(Task executedTask, CallingCodeContext callingContext)
  325. {
  326. TaskWindow = executedTask.ToObservable();
  327. CallingCodeContext = callingContext;
  328. }
  329. public IObservable<Unit> TaskWindow { get; private set; }
  330. public CallingCodeContext CallingCodeContext { get; private set; }
  331. }
  332. }
  333. }