这份原稿.微支持PasswordBox



calburn。在http://caliburnmicro.com的微主页做出以下声明,但我无法使CM工作与PasswordBox控件使用任何变体,我可以从这个例子中想到。无论如何,不要看到这是如何工作的,因为名称不是相同的情况。有没有人有一个CM的例子,确实允许我得到密码盒的值?是否需要特定版本的CM ?我正在运行CM的1.5.2版本。理想情况下,w/o使用附加属性,但如果可以与CM和唯一的方法一起工作,那么很好。请不要讲授安全问题,因为那不是我的问题。


使用参数和保护方法在视图和视图模型之间自动应用方法

<StackPanel>
    <TextBox x:Name="Username" />
    <PasswordBox x:Name="Password" />
    <Button x:Name="Login" Content="Log in" />
</StackPanel>

public bool CanLogin(string username, string password)
{
    return !String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password);
}
public string Login(string username, string password)
{
    ...
}

这里有一个更简单的例子,包括一个绑定约定,以便在Caliburn中PasswordBox绑定。:

public static class PasswordBoxHelper
{
    public static readonly DependencyProperty BoundPasswordProperty =
        DependencyProperty.RegisterAttached("BoundPassword",
            typeof(string),
            typeof(PasswordBoxHelper),
            new FrameworkPropertyMetadata(string.Empty, OnBoundPasswordChanged));
    public static string GetBoundPassword(DependencyObject d)
    {
        var box = d as PasswordBox;
        if (box != null)
        {
            // this funny little dance here ensures that we've hooked the
            // PasswordChanged event once, and only once.
            box.PasswordChanged -= PasswordChanged;
            box.PasswordChanged += PasswordChanged;
        }
        return (string)d.GetValue(BoundPasswordProperty);
    }
    public static void SetBoundPassword(DependencyObject d, string value)
    {
        if (string.Equals(value, GetBoundPassword(d)))
            return; // and this is how we prevent infinite recursion
        d.SetValue(BoundPasswordProperty, value);
    }
    private static void OnBoundPasswordChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var box = d as PasswordBox;
        if (box == null)
            return;
        box.Password = GetBoundPassword(d);
    }
    private static void PasswordChanged(object sender, RoutedEventArgs e)
    {
        PasswordBox password = sender as PasswordBox;
        SetBoundPassword(password, password.Password);
        // set cursor past the last character in the password box
        password.GetType().GetMethod("Select", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(password, new object[] { password.Password.Length, 0 }); 
    }
}

然后,在你的bootstrapper中:

public sealed class Bootstrapper : BootstrapperBase
{
    public Bootstrapper()
    {
        Initialize();
        ConventionManager.AddElementConvention<PasswordBox>(
            PasswordBoxHelper.BoundPasswordProperty,
            "Password",
            "PasswordChanged");
    }
    // other bootstrapper stuff here
}

这里提供的解决方案似乎是不必要的复杂。

我们可以很容易地使用Caliburn。将密码发送给ViewModel的微动作。

XAML:

<PasswordBox cal:Message.Attach="[Event PasswordChanged] = [Action OnPasswordChanged($source)]" />

ViewModel:

public void OnPasswordChanged(PasswordBox source)
{
    password = source.Password;
}

然后记得清除密码字段,这样它们就不会留在内存中。

注意:显然这个解决方案不允许您轻松地从ViewModel更改密码,如果有必要,那么最好使用附加属性方法。

我只能让它与依赖属性一起工作,有效地绕过了Caliburn的约定绑定。微供应。我知道这不是你的理想,但实际上这是我经常使用的解决方案。我相信当我在历史上遇到这个障碍时,我在StackOverflow上找到了这篇文章,它把我带到了这个方向。供你方考虑:

public class BoundPasswordBox
    {
        private static bool _updating = false;
        /// <summary>
        /// BoundPassword Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty BoundPasswordProperty =
            DependencyProperty.RegisterAttached("BoundPassword",
                typeof(string),
                typeof(BoundPasswordBox),
                new FrameworkPropertyMetadata(string.Empty, OnBoundPasswordChanged));
        /// <summary>
        /// Gets the BoundPassword property.
        /// </summary>
        public static string GetBoundPassword(DependencyObject d)
        {
            return (string)d.GetValue(BoundPasswordProperty);
        }
        /// <summary>
        /// Sets the BoundPassword property.
        /// </summary>
        public static void SetBoundPassword(DependencyObject d, string value)
        {
            d.SetValue(BoundPasswordProperty, value);
        }
        /// <summary>
        /// Handles changes to the BoundPassword property.
        /// </summary>
        private static void OnBoundPasswordChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            PasswordBox password = d as PasswordBox;
            if (password != null)
            {
                // Disconnect the handler while we're updating.
                password.PasswordChanged -= PasswordChanged;
            }
            if (e.NewValue != null)
            {
                if (!_updating)
                {
                    password.Password = e.NewValue.ToString();
                }
            }
            else 
            {
                password.Password = string.Empty;
            }
            // Now, reconnect the handler.
            password.PasswordChanged += PasswordChanged;
        }
        /// <summary>
        /// Handles the password change event.
        /// </summary>
        static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox password = sender as PasswordBox;
            _updating = true;
            SetBoundPassword(password, password.Password);
            _updating = false;
        }
    }
然后,在XAML中:
<PasswordBox pwbx:BoundPasswordBox.BoundPassword="{Binding UserPassword, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnValidationError=True,ValidatesOnDataErrors=True}" />

和pwbx在Window标签上被发现是一个命名空间:

<Window x:Class="MyProject.Views.LoginView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             xmlns:pwbx="clr-namespace:MyProject.Client.Controls">

ViewModel:

using Caliburn.Micro;
using MyProject.Core;
using MyProject.Repositories;
using MyProject.Types;
using MyProject.ViewModels.Interfaces;
namespace MyProject.ViewModels
{
    public class LoginViewModel : Screen, ILoginViewModel
    {
        private readonly IWindowManager _windowManager;
        private readonly IUnitRepository _unitRepository;
        public bool IsLoginValid { get; set; }
        public Unit LoggedInUnit { get; set; }
        private string _password;
        public string UserPassword
        {
            get { return _password; }
            set
            {
                _password = value;
                NotifyOfPropertyChange(() => UserPassword);
                NotifyOfPropertyChange(() => CanLogin);
            }
        }
        private string _name;
        public string Username
        {
            get { return _name; }
            set
            {
                _name = value;
                NotifyOfPropertyChange(() => Username);
                NotifyOfPropertyChange(() => CanLogin);
            }
        }
        public LoginViewModel(IWindowManager windowManager,IUnitRepository unitRepository)
        {
            _windowManager = windowManager;
            _unitRepository = unitRepository;
            DisplayName = "MyProject - Login";
            Version = ApplicationVersionRepository.GetVersion();
        }
        public string Version { get; private set; }
        public void Login()
        {
            // Login logic
            var credentials = new UserCredentials { Username = Username, Password=UserPassword };
            var resp = _unitRepository.AuthenticateUnit(credentials);
            if (resp == null) return;
            if (resp.IsValid)
            {
                IsLoginValid = true;
                LoggedInUnit = resp.Unit;
                TryClose();
            }
            else
            {
                var dialog = new MessageBoxViewModel(DialogType.Warning, DialogButton.Ok, "Login Failed", "Login Error: " + resp.InvalidReason);
                _windowManager.ShowDialog(dialog);
            }
        }
        public bool CanLogin
        {
            get
            {
                return !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(UserPassword);
            }
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新