123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- namespace Caliburn.Micro {
- using System;
- using System.Collections.Generic;
- using System.Threading.Tasks;
- #if WinRT
- using System.Reflection;
- using Windows.UI.Core;
- using Windows.UI.Xaml;
- #else
- using System.Windows;
- using System.Windows.Threading;
- using Caliburn.Micro.Core;
- #endif
- /// <summary>
- /// A <see cref="IPlatformProvider"/> implementation for the XAML platfrom.
- /// </summary>
- public class XamlPlatformProvider : IPlatformProvider {
- #if WinRT
- private CoreDispatcher dispatcher;
- #else
- private Dispatcher dispatcher;
- #endif
- /// <summary>
- /// Initializes a new instance of the <see cref="XamlPlatformProvider"/> class.
- /// </summary>
- public XamlPlatformProvider() {
- #if SILVERLIGHT
- dispatcher = System.Windows.Deployment.Current.Dispatcher;
- #elif WinRT
- dispatcher = Window.Current.Dispatcher;
- #else
- dispatcher = Dispatcher.CurrentDispatcher;
- #endif
- }
- /// <summary>
- /// Indicates whether or not the framework is in design-time mode.
- /// </summary>
- public bool InDesignMode {
- get { return View.InDesignMode; }
- }
- private void ValidateDispatcher() {
- if (dispatcher == null)
- throw new InvalidOperationException("Not initialized with dispatcher.");
- }
- private bool CheckAccess() {
- #if WinRT
- return dispatcher == null || Window.Current != null;
- #else
- return dispatcher == null || dispatcher.CheckAccess();
- #endif
- }
- /// <summary>
- /// Executes the action on the UI thread asynchronously.
- /// </summary>
- /// <param name="action">The action to execute.</param>
- public void BeginOnUIThread(System.Action action) {
- ValidateDispatcher();
- #if WinRT
- var dummy = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action());
- #else
- dispatcher.BeginInvoke(action);
- #endif
- }
- /// <summary>
- /// Executes the action on the UI thread asynchronously.
- /// </summary>
- /// <param name="action">The action to execute.</param>
- /// <returns></returns>
- public Task OnUIThreadAsync(System.Action action) {
- ValidateDispatcher();
- #if WinRT
- return dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask();
- #elif NET45
- return dispatcher.InvokeAsync(action).Task;
- #else
- var taskSource = new TaskCompletionSource<object>();
- System.Action method = () => {
- try {
- action();
- taskSource.SetResult(null);
- }
- catch(Exception ex) {
- taskSource.SetException(ex);
- }
- };
- dispatcher.BeginInvoke(method);
- return taskSource.Task;
- #endif
- }
- /// <summary>
- /// Executes the action on the UI thread.
- /// </summary>
- /// <param name="action">The action to execute.</param>
- /// <exception cref="System.NotImplementedException"></exception>
- public void OnUIThread(System.Action action) {
- if (CheckAccess())
- action();
- else {
- #if WinRT
- dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask().Wait();
- #elif NET
- Exception exception = null;
- System.Action method = () => {
- try {
- action();
- }
- catch(Exception ex) {
- exception = ex;
- }
- };
- dispatcher.Invoke(method);
- if (exception != null)
- throw new System.Reflection.TargetInvocationException("An error occurred while dispatching a call to the UI Thread", exception);
- #else
- var waitHandle = new System.Threading.ManualResetEvent(false);
- Exception exception = null;
- System.Action method = () => {
- try {
- action();
- }
- catch (Exception ex) {
- exception = ex;
- }
- waitHandle.Set();
- };
- dispatcher.BeginInvoke(method);
- waitHandle.WaitOne();
- if (exception != null)
- throw new System.Reflection.TargetInvocationException("An error occurred while dispatching a call to the UI Thread", exception);
- #endif
- }
- }
- /// <summary>
- /// Used to retrieve the root, non-framework-created view.
- /// </summary>
- /// <param name="view">The view to search.</param>
- /// <returns>
- /// The root element that was not created by the framework.
- /// </returns>
- /// <remarks>
- /// In certain instances the services create UI elements.
- /// For example, if you ask the window manager to show a UserControl as a dialog, it creates a window to host the UserControl in.
- /// The WindowManager marks that element as a framework-created element so that it can determine what it created vs. what was intended by the developer.
- /// Calling GetFirstNonGeneratedView allows the framework to discover what the original element was.
- /// </remarks>
- public object GetFirstNonGeneratedView(object view) {
- return View.GetFirstNonGeneratedView(view);
- }
- private static readonly DependencyProperty PreviouslyAttachedProperty = DependencyProperty.RegisterAttached(
- "PreviouslyAttached",
- typeof (bool),
- typeof (XamlPlatformProvider),
- null
- );
- /// <summary>
- /// Executes the handler the fist time the view is loaded.
- /// </summary>
- /// <param name="view">The view.</param>
- /// <param name="handler">The handler.</param>
- public void ExecuteOnFirstLoad(object view, Action<object> handler) {
- var element = view as FrameworkElement;
- if (element != null && !(bool) element.GetValue(PreviouslyAttachedProperty)) {
- element.SetValue(PreviouslyAttachedProperty, true);
- View.ExecuteOnLoad(element, (s, e) => handler(s));
- }
- }
- /// <summary>
- /// Executes the handler the next time the view's LayoutUpdated event fires.
- /// </summary>
- /// <param name="view">The view.</param>
- /// <param name="handler">The handler.</param>
- public void ExecuteOnLayoutUpdated(object view, Action<object> handler) {
- var element = view as FrameworkElement;
- if (element != null) {
- View.ExecuteOnLayoutUpdated(element, (s, e) => handler(s));
- }
- }
- /// <summary>
- /// Get the close action for the specified view model.
- /// </summary>
- /// <param name="viewModel">The view model to close.</param>
- /// <param name="views">The associated views.</param>
- /// <param name="dialogResult">The dialog result.</param>
- /// <returns>
- /// An <see cref="Action" /> to close the view model.
- /// </returns>
- /// <exception cref="System.NotImplementedException"></exception>
- public System.Action GetViewCloseAction(object viewModel, ICollection<object> views, bool? dialogResult) {
- var child = viewModel as IChild;
- if (child != null) {
- var conductor = child.Parent as IConductor;
- if (conductor != null) {
- return () => conductor.CloseItem(viewModel);
- }
- }
- foreach (var contextualView in views) {
- var viewType = contextualView.GetType();
- #if WinRT
- var closeMethod = viewType.GetRuntimeMethod("Close", new Type[0]);
- #else
- var closeMethod = viewType.GetMethod("Close");
- #endif
- if (closeMethod != null)
- return () => {
- #if !SILVERLIGHT && !WinRT
- var isClosed = false;
- if (dialogResult != null) {
- var resultProperty = contextualView.GetType().GetProperty("DialogResult");
- if (resultProperty != null) {
- resultProperty.SetValue(contextualView, dialogResult, null);
- isClosed = true;
- }
- }
- if (!isClosed) {
- closeMethod.Invoke(contextualView, null);
- }
- #else
- closeMethod.Invoke(contextualView, null);
- #endif
- };
- #if WinRT
- var isOpenProperty = viewType.GetRuntimeProperty("IsOpen");
- #else
- var isOpenProperty = viewType.GetProperty("IsOpen");
- #endif
- if (isOpenProperty != null) {
- return () => isOpenProperty.SetValue(contextualView, false, null);
- }
- }
- return () => LogManager.GetLog(typeof(Screen)).Info("TryClose requires a parent IConductor or a view with a Close method or IsOpen property.");
- }
- }
- }
|