带有 MVVM 的密码盒

发布于 2024-07-26 21:01:18 字数 278 浏览 10 评论 0原文

大家好,stackoverflow。 我正在使用 MVVM,我有 ViewModel 使用属性密码调用 UserViewModel。 在View中有一个控件PasswordBox。

<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />

但是这个xaml不起作用。 请问怎么绑定啊?? 请帮助!!

Hi people stackoverflow. I'm working with MVVM, I have ViewModel call UserViewModel with a Property Password. In the View have a control PasswordBox.

<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />

But this xaml don't work. How do you do the binding?? Help please!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

终止放荡 2024-08-02 21:01:18

出于安全原因,Password 属性不是依赖属性,因此您无法绑定到它。 不幸的是,您需要在老式方式背后的代码中执行绑定(注册 OnPropertyChanged 事件并通过代码更新值...)


我快速搜索将我带到 此博文 展示了如何编写附加属性来回避该问题。 这是否值得做实际上取决于您对代码隐藏的厌恶。

For security reasons the Password property is not a dependency property and therefore you can't bind to it. Unfortunately you'll need to perform the binding in the code behind the old fashioned way (register for OnPropertyChanged event and update the value through code...)


I quick search brings me to this blog post which shows how to write an attached property to sidestep the issue. Whether this is worth doing or not though really depends on your aversion to code-behind.

爱*していゐ 2024-08-02 21:01:18

您始终可以编写一个包装密码并为密码属性添加依赖属性的控件。

我只会使用后面的代码,但如果你必须的话,你可以这样做:

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox));

    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }

}

You can always write a control that wraps the Password and adds a dependency property for the Password property.

I would just use code behind, but if you must you can do something like:

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox));

    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }

}
耳钉梦 2024-08-02 21:01:18

BindablePasswordBox 有问题。 它仅在一个方向上起作用,即PasswordBox 到PasswordProperty。 下面是它的修改版本,可以双向工作。 它注册一个PropertyChangedCallback并在调用时更新PasswordBox的密码。
我希望有人觉得这很有用。

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox), new PropertyMetadata(string.Empty, OnDependencyPropertyChanged));
    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    private static void OnDependencyPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        BindablePasswordBox p = source as BindablePasswordBox;
        if (p != null)
        {
            if (e.Property == PasswordProperty)
            {
                var pb = p.Child as PasswordBox;
                if (pb != null)
                {
                    if (pb.Password != p.Password)
                        pb.Password = p.Password;
                }
            }
        }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }
}

There is an issue with the BindablePasswordBox. It only works in one direction, PasswordBox to PasswordProperty. Below is a modified version of it that works in both directions. It registers a PropertyChangedCallback and updates the PasswordBox's Password when it is called.
I hope that someone finds this useful.

public class BindablePasswordBox : Decorator
{
    public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox), new PropertyMetadata(string.Empty, OnDependencyPropertyChanged));
    public string Password
    {
        get { return (string)GetValue(PasswordProperty); }
        set { SetValue(PasswordProperty, value); }
    }

    private static void OnDependencyPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        BindablePasswordBox p = source as BindablePasswordBox;
        if (p != null)
        {
            if (e.Property == PasswordProperty)
            {
                var pb = p.Child as PasswordBox;
                if (pb != null)
                {
                    if (pb.Password != p.Password)
                        pb.Password = p.Password;
                }
            }
        }
    }

    public BindablePasswordBox()
    {
        Child = new PasswordBox();
        ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged;
    }

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
    {
        Password = ((PasswordBox)Child).Password;
    }
}
梦里梦着梦中梦 2024-08-02 21:01:18

为了避免密码在任何时候以纯文本形式存在于内存中,我将该值作为参数提供给我的命令。

<Label>User Name</Label>
<TextBox Text="{Binding UserName}" />
<Label>Password</Label>
<PasswordBox Name="PasswordBox" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 16 0 0">
    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox}">
        Login
    </Button>
    <Button MinWidth="65" Command="{Binding LoginCancel}">Cancel</Button>
</StackPanel>

然后在我的视图模型中。

public DelegateCommand<object> LoginAccept { get; private set; }
public DelegateCommand<object> LoginCancel { get; private set; }

public LoginViewModel {
    LoginAccept = new DelegateCommand<object>(o => OnLogin(o), (o) => IsLoginVisible);
    LoginCancel = new DelegateCommand<object>(o => OnLoginCancel(), (o) => IsLoginVisible);
}

private void OnLogin(object o)
{
    var passwordBox = (o as System.Windows.Controls.PasswordBox);
    var password = passwordBox.SecurePassword.Copy();
    passwordBox.Clear();
    ShowLogin = false;
    var credential = new System.Net.NetworkCredential(UserName, password);
}

private void OnLoginCancel()
{
    ShowLogin = false;
}

虽然直接从绑定提供 SecurePassword 是有意义的,但它似乎总是提供空值。 所以这不起作用:

    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox, Path=SecurePassword}">

To avoid having the password available in memory as plain text at any point, I provide the value as a parameter to my command.

<Label>User Name</Label>
<TextBox Text="{Binding UserName}" />
<Label>Password</Label>
<PasswordBox Name="PasswordBox" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 16 0 0">
    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox}">
        Login
    </Button>
    <Button MinWidth="65" Command="{Binding LoginCancel}">Cancel</Button>
</StackPanel>

Then in my view model.

public DelegateCommand<object> LoginAccept { get; private set; }
public DelegateCommand<object> LoginCancel { get; private set; }

public LoginViewModel {
    LoginAccept = new DelegateCommand<object>(o => OnLogin(o), (o) => IsLoginVisible);
    LoginCancel = new DelegateCommand<object>(o => OnLoginCancel(), (o) => IsLoginVisible);
}

private void OnLogin(object o)
{
    var passwordBox = (o as System.Windows.Controls.PasswordBox);
    var password = passwordBox.SecurePassword.Copy();
    passwordBox.Clear();
    ShowLogin = false;
    var credential = new System.Net.NetworkCredential(UserName, password);
}

private void OnLoginCancel()
{
    ShowLogin = false;
}

While it would make sense to provide the SecurePassword directly from the binding, it always seems to provide an empty value. So this does NOT work:

    <Button Margin="0 0 8 0" MinWidth="65" 
            Command="{Binding LoginAccept}" 
            CommandParameter="{Binding ElementName=PasswordBox, Path=SecurePassword}">
这个俗人 2024-08-02 21:01:18

检查密码框上的另一个线程。
最好不要将密码保存在任何 DP 或公共财产上。

密码框上的其他线程

Check another thread on password box.
Its better not to keep the password on any DP or public property.

Other thread on passwordbox

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文