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 /// /// A implementation for the XAML platfrom. /// public class XamlPlatformProvider : IPlatformProvider { #if WinRT private CoreDispatcher dispatcher; #else private Dispatcher dispatcher; #endif /// /// Initializes a new instance of the class. /// public XamlPlatformProvider() { #if SILVERLIGHT dispatcher = System.Windows.Deployment.Current.Dispatcher; #elif WinRT dispatcher = Window.Current.Dispatcher; #else dispatcher = Dispatcher.CurrentDispatcher; #endif } /// /// Indicates whether or not the framework is in design-time mode. /// 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 } /// /// Executes the action on the UI thread asynchronously. /// /// The action to execute. public void BeginOnUIThread(System.Action action) { ValidateDispatcher(); #if WinRT var dummy = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()); #else dispatcher.BeginInvoke(action); #endif } /// /// Executes the action on the UI thread asynchronously. /// /// The action to execute. /// 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(); System.Action method = () => { try { action(); taskSource.SetResult(null); } catch(Exception ex) { taskSource.SetException(ex); } }; dispatcher.BeginInvoke(method); return taskSource.Task; #endif } /// /// Executes the action on the UI thread. /// /// The action to execute. /// 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 } } /// /// Used to retrieve the root, non-framework-created view. /// /// The view to search. /// /// The root element that was not created by the framework. /// /// /// 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. /// public object GetFirstNonGeneratedView(object view) { return View.GetFirstNonGeneratedView(view); } private static readonly DependencyProperty PreviouslyAttachedProperty = DependencyProperty.RegisterAttached( "PreviouslyAttached", typeof (bool), typeof (XamlPlatformProvider), null ); /// /// Executes the handler the fist time the view is loaded. /// /// The view. /// The handler. public void ExecuteOnFirstLoad(object view, Action handler) { var element = view as FrameworkElement; if (element != null && !(bool) element.GetValue(PreviouslyAttachedProperty)) { element.SetValue(PreviouslyAttachedProperty, true); View.ExecuteOnLoad(element, (s, e) => handler(s)); } } /// /// Executes the handler the next time the view's LayoutUpdated event fires. /// /// The view. /// The handler. public void ExecuteOnLayoutUpdated(object view, Action handler) { var element = view as FrameworkElement; if (element != null) { View.ExecuteOnLayoutUpdated(element, (s, e) => handler(s)); } } /// /// Get the close action for the specified view model. /// /// The view model to close. /// The associated views. /// The dialog result. /// /// An to close the view model. /// /// public System.Action GetViewCloseAction(object viewModel, ICollection 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."); } } }