zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    [日常] Go-逐行读取文本信息
    [日常] nginx的错误日志error_log设置
    [日常] nginx记录post数据
    [PHP] PHP在CLI环境下的错误日志
    [PHP] 2018年终总结
    [MySQL] INFORMATION_SCHEMA 数据库包含所有表的字段
    前端吐槽的后端接口那些事
    读《猫力乱步》 | 如果你走得够远,你也能有那么多故事
    js获取隐藏元素宽高的方法
    RequireJS使用注意地方
  • 原文地址:https://www.cnblogs.com/bomo/p/3952419.html
Copyright © 2011-2022 走看看