gpt4 book ai didi

c# - 将 SecurePassword 绑定(bind)到 ViewModel

转载 作者:行者123 更新时间:2023-11-30 22:07:22 28 4
gpt4 key购买 nike

我尝试使用自定义 BehaviorPasswordBoxSecurePassword 属性绑定(bind)到我的 ViewModel。遗憾的是它不能正常工作。

基本上,我向 Behavior 添加了一个属性,其中包含我的 ViewModel 的目标属性。

知道为什么它不起作用吗?

PS:我目前正在回家的路上,没有带笔记本电脑,我将在大约 15 分钟内用我的代码更新问题。但是,如果有人能发布想法或其他内容,那就太好了。

编辑

正如我所 promise 的,这是一些代码:)

首先是行为:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.Security;

namespace Knerd.Behaviors {
public class PasswordChangedBehavior : Behavior<PasswordBox> {

protected override void OnAttached() {
AssociatedObject.PasswordChanged += AssociatedObject_PasswordChanged;
base.OnAttached();
}

private void AssociatedObject_PasswordChanged(object sender, RoutedEventArgs e) {
if (AssociatedObject.Password != null)
TargetPassword = AssociatedObject.SecurePassword;
}

protected override void OnDetaching() {
AssociatedObject.PasswordChanged -= AssociatedObject_PasswordChanged;
base.OnDetaching();
}

public SecureString TargetPassword {
get { return (SecureString)GetValue(TargetPasswordProperty); }
set { SetValue(TargetPasswordProperty, value); }
}

// Using a DependencyProperty as the backing store for TargetPassword. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TargetPasswordProperty = DependencyProperty.Register("TargetPassword", typeof(SecureString), typeof(PasswordChangedBehavior), new PropertyMetadata(default(SecureString)));
}
}

密码框:

<PasswordBox Grid.Column="1" Grid.Row="1" Margin="5" Width="300" MinWidth="200">
<i:Interaction.Behaviors>
<behaviors:PasswordChangedBehavior TargetPassword="{Binding Password}" />
</i:Interaction.Behaviors>
</PasswordBox>

最后,我的 ViewModel 部分。

private SecureString password;

public SecureString Password {
get { return password; }
set {
if (password != value) {
password = value;
OnPropertyChanged("Password");
}
}
}

我希望任何人都可以提供帮助,atm 我使用代码隐藏版本,但我宁愿不这样做。

编辑 2

实际上不起作用的是,TargetPassword 属性不会更新我的 ViewModel

的属性

最佳答案

创建附加属性

public static class PasswordBoxAssistant
{
public static readonly DependencyProperty BoundPassword =
DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));

public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
"BindPassword", typeof (bool), typeof (PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));


private static readonly DependencyProperty UpdatingPassword =
DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false));

private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PasswordBox box = d as PasswordBox;

// only handle this event when the property is attached to a PasswordBox
// and when the BindPassword attached property has been set to true
if (d == null || !GetBindPassword(d))
{
return;
}

// avoid recursive updating by ignoring the box's changed event
box.PasswordChanged -= HandlePasswordChanged;

string newPassword = (string)e.NewValue;

if (!GetUpdatingPassword(box))
{
box.Password = newPassword;
}

box.PasswordChanged += HandlePasswordChanged;
}

private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
// when the BindPassword attached property is set on a PasswordBox,
// start listening to its PasswordChanged event

PasswordBox box = dp as PasswordBox;

if (box == null)
{
return;
}

bool wasBound = (bool)(e.OldValue);
bool needToBind = (bool)(e.NewValue);

if (wasBound)
{
box.PasswordChanged -= HandlePasswordChanged;
}

if (needToBind)
{
box.PasswordChanged += HandlePasswordChanged;
}
}

private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox box = sender as PasswordBox;

// set a flag to indicate that we're updating the password
SetUpdatingPassword(box, true);
// push the new password into the BoundPassword property
SetBoundPassword(box, box.Password);
SetUpdatingPassword(box, false);
}

public static void SetBindPassword(DependencyObject dp, bool value)
{
dp.SetValue(BindPassword, value);
}

public static bool GetBindPassword(DependencyObject dp)
{
return (bool)dp.GetValue(BindPassword);
}

public static string GetBoundPassword(DependencyObject dp)
{
return (string)dp.GetValue(BoundPassword);
}

public static void SetBoundPassword(DependencyObject dp, string value)
{
dp.SetValue(BoundPassword, value);
}

private static bool GetUpdatingPassword(DependencyObject dp)
{
return (bool)dp.GetValue(UpdatingPassword);
}

private static void SetUpdatingPassword(DependencyObject dp, bool value)
{
dp.SetValue(UpdatingPassword, value);
}
}

并且在您的 XAML

<Page xmlns:ff="clr-namespace:FunctionalFun.UI">
<!-- [Snip] -->
<PasswordBox x:Name="PasswordBox"
ff:PasswordBoxAssistant.BindPassword="true" ff:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

</Page>

你可能不想这样做,但如果你真的想继续的话。

The reason the WPF/Silverlight PasswordBox doesn't expose a DP for the Password property is security related. If WPF/Silverlight were to keep a DP for Password it would require the framework to keep the password itself unencrypted in memory. Which is considered quite a troublesome security attack vector. The PasswordBox uses encrypted memory (of sorts) and the only way to access the password is through the CLR property.

我建议在访问 PasswordBox.Password CLR 属性时,不要将它放在任何变量中或作为任何属性的值。将您的密码以明文形式保存在客户端计算机 RAM 中是安全禁忌。

SecurePassword 无法通过绑定(bind)完成。

.NET documentation explains why the PasswordBox was not made bindable in the first place.

另一种解决方案是将 PasswordBox 放入您的 ViewModelpublic class LoginViewModel

public class LoginViewModel
{
// other properties here

public PasswordBox Password
{
get { return m_passwordBox; }
}

// Executed when the Login button is clicked.
private void LoginExecute()
{
var password = Password.SecurePassword;

// do more stuff...
}
}

是的,您在这里违反了 ViewModel 最佳实践,但是

  1. 最佳做法是“在大多数情况下行之有效的建议”而不是严格的规则和
  2. 编写简单、易读、可维护的代码并避免不必要的复杂性也是那些“最佳实践”规则之一(“附加属性(property)”可能会略微违反解决方法)。

关于c# - 将 SecurePassword 绑定(bind)到 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23020163/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com