【WP8】扩展CM的WindowManager

14-09-09更新:修复AppBar冲突bug

 

关于WindowManager,一直都很想写一篇博客分享一下,一直在忙别的,今天抽空把这个分享一下

在弹窗在移动开发是一个很常见的交互,很多时候我们都需要进行弹窗,比如我们需要询问用户的一些操作,提供更丰富的交互,又比如我们需要弹出一个框提示用户给我们好评

WP系统提供关于对话框的操作只有一个MessageBox,MessageBox样式简单,并且无法扩展,比如我们需要自定义按钮的文字都不可以,极大限制了我们的发挥,如果我们需要弹窗,还有Popup控件可以用,比如Coding4fun就对Popup进行了扩展,提供了更丰富对话框样式

用CM(Caluburn.Micro)也有一段时间了,CM不仅提供了MVVM的支持,还提供了IoC依赖注入容器,还提供了WindowManager的支持(这是一个非常值得深入研究的开源框架)可以在页面的ViewModel中直接通过控件对应的ViewModel构造控件进行显示,下面我们对控件进行

 

一、页面框架层次

首先说明一下页面框架的层次关系:

  Frame:最底层

  Page:页面在Frame的上层

  Popup:在页面的上层,弹出的控件会在覆盖在页面的上面

  Keyboard:键盘可以遮住Popup弹窗

  ApplicationBar:应用程序栏在键盘之上,不会被Popup覆盖,所以自定义的弹窗是不能把ApplicationBar给遮住的

  MessageBox:系统自带的MessageBox可以把一切遮住,包括ApplicationBar

 

二、WindowManager职责

  WindowManager通过封装Popup,给为外部提供很方便的弹窗操作,下面列举一下WindowManager关于弹窗所做的操作(基于CM)

    1、新建一个Host:当我们显示弹窗之前,我们需要一个容器(ContentControl)用于内部管理

    2、通过ViewModel找到对应的View(控件),并且将ViewModel绑定到View上(CM)

    3、Host.Content = view

    4、ApplySetting:通过反射设置信息,CM默认的WindowManager提供了对Host的设置

    5、判断ViewModel是否实现IActivate和IDeactivate事件,如果有,则绑定事件(在弹窗打开和关闭的时候触发)

    6、接管BackKey:比如用户按返回键是否需要关闭弹窗

    7、接管ApplicationBar:由于Popup在ApplicationBar下层,无法遮住ApplicationBar,一般的做法是隐藏掉ApplicationBar,或者是禁用掉ApplicationBar上的按钮和MenuItem,在弹窗关闭后,恢复ApplicationBar原有的状态

    8、接管Page.OrientationChanged事件:一般我们不处理该事件

    9、Popup.IsOpen = true;  打开弹窗(打开之前一般设置其Opacity为0,防止闪一下)

    10、开启弹窗动画(CM默认没有提供动画的支持,后面我们自定义的时候加入该支持)

 

定义WindowManager主要就是上面一些操作,这里不分析CM中的WindowManager的源码了,有兴趣的可以去看,但是CM提供的WindowManager还是不够用,我们需要可以更多自定义的一些配置,比如:

  1、弹窗的时候是否隐藏ApplicationBar

  2、弹窗的时候点击其他区域是否关闭弹窗

  3、弹窗是否需要用一个遮罩遮住原来页面

  4、弹窗是否支持动画注入(支持扩展)

  5、弹窗是否可以被返回键关闭

三、定义与实现

  原本是想直接继承WindowManager来做的,但是发现WindowManager提供的属性和方法太少了,很难扩展,所以下面通过自定义的方式扩展

  定义接口

 

    public interface ICustomWindowManager : IWindowManager

    {

        void ShowDialog(object rootModel, bool isTapClose = true, double maskOpacity = 0.8, IWindowAnimator windowAnimator = null, bool isHideApplicationBar = true, bool canClose = true);

    }

 

  实现:

    动画接口

    /// <summary>

    /// WindowManager动画的接口(用于扩展动画)

    /// </summary>

    public interface IWindowAnimator

    {

        void Enter(FrameworkElement viewContainer, FrameworkElement host);

        void Exit(FrameworkElement viewContainer, FrameworkElement host, Action complete);

    }

    WindowAnimator动画默认实现

    /// <summary>

    /// 默认弹窗动画的实现(渐入和渐出)

    /// </summary>

    public class DefaultWindowAnimator : IWindowAnimator

    {

        public void Enter(FrameworkElement viewContainer, FrameworkElement host)

        {

            var storyboard = new Storyboard();

            var doubleAnimation = new DoubleAnimation

            {

                Duration = new Duration(TimeSpan.FromSeconds(0.1)),

                From = 0,

                To = 1

            };

            Storyboard.SetTarget(doubleAnimation, host);

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity", new object[0]));

            storyboard.Children.Add(doubleAnimation);

            storyboard.Begin();

        }



        public void Exit(FrameworkElement viewContainer, FrameworkElement host, Action complete)

        {

            var storyboard = new Storyboard();

            var doubleAnimation = new DoubleAnimation

            {

                Duration = new Duration(TimeSpan.FromSeconds(0.1)),

                From = 1,

                To = 0

            };

            Storyboard.SetTarget(doubleAnimation, host);

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity", new object[0]));

            storyboard.Children.Add(doubleAnimation);

            storyboard.Completed += (sender, e) => complete.Invoke();

            storyboard.Begin();

        }

    }

    下面提供其他动画的实现

【WP8】扩展CM的WindowManager
    /// <summary>

    /// 翻转动画

    /// </summary>

    public class FlipWindowAnimator : IWindowAnimator

    {

        private const double DURATION_SECONDS = 0.15;



        public void Enter(FrameworkElement viewContainer, FrameworkElement host)

        {

            viewContainer.Projection = new PlaneProjection();



            var storyboard = new Storyboard();

            var doubleAnimation = new DoubleAnimation

            {

                Duration = new Duration(TimeSpan.FromSeconds(DURATION_SECONDS)),

                From = 90,

                To = 0

            };





            Storyboard.SetTarget(doubleAnimation, viewContainer.Projection);

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("RotationX", new object[0]));

            storyboard.Children.Add(doubleAnimation);



            doubleAnimation = new DoubleAnimation

            {

                Duration = new Duration(TimeSpan.FromSeconds(DURATION_SECONDS)),

                From = 0,

                To = 1

            };

            Storyboard.SetTarget(doubleAnimation, host);

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity", new object[0]));

            storyboard.Children.Add(doubleAnimation);

            storyboard.Begin();

        }



        public void Exit(FrameworkElement viewContainer, FrameworkElement host, Action complete)

        {

            var storyboard = new Storyboard();

            var doubleAnimation = new DoubleAnimation

            {

                Duration = new Duration(TimeSpan.FromSeconds(DURATION_SECONDS)),

                From = 0,

                To = 90

            };



            Storyboard.SetTarget(doubleAnimation, viewContainer.Projection);

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("RotationX", new object[0]));

            storyboard.Children.Add(doubleAnimation);



            doubleAnimation = new DoubleAnimation

            {

                Duration = new Duration(TimeSpan.FromSeconds(DURATION_SECONDS)),

                From = 1,

                To = 0

            };

            Storyboard.SetTarget(doubleAnimation, host);

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity", new object[0]));

            storyboard.Children.Add(doubleAnimation);





            storyboard.Completed += (sender, e) => complete.Invoke();

            storyboard.Begin();

        }

    }
翻转动画:FlipWindowAnimator

    滑动动画参考自WPToolkit

【WP8】扩展CM的WindowManager
    /// <summary>

    /// 上下滑动动画

    /// </summary>

    public class SlideUpWindowAnimator : IWindowAnimator

    {

        /// <summary>

        /// 向上显示动画

        /// </summary>

        private const string SLIDE_UP_STORYBOARD = @"

        <Storyboard  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">

            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=""(UIElement.RenderTransform).(CompositeTransform.TranslateY)"">

                <EasingDoubleKeyFrame KeyTime=""0"" Value=""150""/>

                <EasingDoubleKeyFrame KeyTime=""0:0:0.35"" Value=""0"">

                    <EasingDoubleKeyFrame.EasingFunction>

                        <ExponentialEase EasingMode=""EaseOut"" Exponent=""6""/>

                    </EasingDoubleKeyFrame.EasingFunction>

                </EasingDoubleKeyFrame>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimation Storyboard.TargetProperty=""(UIElement.Opacity)"" From=""0"" To=""1"" Duration=""0:0:0.350"">

                <DoubleAnimation.EasingFunction>

                    <ExponentialEase EasingMode=""EaseOut"" Exponent=""6""/>

                </DoubleAnimation.EasingFunction>

            </DoubleAnimation>

        </Storyboard>";



        /// <summary>

        /// 向下消失动画

        /// </summary>

        private const string SLIDE_DOWN_STORYBOARD = @"

        <Storyboard  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">

            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=""(UIElement.RenderTransform).(CompositeTransform.TranslateY)"">

                <EasingDoubleKeyFrame KeyTime=""0"" Value=""0""/>

                <EasingDoubleKeyFrame KeyTime=""0:0:0.25"" Value=""150"">

                    <EasingDoubleKeyFrame.EasingFunction>

                        <ExponentialEase EasingMode=""EaseIn"" Exponent=""6""/>

                    </EasingDoubleKeyFrame.EasingFunction>

                </EasingDoubleKeyFrame>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimation Storyboard.TargetProperty=""(UIElement.Opacity)"" From=""1"" To=""0"" Duration=""0:0:0.25"">

                <DoubleAnimation.EasingFunction>

                    <ExponentialEase EasingMode=""EaseIn"" Exponent=""6""/>

                </DoubleAnimation.EasingFunction>

            </DoubleAnimation>

        </Storyboard>";



        public void Enter(FrameworkElement viewContainer, FrameworkElement host)

        {

            var storyboard = XamlReader.Load(SLIDE_UP_STORYBOARD) as Storyboard;



            if (storyboard != null)

            {

                foreach (var t in storyboard.Children)

                {

                    Storyboard.SetTarget(t, host);

                }



                storyboard.Begin();

            }

        }



        public void Exit(FrameworkElement viewContainer, FrameworkElement host, Action complete)

        {

            var storyboard = XamlReader.Load(SLIDE_DOWN_STORYBOARD) as Storyboard;



            if (storyboard != null)

            {

                foreach (var t in storyboard.Children)

                {

                    Storyboard.SetTarget(t, host);

                }



                storyboard.Completed += (sender, e) => complete.Invoke();

                storyboard.Begin();

            }

        }

    }
上下滑动动画:SlideUpWindowAnimator

    WindowManager实现:大部分参考自原来的WindowManager实现

 

【WP8】扩展CM的WindowManager
using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Linq;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Controls.Primitives;

using System.Windows.Markup;

using System.Windows.Media;

using Caliburn.Micro;

using Microsoft.Phone.Controls;

using Microsoft.Phone.Shell;



namespace TestDemo

{

    /// <summary>

    /// 自定义窗口管理器(基于Caliburn.Micro)

    /// </summary>

    public class CustomWindowManager : ICustomWindowManager

    {

        public static Func<Uri, bool> IsSystemDialogNavigation = uri => uri != null && uri.ToString().StartsWith("/Microsoft.Phone.Controls.Toolkit");



        public virtual void ShowDialog(object rootModel, object context = null, IDictionary<string, object> settings = null)

        {

            var navigationSvc = IoC.Get<INavigationService>();



            var host = new DialogHost(navigationSvc);

            var view = ViewLocator.LocateForModel(rootModel, host, context);

            host.Content = view as FrameworkElement;

            host.SetValue(View.IsGeneratedProperty, true);



            ViewModelBinder.Bind(rootModel, host, null);

            host.SetActionTarget(rootModel);



            ApplySettings(host, settings);



            var activatable = rootModel as IActivate;

            if (activatable != null)

            {

                activatable.Activate();

            }



            var deactivator = rootModel as IDeactivate;

            if (deactivator != null)

            {

                host.Closed += delegate { deactivator.Deactivate(true); };

            }



            host.Open();

        }



        public virtual void ShowPopup(object rootModel, object context = null, IDictionary<string, object> settings = null)

        {

            var popup = CreatePopup(rootModel, settings);

            var view = ViewLocator.LocateForModel(rootModel, popup, context);



            popup.Child = view;

            popup.SetValue(View.IsGeneratedProperty, true);



            ViewModelBinder.Bind(rootModel, popup, null);



            var activatable = rootModel as IActivate;

            if (activatable != null)

            {

                activatable.Activate();

            }



            var deactivator = rootModel as IDeactivate;

            if (deactivator != null)

            {

                popup.Closed += delegate { deactivator.Deactivate(true); };

            }



            popup.IsOpen = true;

        }





        public void ShowDialog(object rootModel, bool isTapClose = true, double maskOpacity = 0.5,

            IWindowAnimator windowAnimator = null, bool isHideApplicationBar = true, bool canClose = true)

        {

            var navigationSvc = IoC.Get<INavigationService>();



            var host = new DialogHost(navigationSvc, isTapClose, maskOpacity, isHideApplicationBar, windowAnimator, canClose);

            var view = ViewLocator.LocateForModel(rootModel, host, null);

            host.Content = view as FrameworkElement;

            host.SetValue(View.IsGeneratedProperty, true);



            ViewModelBinder.Bind(rootModel, host, null);

            host.SetActionTarget(rootModel);



            var activatable = rootModel as IActivate;

            if (activatable != null)

            {

                activatable.Activate();

            }



            var deactivator = rootModel as IDeactivate;

            if (deactivator != null)

            {

                host.Closed += delegate { deactivator.Deactivate(true); };

            }



            host.Open();

        }



        protected virtual Popup CreatePopup(object rootModel, IDictionary<string, object> settings)

        {

            var popup = new Popup();

            ApplySettings(popup, settings);

            return popup;

        }



        private static void ApplySettings(object target, IEnumerable<KeyValuePair<string, object>> settings)

        {

            if (settings != null)

            {

                var type = target.GetType();



                foreach (var pair in settings)

                {

                    var propertyInfo = type.GetProperty(pair.Key);



                    if (propertyInfo != null)

                        propertyInfo.SetValue(target, pair.Value, null);

                }

            }

        }



        [ContentProperty("Content")]

        public class DialogHost : FrameworkElement

        {

            readonly INavigationService navigationSvc;

            PhoneApplicationPage currentPage;



            Popup hostPopup;

            bool isOpen;

            ContentControl viewContainer;

            Border pageFreezingLayer;

            Border maskingLayer;

            private FrameworkElement host;

            private readonly IWindowAnimator animator;





            private readonly double maskOpacity;

            private readonly bool isTapClose;

            private readonly bool canClose;



            private readonly bool isHideApplicationBar;







            private readonly Dictionary<IApplicationBarIconButton, bool> appBarButtonsStatus =

                new Dictionary<IApplicationBarIconButton, bool>();

            bool appBarMenuEnabled;



            public DialogHost(INavigationService navigationSvc, bool isTapClose = true, double maskOpacity = 0.5, bool isHideApplicationBar = true, IWindowAnimator animator = null, bool canClose = true)

            {

                this.navigationSvc = navigationSvc;

                this.canClose = canClose;

                currentPage = navigationSvc.CurrentContent as PhoneApplicationPage;

                if (currentPage == null)

                {

                    throw new InvalidOperationException(

                        string.Format("In order to use ShowDialog the view currently loaded in the application frame ({0})"

                                      + " should inherit from PhoneApplicationPage or one of its descendents.", navigationSvc.CurrentContent.GetType()));

                }



                navigationSvc.Navigating += OnNavigating;

                navigationSvc.Navigated += OnNavigated;



                this.maskOpacity = maskOpacity;

                this.isTapClose = isTapClose;

                this.isHideApplicationBar = isHideApplicationBar;

                CreateUiElements();



                this.animator = animator ?? new DefaultWindowAnimator();

            }



            public EventHandler Closed = delegate { };



            public void SetActionTarget(object target)

            {

                Caliburn.Micro.Action.SetTarget(viewContainer, target);

            }



            public virtual FrameworkElement Content

            {

                get { return (FrameworkElement)viewContainer.Content; }

                set { viewContainer.Content = value; }

            }



            public void Open()

            {

                if (isOpen)

                {

                    return;

                }



                isOpen = true;



                if (currentPage.ApplicationBar != null)

                {

                    DisableAppBar();

                }





                ArrangePlacement();



                currentPage.BackKeyPress += CurrentPageBackKeyPress;

                currentPage.OrientationChanged += CurrentPageOrientationChanged;



                hostPopup.IsOpen = true;

            }



            public void Close()

            {

                Close(reopenOnBackNavigation: false);

            }



            void Close(bool reopenOnBackNavigation)

            {

                if (!isOpen)

                {

                    return;

                }



                isOpen = false;

                animator.Exit(Content, host, () => { hostPopup.IsOpen = false; });



                if (currentPage.ApplicationBar != null)

                {

                    RestoreAppBar();

                }



                currentPage.BackKeyPress -= CurrentPageBackKeyPress;

                currentPage.OrientationChanged -= CurrentPageOrientationChanged;



                if (!reopenOnBackNavigation)

                {

                    navigationSvc.Navigating -= OnNavigating;

                    navigationSvc.Navigated -= OnNavigated;



                    Closed(this, EventArgs.Empty);

                }

            }





            protected IWindowAnimator CreateElementsAnimator()

            {

                return new DefaultWindowAnimator();

            }



            protected void CreateUiElements()

            {

                var alpha = Convert.ToByte(maskOpacity * 255);



                viewContainer = new ContentControl

                {

                    HorizontalContentAlignment = HorizontalAlignment.Stretch,

                    VerticalContentAlignment = VerticalAlignment.Stretch,

                };

                maskingLayer = new Border

                {

                    Child = viewContainer,

                    Background = new SolidColorBrush(Color.FromArgb(alpha, 0, 0, 0)),

                    VerticalAlignment = VerticalAlignment.Stretch,

                    HorizontalAlignment = HorizontalAlignment.Stretch,

                    Width = Application.Current.Host.Content.ActualWidth,

                    Height = Application.Current.Host.Content.ActualHeight

                };



                if (isTapClose)

                {

                    maskingLayer.Tap += (s, e) =>

                    {

                        if (e.OriginalSource == maskingLayer)

                        {

                            Close();

                        }

                    };

                }





                pageFreezingLayer = new Border

                {

                    Background = new SolidColorBrush(Colors.Transparent),

                    Width = Application.Current.Host.Content.ActualWidth,

                    Height = Application.Current.Host.Content.ActualHeight

                };



                var panel = new Grid { RenderTransform = new CompositeTransform() };

                panel.Children.Add(pageFreezingLayer);

                panel.Children.Add(maskingLayer);



                host = panel;

                hostPopup = new Popup { Child = panel };

            }



            private bool applicationBarVisible;



            private void DisableAppBar()

            {

                if (isHideApplicationBar)

                {

                    if (currentPage.ApplicationBar.IsVisible)

                    {

                        applicationBarVisible = currentPage.ApplicationBar.IsVisible;

                        currentPage.ApplicationBar.IsVisible = false;    

                    }

                }

                else

                {

                    appBarMenuEnabled = currentPage.ApplicationBar.IsMenuEnabled;

                    appBarButtonsStatus.Clear();

                    currentPage.ApplicationBar.Buttons.Cast<IApplicationBarIconButton>()

                        .Apply(b =>

                        {

                            appBarButtonsStatus.Add(b, b.IsEnabled);

                            b.IsEnabled = false;

                        });



                    currentPage.ApplicationBar.IsMenuEnabled = false;

                }

            }



            private void RestoreAppBar()

            {

                if (isHideApplicationBar)

                {

                    if (applicationBarVisible)

                    {

                        currentPage.ApplicationBar.IsVisible = applicationBarVisible;

                    }

                }

                else

                {

                    if (currentPage.ApplicationBar.IsMenuEnabled != appBarMenuEnabled)

                    {

                        currentPage.ApplicationBar.IsMenuEnabled = appBarMenuEnabled;

                        currentPage.ApplicationBar.Buttons.Cast<IApplicationBarIconButton>()

                            .Apply(b =>

                            {

                                bool status;

                                if (appBarButtonsStatus.TryGetValue(b, out status))

                                    b.IsEnabled = status;

                            });

                    }

                }

            }



            void ArrangePlacement()

            {

                //设置Opacity为0防止闪屏

                host.Opacity = 0;

                maskingLayer.Dispatcher.BeginInvoke(() => animator.Enter(Content, host));

            }



            Uri currentPageUri;

            void OnNavigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)

            {

                if (IsSystemDialogNavigation(e.Uri))

                {

                    currentPageUri = navigationSvc.CurrentSource;

                }

            }



            void OnNavigated(object sender, System.Windows.Navigation.NavigationEventArgs e)

            {

                if (IsSystemDialogNavigation(e.Uri))

                {

                    Close(currentPageUri != null);

                }

                else if (e.Uri.Equals(currentPageUri))

                {

                    currentPageUri = null;

                    //refreshes the page instance

                    currentPage = (PhoneApplicationPage)navigationSvc.CurrentContent;



                    Open();

                }

                else

                {

                    Close(reopenOnBackNavigation: false);

                }

            }



            void CurrentPageBackKeyPress(object sender, CancelEventArgs e)

            {

                e.Cancel = true;

                if (canClose)

                {

                    Close();

                }

            }



            void CurrentPageOrientationChanged(object sender, OrientationChangedEventArgs e)

            {

                ArrangePlacement();

            }

        }





        //TODO:待改

        public void ShowDialog1(object rootModel, IWindowAnimator windowAnimator = null,

            bool isTapClose = true, double maskOpacity = 0.8,

            bool isHideApplicationBar = true, bool canClose = true)

        {

        }

    }

}
CustomWindowManager

 

 

四、使用

 

  使用很简单,首先我们定义一个自定义窗口

【WP8】扩展CM的WindowManager
<UserControl x:Class="XTuOne.Friday.Controls.Views.CommonDialogView"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             VerticalAlignment="Top"

             FontFamily="{StaticResource PhoneFontFamilyNormal}"

             FontSize="{StaticResource PhoneFontSizeNormal}"

             Foreground="{StaticResource PhoneForegroundBrush}"

             d:DesignHeight="480"

             d:DesignWidth="480"

             mc:Ignorable="d">



    <Grid Background="#1F1F1F">

        <StackPanel Margin="12 48 12 12">

            <TextBlock x:Name="Title"

                       Margin="{StaticResource PhoneHorizontalMargin}"

                       FontFamily="{StaticResource PhoneFontFamilySemiBold}"

                       FontSize="{StaticResource PhoneFontSizeLarge}"

                       Foreground="White"

                       TextWrapping="Wrap" />

            <TextBlock x:Name="Text"

                       Margin="12 24"

                       Foreground="White"

                       Style="{StaticResource PhoneTextTitle3Style}"

                       TextWrapping="Wrap" />

            <Grid>

                <Grid.ColumnDefinitions>

                    <ColumnDefinition />

                    <ColumnDefinition />

                </Grid.ColumnDefinitions>

                <Button x:Name="Ok"

                        Grid.Column="0"

                        BorderBrush="White"

                        Foreground="White">

                    <TextBlock x:Name="OkText" Text="Ok" />

                </Button>

                <Button x:Name="Cancel"

                        Grid.Column="1"

                        BorderBrush="White"

                        Foreground="White">

                    <TextBlock x:Name="CancelText" Text="Cancel" />

                </Button>

            </Grid>

        </StackPanel>

    </Grid>

</UserControl>
自定义弹窗控件:CommonDialogView

  后台没有内容,就不贴,然后定义控件对应的ViewModel

【WP8】扩展CM的WindowManager
    public enum DialogResult

    {

        Cancel,

        Ok,

        Close,

    }



    public class CommonDialogViewModel : Screen

    {

        //返回值

        public DialogResult Result { get; private set; }



        //对话框的标题

        public string Title { get; set; }



        //对话框的文字

        public string Text { get; set; }



        //左边按钮的文字

        public string OkText { get; set; }



        //右边按钮的文字

        public string CancelText { get; set; }





        public CommonDialogViewModel()

        {

            Result = DialogResult.Close;

            OkText = "Ok";

            CancelText = "Cancel";

        }



        public void Ok()

        {

            Result = DialogResult.Ok;

            TryClose();

        }



        public void Cancel()

        {

            Result = DialogResult.Cancel;

            TryClose();

        }

    }
CommonDialogViewModel

  接下来是使用

    var windowAnimator = new FlipWindowAnimator();

    var customWindowManager = new CustomWindowManager();



    var commonDialog = new CommonDialogViewModel

    {

        Title = "提示",

        Text = "该手机号已经注册过,您可以:",

        CancelText = "换个手机",

        OkText = "直接登录"

    };



    commonDialog.Deactivated += (s, e) =>

    {

        if (commonDialog.Result == DialogResult.Ok)

        {

            //用户点击左边按钮

           

        }

        else if (commonDialog.Result == DialogResult.Cancel)

        {

            //用户点击右边按钮

        }

        else

        {

            //非用户点击按钮关闭(用户点击返回键或离开App)

        }

    };

    customWindowManager.ShowDialog(commonDialog, false, 0.8, flipWindowAnimator, false);

  效果图

【WP8】扩展CM的WindowManager 【WP8】扩展CM的WindowManager

 截图后面一张正在登陆的LoadingMask由于比较轻,没有用上面的WindowManager,我自己重新定义了一个PageMaskManager,下次再分享

注意:  

  1、为了防止多个弹窗导致HideApplicationBar冲突问题
  2、由于这里是通过ApplicationBar.IsMenuEnable来判断是否被禁用的
  3、所以请保证ApplicationBar.IsMenuEnable为true

 

  WindowManager会改变ApplicationBar的绑定,如果使用了绑定,请注意 IsVisible,IsEnabled,IsMenuEnabled属性的绑定,因为这两个属性在WindowManager中被重新设置过

  还有应该注意多个WindowManager同时使用时候的ApplicationBar冲突

 

  

 

个人能力有限,如果上文有误或者您有更好的实现,可以给我留言

转载请注明出处:http://www.cnblogs.com/bomo/p/3952419.html

你可能感兴趣的:(windowmanager)