123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- #if XFORMS
- namespace Caliburn.Micro.Core.Xamarin.Forms
- #else
- namespace Caliburn.Micro
- #endif
- {
- using System;
- using System.Linq;
- #if WinRT
- using System.Reflection;
- using Windows.ApplicationModel;
- using Windows.UI.Xaml;
- using Windows.UI.Xaml.Controls;
- using Windows.UI.Xaml.Markup;
- using Windows.UI.Xaml.Media;
- #elif XFORMS
- using System.Reflection;
- using global::Xamarin.Forms;
- using UIElement = global::Xamarin.Forms.Element;
- using FrameworkElement = global::Xamarin.Forms.VisualElement;
- using DependencyProperty = global::Xamarin.Forms.BindableProperty;
- using DependencyObject = global::Xamarin.Forms.BindableObject;
- using ContentControl = global::Xamarin.Forms.ContentView;
- #else
- using System.ComponentModel;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Markup;
- using Caliburn.Micro.Core;
- #endif
- /// <summary>
- /// Hosts attached properties related to view models.
- /// </summary>
- public static class View {
- static readonly ILog Log = LogManager.GetLog(typeof(View));
- #if WinRT || XFORMS
- const string DefaultContentPropertyName = "Content";
- #else
- static readonly ContentPropertyAttribute DefaultContentProperty = new ContentPropertyAttribute("Content");
- #endif
- /// <summary>
- /// A dependency property which allows the framework to track whether a certain element has already been loaded in certain scenarios.
- /// </summary>
- public static readonly DependencyProperty IsLoadedProperty =
- DependencyPropertyHelper.RegisterAttached(
- "IsLoaded",
- typeof(bool),
- typeof(View),
- false
- );
- /// <summary>
- /// A dependency property which marks an element as a name scope root.
- /// </summary>
- public static readonly DependencyProperty IsScopeRootProperty =
- DependencyPropertyHelper.RegisterAttached(
- "IsScopeRoot",
- typeof(bool),
- typeof(View),
- false
- );
- /// <summary>
- /// A dependency property which allows the override of convention application behavior.
- /// </summary>
- public static readonly DependencyProperty ApplyConventionsProperty =
- DependencyPropertyHelper.RegisterAttached(
- "ApplyConventions",
- typeof(bool?),
- typeof(View)
- );
- /// <summary>
- /// A dependency property for assigning a context to a particular portion of the UI.
- /// </summary>
- public static readonly DependencyProperty ContextProperty =
- DependencyPropertyHelper.RegisterAttached(
- "Context",
- typeof(object),
- typeof(View),
- null,
- OnContextChanged
- );
- /// <summary>
- /// A dependency property for attaching a model to the UI.
- /// </summary>
- public static DependencyProperty ModelProperty =
- DependencyPropertyHelper.RegisterAttached(
- "Model",
- typeof(object),
- typeof(View),
- null,
- OnModelChanged
- );
- /// <summary>
- /// Used by the framework to indicate that this element was generated.
- /// </summary>
- public static readonly DependencyProperty IsGeneratedProperty =
- DependencyPropertyHelper.RegisterAttached(
- "IsGenerated",
- typeof(bool),
- typeof(View),
- false
- );
- /// <summary>
- /// Executes the handler immediately if the element is loaded, otherwise wires it to the Loaded event.
- /// </summary>
- /// <param name="element">The element.</param>
- /// <param name="handler">The handler.</param>
- /// <returns>true if the handler was executed immediately; false otherwise</returns>
- public static bool ExecuteOnLoad(FrameworkElement element, RoutedEventHandler handler) {
- #if XFORMS
- handler(element, new RoutedEventArgs());
- return true;
- #else
- #if SILVERLIGHT
- if ((bool)element.GetValue(IsLoadedProperty)) {
- #elif WinRT
- if (IsElementLoaded(element)) {
- #else
- if(element.IsLoaded) {
- #endif
- handler(element, new RoutedEventArgs());
- return true;
- }
- RoutedEventHandler loaded = null;
- loaded = (s, e) => {
- element.Loaded -= loaded;
- #if SILVERLIGHT
- element.SetValue(IsLoadedProperty, true);
- #endif
- handler(s, e);
- };
- element.Loaded += loaded;
- return false;
- #endif
- }
- /// <summary>
- /// Executes the handler when the element is unloaded.
- /// </summary>
- /// <param name="element">The element.</param>
- /// <param name="handler">The handler.</param>
- public static void ExecuteOnUnload(FrameworkElement element, RoutedEventHandler handler) {
- #if !XFORMS
- RoutedEventHandler unloaded = null;
- unloaded = (s, e) => {
- element.Unloaded -= unloaded;
- handler(s, e);
- };
- element.Unloaded += unloaded;
- #endif
- }
- #if WinRT
- /// <summary>
- /// Determines whether the specified <paramref name="element"/> is loaded.
- /// </summary>
- /// <param name="element">The element.</param>
- /// <returns>true if the element is loaded; otherwise, false.
- /// </returns>
- public static bool IsElementLoaded(FrameworkElement element) {
- try
- {
- if ((element.Parent ?? VisualTreeHelper.GetParent(element)) != null)
- {
- return true;
- }
- var rootVisual = Window.Current.Content;
- if (rootVisual != null)
- {
- return element == rootVisual;
- }
- return false;
- }
- catch
- {
- return false;
- }
- }
- #endif
- /// <summary>
- /// Executes the handler the next time the elements's LayoutUpdated event fires.
- /// </summary>
- /// <param name="element">The element.</param>
- /// <param name="handler">The handler.</param>
- #if WinRT
- public static void ExecuteOnLayoutUpdated(FrameworkElement element, EventHandler<object> handler) {
- EventHandler<object> onLayoutUpdate = null;
- #else
- public static void ExecuteOnLayoutUpdated(FrameworkElement element, EventHandler handler) {
- EventHandler onLayoutUpdate = null;
- #endif
- #if !XFORMS
- onLayoutUpdate = (s, e) => {
- element.LayoutUpdated -= onLayoutUpdate;
- handler(element, e);
- };
- element.LayoutUpdated += onLayoutUpdate;
- #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 static Func<object, object> GetFirstNonGeneratedView = view => {
- var dependencyObject = view as DependencyObject;
- if (dependencyObject == null) {
- return view;
- }
- if ((bool)dependencyObject.GetValue(IsGeneratedProperty)) {
- if (dependencyObject is ContentControl) {
- return ((ContentControl)dependencyObject).Content;
- }
- #if WinRT || XFORMS
- var type = dependencyObject.GetType();
- var contentPropertyName = GetContentPropertyName(type);
- return type.GetRuntimeProperty(contentPropertyName)
- .GetValue(dependencyObject, null);
- #else
- var type = dependencyObject.GetType();
- var contentProperty = type.GetAttributes<ContentPropertyAttribute>(true)
- .FirstOrDefault() ?? DefaultContentProperty;
- return type.GetProperty(contentProperty.Name)
- .GetValue(dependencyObject, null);
- #endif
- }
- return dependencyObject;
- };
- /// <summary>
- /// Gets the convention application behavior.
- /// </summary>
- /// <param name="d">The element the property is attached to.</param>
- /// <returns>Whether or not to apply conventions.</returns>
- public static bool? GetApplyConventions(DependencyObject d) {
- return (bool?)d.GetValue(ApplyConventionsProperty);
- }
- /// <summary>
- /// Sets the convention application behavior.
- /// </summary>
- /// <param name="d">The element to attach the property to.</param>
- /// <param name="value">Whether or not to apply conventions.</param>
- public static void SetApplyConventions(DependencyObject d, bool? value) {
- d.SetValue(ApplyConventionsProperty, value);
- }
- /// <summary>
- /// Sets the model.
- /// </summary>
- /// <param name="d">The element to attach the model to.</param>
- /// <param name="value">The model.</param>
- public static void SetModel(DependencyObject d, object value) {
- d.SetValue(ModelProperty, value);
- }
- /// <summary>
- /// Gets the model.
- /// </summary>
- /// <param name="d">The element the model is attached to.</param>
- /// <returns>The model.</returns>
- public static object GetModel(DependencyObject d) {
- return d.GetValue(ModelProperty);
- }
- /// <summary>
- /// Gets the context.
- /// </summary>
- /// <param name="d">The element the context is attached to.</param>
- /// <returns>The context.</returns>
- public static object GetContext(DependencyObject d) {
- return d.GetValue(ContextProperty);
- }
- /// <summary>
- /// Sets the context.
- /// </summary>
- /// <param name="d">The element to attach the context to.</param>
- /// <param name="value">The context.</param>
- public static void SetContext(DependencyObject d, object value) {
- d.SetValue(ContextProperty, value);
- }
- static void OnModelChanged(DependencyObject targetLocation, DependencyPropertyChangedEventArgs args) {
- if (args.OldValue == args.NewValue) {
- return;
- }
- if (args.NewValue != null) {
- var context = GetContext(targetLocation);
-
- var view = ViewLocator.LocateForModel(args.NewValue, targetLocation, context);
- // Trialing binding before setting content in Xamarin Forms
- #if XFORMS
- ViewModelBinder.Bind(args.NewValue, view, context);
- #endif
- if (!SetContentProperty(targetLocation, view)) {
- Log.Warn("SetContentProperty failed for ViewLocator.LocateForModel, falling back to LocateForModelType");
- view = ViewLocator.LocateForModelType(args.NewValue.GetType(), targetLocation, context);
- SetContentProperty(targetLocation, view);
- }
- #if !XFORMS
- ViewModelBinder.Bind(args.NewValue, view, context);
- #endif
- }
- else {
- SetContentProperty(targetLocation, args.NewValue);
- }
- }
- static void OnContextChanged(DependencyObject targetLocation, DependencyPropertyChangedEventArgs e) {
- if (e.OldValue == e.NewValue) {
- return;
- }
- var model = GetModel(targetLocation);
- if (model == null) {
- return;
- }
- var view = ViewLocator.LocateForModel(model, targetLocation, e.NewValue);
- if (!SetContentProperty(targetLocation, view)) {
- Log.Warn("SetContentProperty failed for ViewLocator.LocateForModel, falling back to LocateForModelType");
- view = ViewLocator.LocateForModelType(model.GetType(), targetLocation, e.NewValue);
- SetContentProperty(targetLocation, view);
- }
- ViewModelBinder.Bind(model, view, e.NewValue);
- }
- static bool SetContentProperty(object targetLocation, object view) {
- var fe = view as FrameworkElement;
- if (fe != null && fe.Parent != null) {
- SetContentPropertyCore(fe.Parent, null);
- }
- return SetContentPropertyCore(targetLocation, view);
- }
- #if WinRT || XFORMS
- static bool SetContentPropertyCore(object targetLocation, object view) {
- try {
- var type = targetLocation.GetType();
- var contentPropertyName = GetContentPropertyName(type);
- type.GetRuntimeProperty(contentPropertyName)
- .SetValue(targetLocation, view, null);
- return true;
- }
- catch (Exception e) {
- Log.Error(e);
- return false;
- }
- }
- private static string GetContentPropertyName(Type type) {
- var typeInfo = type.GetTypeInfo();
- var contentProperty = typeInfo.GetCustomAttribute<ContentPropertyAttribute>();
-
- return contentProperty?.Name ?? DefaultContentPropertyName;
- }
- #else
- static bool SetContentPropertyCore(object targetLocation, object view) {
- try {
- var type = targetLocation.GetType();
- var contentProperty = type.GetAttributes<ContentPropertyAttribute>(true)
- .FirstOrDefault() ?? DefaultContentProperty;
- type.GetProperty(contentProperty.Name ?? DefaultContentProperty.Name)
- .SetValue(targetLocation, view, null);
- return true;
- }
- catch(Exception e) {
- Log.Error(e);
- return false;
- }
- }
- #endif
- private static bool? inDesignMode;
- /// <summary>
- /// Gets a value that indicates whether the process is running in design mode.
- /// </summary>
- public static bool InDesignMode
- {
- get
- {
- if (inDesignMode == null)
- {
- #if XFORMS
- inDesignMode = false;
- #elif WinRT
- inDesignMode = DesignMode.DesignModeEnabled;
- #elif SILVERLIGHT
- inDesignMode = DesignerProperties.IsInDesignTool;
- #else
- var descriptor = DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement));
- inDesignMode = (bool)descriptor.Metadata.DefaultValue;
- #endif
- }
- return inDesignMode.GetValueOrDefault(false);
- }
- }
- }
- }
|