zoukankan      html  css  js  c++  java
  • MyFessttoWord P8 ----PageViewModel

    1,将Page更改为一个泛型的Page

     public class BasePage<VM> : Page
            where VM:BaseViewModel,new()
        {
    
            #region Private Member
    
            private VM mViewModel;//创建Page的ViewModel字段
            #endregion
            #region public properties
    
            /// <summary>
            /// the Animation is play when the page is first loaded
            /// </summary>
            public PageAnimation PageLoadAnimation { get; set; } = PageAnimation.SlideAndFadeInFromRight;
    
            /// <summary>
            /// The Animation is play when the page is unloaded
            /// </summary>
            public PageAnimation PageUnloadAnimation { get; set; } = PageAnimation.SlideAndFadeOutToLeft;
    
            /// <summary>
            /// the time any slide animation takes to complete
            /// </summary>
            public float SlideSeconds { get; set; } = 0.8f;
    
            public VM ViewModel  //设置和获取ViewModel
            {
                get
                { return mViewModel; }
    
                set
                {
                    //if nothing has changed return;
                    if (mViewModel == value) return;
    
                    //Update the value
                    mViewModel = value;
    
                    //Set the datacontext for this page
                    this.DataContext = mViewModel;//设置的时候,另Page的DataContext=特定的ViewModel
    
                }
            }
    
            #endregion
    
            #region Constructor
    
            /// <summary>
            /// Default Constructor
            /// </summary>
            public BasePage()
            {
                // If We are animate in ,hide to begin with
                if (this.PageLoadAnimation != PageAnimation.None)
                    this.Visibility = Visibility.Collapsed;
    
                //Fire when Page loaded.
                this.Loaded += BasePage_LoadedAsync;
    
                //create a default view model
                this.ViewModel = new VM();//构造函数建立默认的ViewModel实例.?如何建立带参数的
            }
    
            #endregion
            #region Animation Load / Unload
            /// <summary>
            /// 
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private async void BasePage_LoadedAsync(object sender, RoutedEventArgs e)
            {
                await AnimateIn();
            }
            #region AnimateIn
            public async Task AnimateIn()
            {
                //make sure we have something to do
                if (this.PageLoadAnimation == PageAnimation.None)
                    return;
    
                //select the LoadSwitch
                switch (this.PageLoadAnimation)
                {
                    //choose Slide And Fade In From Right
                    case PageAnimation.SlideAndFadeInFromRight:
                        await this.SlideAndFadeInFromRight(SlideSeconds);
                        break;
                }
    
            }
            #endregion
            #region AnimateOut
            public async Task AnimateOut()
            {
                //make sure we have something to do
                if (this.PageUnloadAnimation == PageAnimation.None)
                    return;
    
                //select the LoadSwitch
                switch (this.PageUnloadAnimation)
                {
                    //choose Slide And Fade In From Right
                    case PageAnimation.SlideAndFadeOutToLeft:
                        await this.SlideAndFadeOutToLeft(SlideSeconds);
                        break;
                }
    
            }
            #endregion
            #endregion
        }
    • 创建View Model的私有字段
    • ,并且属性化.
    • 并且在运行时,默认创建一个ViewModel
    • Page.DataContext=ViewModel

    2,创建ViewMode类

    /// <summary>
        /// ViewModel For Login Page
        /// </summary>
        public class LoginViewModel:BaseViewModel
        {
            #region Private Members
    
            #endregion
    
            #region Public Property
    
            /// <summary>
            /// the Email of the user
            /// </summary>
            public string Email { get; set; }
    
            public SecureString SecurePassword { get; set; }
            #endregion
    
    
            #region Commands
    
           public ICommand LoginCommand { get; set; }
    
            /// <summary>
            /// Indicate the login is runn
            /// </summary>
            public bool LoginIsRunning { get; set; }
    
            #endregion
    
            #region Constructor
            /// <summary>
            /// default construct
            /// </summary>
            public LoginViewModel()
            {
    
    
                //Create commands
                LoginCommand = new RelayParameterizedCommand(async (parameter) =>await Login(parameter) ) ;
    
    
            }
            #endregion
            /// <summary>
            /// Attempts to log the user in 
            /// </summary>
            /// <param name="parameter">the<see cref="SecureString"/>passed in from the view for the users password</param>
            /// <returns></returns>
            public async Task Login(object parameter)
            {
                await RunCommand(() => this.LoginIsRunning, async () =>
                 {
                     //body of a async work!
                     await Task.Delay(5000);
                     var email = this.Email;
                     var password = this.SecurePassword.Unsecure();
                 });
    
            }
    
    
    
    
    
    
    
        }
    • 创建属性对应页面的内容
      • public string Email { get; set; }//Email
      • public SecureString SecurePassword { get; set; } //密码
      • public ICommand LoginCommand { get; set; }//登录
      • public bool LoginIsRunning { get; set; }//登录运行中
    • 绑定LoginCommand
      • 建立参数化的RelayCommand类
      public class RelayParameterizedCommand : ICommand
        {
            /// <summary>
            ///  for action
            /// </summary>
            private Action<object> mAction;
    
            /// <summary>
            ///  constructor
            /// </summary>
            /// <param name="action"></param>
            public RelayParameterizedCommand(Action<object> action)
            {
                mAction = action;
            }
    
            //event when CanExecuteChanged,and doing Nothing
            public event EventHandler CanExecuteChanged = (send, e) => { };
    
            /// <summary>
            /// Judge if CanExecute the Command.
            /// </summary>
            /// <param name="parameter"></param>
            /// <returns></returns>
            public bool CanExecute(object parameter)
            {
                return true;
            }
    
            /// <summary>
            /// do action of command
            /// </summary>
            /// <param name="parameter"></param>
            public void Execute(object parameter)
            {
                mAction(parameter);
            }
        }
            #endregion
    • 创建一个BaseViewModel的一个等待函数
    protected async Task RunCommand(Expression<Func<bool>> updatingFlag,Func<Task> action)
            {
                //Expression.complie.get value
                if (updatingFlag.GetPropertyValue()) return;
    
                //Indicate we're running.
                updatingFlag.SetPropertyValue(true);
                try
                {
                    await action();
                }
                finally
                {
                    //set the property flag back to false now it's finished
                    updatingFlag.SetPropertyValue(false);
                }
    
            }
    主要
    • 用来避免异步任务多次执行.并且指示如果当前任务正在执行,则,updatingFlag=True,奖励了一个陷阱来防止任务多次执行.
    • finally来保证在一次时,释放掉锁.
    • 制作扩展函数利用反射来获取和设置属性的值.

    public static class ExpressionHelpers
        {
            /// <summary>
            /// get a propertyValue use lambda
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="lambda"></param>
            /// <returns></returns>
            public static T GetPropertyValue<T>(this Expression<Func<T>> lambda)
            {
                return lambda.Compile().Invoke();
            }
    
            public static void SetPropertyValue<T>(this Expression<Func<T>> lambda,T value)
            {
                //comvert a lambada()=>some.Property, to some.Property.
                var expression = (lambda as LambdaExpression).Body as MemberExpression;
                var propertyInfo = (PropertyInfo)expression.Member;
    
                // use this
                var target = Expression.Lambda(expression.Expression).Compile().DynamicInvoke();
                propertyInfo.SetValue(target, value);
            }
        }

    • 从lambda中提取出来表达式本体://()=>value(LoginPage).LoginIsRunning===>value(LoginPage).LoginIsRunning
    • 作为MemberExpression,从中提取PropertyInfo
    • expression.Expression--->将value(LoginPage).LoginIsRunning--->获取包含属性的类对象.
    • 利用Expression.Lambda(expression.Expression)--->重构类对象指针.
    • Compile().DynamicInvoke()—>获取到其对象.

    3,获取Password的值的信息

    • 建立扩展函数用于解析SecureString--->String
    public static class SecureStringHelper
        {
            /// <summary>
            /// Unsecure a<see cref="SecureString"/> class
            /// </summary>
            /// <param name="securePassword">the Secure String</param>
            /// <returns></returns>
            public static string Unsecure(this SecureString secureString)
            {
                //makesure we has a secure string
                if (secureString == null) return string.Empty;
    
                var unmanagedString = IntPtr.Zero;
    
                //a way to get the secure string to a common string.
                try
                {
                    //get a pointer of a secure string 
                    unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
                    //copy it to the string .
                    return Marshal.PtrToStringUni(unmanagedString);
                }
                finally
                {
    
                    //Clean up any memory allocation
                    Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
                }
    
            }
        }
    • 新建一个字符串指针//var unmanagedString = IntPtr.Zero
    • 将其指向安全字符串类//:unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
    • 将指针转回字符串//Marshal.PtrToStringUni(unmanagedString);
    • 注意Finally强制释放指针Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);

    • 在LoginPage类中建立 映射,将密码框的SecurePassword转为SecurePassword.
    • SecureString SecurePassword => PasswordText.SecurePassword;

    • 建立一个IhaveSecure接口,从而避免将整个页面信息暴露.
    • 然后再页面的CommandParameter中,将整个xaml类赋值过去

    4,将Login按钮添加一个Spinner功能

    • 新建一个等待的TextBlock Style

    <Style TargetType="{x:Type TextBlock}" x:Key="SpinnerText" BasedOn="{StaticResource BaseTextBlockStyle}">
            <Style.Resources>
                <Storyboard x:Key="sb" >
                    <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
                                     From="0"
                                     To="360"
                                     Duration="0:0:2"
                                     RepeatBehavior="Forever"/>
                </Storyboard>
            </Style.Resources>
    
            <Setter Property="FontFamily" Value="{StaticResource FontAwesome}"/>
            <Setter Property="Text" Value="&#xf110;"/>
            <Setter Property="RenderTransform">
                <Setter.Value>
                    <RotateTransform/>
                </Setter.Value>
            </Setter>
            <Setter Property="RenderTransformOrigin" Value="0.5 0.5"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=IsVisible}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard x:Name="beginSb"  Storyboard="{StaticResource sb}"/>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <RemoveStoryboard BeginStoryboardName="beginSb"/>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    • 在FontAweSome网站下载字体.
    • 并且讲述了如何查看每个图标的字体代码---&#xff10;类似这种,在图标里面查找spin,然后右击该图标选择查看类型.然后在跳出来的网页源代码里面,点开i开头的东西,然后点击before,
    • image
    • 添加字体image
    • 添加资源
    • <FontFamily x:Key="FontAwesome">pack://application;,,,/Fonts/#FontAwesome</FontFamily>

    • 引用字体,及字体中的某个图标值
    • <Setter Property="FontFamily" Value="{StaticResource FontAwesome}"/>
              <Setter Property="Text" Value="&#xf110;"/>//注意格式.

    • 注意创建动画的效果.


    5,button按钮中制作LoginIsRunning连接

    <ControlTemplate TargetType="{x:Type ButtonBase}">
                        <Border x:Name="border"
                                CornerRadius="10"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                SnapsToDevicePixels="True">
                            <Grid>
                                <TextBlock Text="{TemplateBinding Content}"
                                       Focusable="False"
                                       FontFamily="{TemplateBinding FontFamily}"
                                       FontSize="{TemplateBinding FontSize}"
                                       HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                       Margin="{TemplateBinding Padding}"
                                       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                       Visibility="{TemplateBinding local:IsBusyProperty.Value, Converter={local:BooleanToVisibilityConverter}}"
                                           />
    
                                <TextBlock Style="{StaticResource SpinnerText}"
                                       Focusable="False"
                                       FontSize="{TemplateBinding FontSize}"
                                       HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                       Margin="{TemplateBinding Padding}"
                                       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                       Visibility="{TemplateBinding local:IsBusyProperty.Value, Converter={local:BooleanToVisibilityConverter},ConverterParameter=True}"/>
                            </Grid>
    
    
    
                        </Border>
                        <ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <ColorAnimation To="{StaticResource WordBlue}" Duration="0:0:0.3" Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <ColorAnimation From="{StaticResource WordBlue}" Duration="0:0:0.3" Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Background" TargetName="border" Value="{StaticResource ForegroundDarkBrush}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>

    1. 建立依赖性属性 IsBusyProperty.Value
    2. 建立一个泛型的依赖项属性生成类

      

    public abstract class BaseAttachedProperty <Parent,Property>
            where Parent :  new()
        {
            #region Public event
            /// <summary>
            /// Fired when the value changes, 
            /// </summary>
            public event Action<DependencyObject, DependencyPropertyChangedEventArgs> ValueChanged = (sender, e) => { };
    
    
            /// <summary>
            /// Fired when the value changes, even when the value is the same
            /// </summary>
            public event Action<DependencyObject, object> ValueUpdated = (sender, value) => { };
            #endregion
            #region Public Properties
            /// <summary>
            /// A singleton instance of our parent class; 使用这个办法是可以一种使用泛型模板制造静态实例的经典案列.
            /// </summary>
            public static Parent Instance { get; private set; } = new Parent();
            #endregion
    
            #region Attaced Property Definitions
    
            public static readonly DependencyProperty Value = DependencyProperty.RegisterAttached("Value",
                                                            typeof(Property),
                                                            typeof(BaseAttachedProperty<Parent, Property>),
                                                            new UIPropertyMetadata(default(Property),new PropertyChangedCallback(OnValuePropertyChanged),
                                                                new CoerceValueCallback(OnValuePropertyUpdated)
                                                                )
                );
    
            public static Property GetValue(DependencyObject d) => (Property)d.GetValue(Value);
    
            public static void SetValue(DependencyObject d, Property value) => d.SetValue(Value, value);
            #endregion
    
            #region FireFunctions
            /// <summary>
            /// when value changed ,trigger it
            /// </summary>
            /// <param name="d"></param>
            /// <param name="e"></param>
    
            private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                //Fire the class Changed
                (Instance as BaseAttachedProperty<Parent, Property>)?.OnValueChanged(d, e);
    
                //Fire the Listerner Changed
                (Instance as BaseAttachedProperty<Parent, Property>)?.ValueChanged(d, e);
    
            }
    
            /// <summary>
            /// when value updated ,do this
            /// </summary>
            /// <param name="d"></param>
            /// <param name="baseValue"></param>
            /// <returns></returns>
            private static object OnValuePropertyUpdated(DependencyObject d, object value)
            {
                //Fire the class Changed
                (Instance as BaseAttachedProperty<Parent, Property>)?.OnValueUpdated(d, value);
    
                //Fire the Listerner Changed
                (Instance as BaseAttachedProperty<Parent, Property>)?.ValueUpdated(d, value);
                return value;
            }
    
    
    
            #endregion
    
            #region Local Fun
            /// <summary>
            /// Func Value Changed doing sth.
            /// </summary>
            /// <param name="d"></param>
            /// <param name="e"></param>
            public virtual void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
    
            }
            /// <summary>
            /// ValueUpdated Fun doing sth.
            /// </summary>
            /// <param name="d"></param>
            /// <param name="value"></param>
            public virtual void OnValueUpdated(DependencyObject d, object value)
            {
    
            }
            #endregion
    
    
        }

    • 定义ValueChanged和ValueUpdate事件
    • 建立Singlton类的实例和依赖性属性Value
    • 建立i两个虚拟函数,用于在事件触发时优先调用.

       将button的Visibility进行绑定之后,使用Convert.

    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (parameter == null)
                    return (bool)value == false ? Visibility.Visible : Visibility.Hidden;
    
                return (bool)value == true ? Visibility.Visible : Visibility.Hidden;
    
            }

    image

    结果:

    在程序中查看密码和Email地址:

    image

  • 相关阅读:
    SYBASE 日志空间满了的几种情况
    命令行对jar包的解压和压缩
    SYBASE 常用 sp_configure
    SYBASE 删除数据库
    【转】从RGB色转为灰度色算法
    C# 指针操作图像 细化处理
    C# 指针操作图像 二值化处理
    C# 对象转换为byte[] ,byte[]还原对象
    javascript 简单加解密
    windows 2003 企业版 下载地址+序列号
  • 原文地址:https://www.cnblogs.com/frogkiller/p/14444623.html
Copyright © 2011-2022 走看看