【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();
        }
    }

    下面提供其他动画的实现

    /// <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

    /// <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实现

 

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

 

 

四、使用

 

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

<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

    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);

  效果图

 

 截图后面一张正在登陆的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

posted @ 2014-09-02 22:24  bomo  阅读(1202)  评论(4编辑  收藏  举报