MVVM에서 PasswordBox에 바인드하는 방법
에의 바인딩에 관한 문제가 발생했습니다.PasswordBox
보안상의 위험인 것 같습니다만, MVVM 패턴을 사용하고 있기 때문에 생략하고 싶습니다.여기서 흥미로운 코드를 찾았습니다(이것이나 비슷한 것을 사용한 사람이 있습니까?)
http://www.wpftutorial.net/PasswordBox.html
기술적으로는 훌륭해 보이지만, 패스워드를 취득하는 방법을 잘 모르겠습니다.
으로 내 있다.LoginViewModel
★★★★★★에Username
★★★★★★★★★★★★★★★★★」Password
Username
정상적으로 동작하고 있습니다.TextBox
.
위의 코드를 그대로 사용하여 입력했습니다.
<PasswordBox ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>
내가 그 일을 했을 때...PasswordBox
로 TextBox
★★★★★★★★★★★★★★★★★」Binding Path=Password
내 LoginViewModel
갱신되었습니다.
내 코드는 매우 간단합니다. 기본적으로는Command
의 를 my를 위하여Button
CanLogin
하면 true를 합니다.Login
.
재산을 확인해 알 수 있습니다.Username
이치노
»Login
하러 Username
★★★★★★★★★★★★★★★★★」Password
,Username
에는 나의 .View
Password
Null|Empty
private DelegateCommand loginCommand;
public string Username { get; set; }
public string Password { get; set; }
public ICommand LoginCommand
{
get
{
if (loginCommand == null)
{
loginCommand = new DelegateCommand(
Login, CanLogin );
}
return loginCommand;
}
}
private bool CanLogin()
{
return !string.IsNullOrEmpty(Username);
}
private void Login()
{
bool result = securityService.IsValidLogin(Username, Password);
if (result) { }
else { }
}
이게 내가 하는 일이야
<TextBox Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged}"
MinWidth="180" />
<PasswordBox ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>
는 내 것을 가지고 있다.TextBox
, 이것은 문제가 되지 않습니다만, 나의 경우.ViewModel
Password
어어있있있있다다
제가 뭔가 잘못하고 있거나 한 발짝이라도 헛디딘 건가요?
것은 만, 이 .Password
집에서는ViewModel
.
뭔가 부족한 점이 있는 것 같습니다만, 이러한 솔루션의 대부분은 지나치게 복잡해지기 때문에, 시큐어한 프랙티스를 배제하고 있는 것 같습니다.
이 방법은 MVVM 패턴을 위반하지 않고 완벽한 보안을 유지합니다.네, 엄밀히 말하면 코드 배후에 있지만 '특수 케이스' 바인딩에 지나지 않습니다.View Model은 아직 View 구현에 대한 지식이 없습니다.Password Box를 View Model에 전달하려고 하면 View 구현에 대한 지식이 있습니다.
!= 자동 MVVM 위반 코드입니다.어떻게 하느냐에 따라 다르죠이 경우 바인딩을 수동으로 코딩할 뿐이므로 UI 구현의 일부로 간주되므로 문제 없습니다.
ViewModel에서는 단순한 속성입니다.어떤 이유로든 View Model 외부에서 가져올 필요가 없기 때문에 "쓰기 전용"으로 만들었지만, 그럴 필요는 없습니다.이것은 단순한 문자열이 아니라 SecureString임을 주의해 주십시오.
public SecureString SecurePassword { private get; set; }
xaml에서 Password Changed 이벤트핸들러를 설정합니다.
<PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/>
뒤에 있는 코드:
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((dynamic)this.DataContext).SecurePassword = ((PasswordBox)sender).SecurePassword; }
}
이 방법을 사용하면 패스워드는 항상 SecureString 내에 유지되므로 보안이 최대한 확보됩니다.보안에 관심이 없거나 보안이 필요한 다운스트림 방식의 클리어 텍스트비밀번호가 필요한 경우(주: 대부분의 경우).패스워드가 필요한 NET 메서드에서는 SecureString 옵션도 지원되므로 클리어 텍스트비밀번호는 필요하지 않을 수 있습니다). 대신 Password 속성을 사용할 수 있습니다.다음과 같이 합니다.
(ViewModel 속성)
public string Password { private get; set; }
(코드 이면)
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((dynamic)this.DataContext).Password = ((PasswordBox)sender).Password; }
}
강하게 타이핑하고 싶은 경우는, (다이나믹) 캐스트를 ViewModel 의 인터페이스로 대체할 수 있습니다.그러나 실제로 "일반" 데이터 바인딩도 강력한 유형이 아니기 때문에 크게 문제가 되지 않습니다.
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((IMyViewModel)this.DataContext).Password = ((PasswordBox)sender).Password; }
}
가장 좋은 점은 패스워드는 안전하고 View Model은 다른 속성과 같은 속성을 가지며 View는 외부 참조가 필요 없다는 것입니다.
나의 2센트:
WPF와 MVVM을 사용하여 일반적인 로그인 대화상자(사용자 및 비밀번호 상자, "확인" 버튼)를 개발한 적이 있습니다.Password Box 컨트롤 자체를 "OK" 버튼에 첨부된 명령어에 파라미터로 전달하기만 하면 패스워드 바인딩 문제를 해결할 수 있습니다.그래서 저는 다음과 같이 생각했습니다.
<PasswordBox Name="txtPassword" VerticalAlignment="Top" Width="120" />
<Button Content="Ok" Command="{Binding Path=OkCommand}"
CommandParameter="{Binding ElementName=txtPassword}"/>
Model 、 View Model 。Execute
첨부된 명령어의 방법은 다음과 같습니다.
void Execute(object parameter)
{
var passwordBox = parameter as PasswordBox;
var password = passwordBox.Password;
//Now go ahead and check the user name and password
}
View Model은 View 구현 방법에 대해 어느 정도 알고 있기 때문에 MVVM 패턴에 약간 위배됩니다. 하지만 이 특정 프로젝트에서는 비용을 감당할 수 있었습니다.그것이 누군가에게 유용하기를 바랍니다.
미안한데, 네가 잘못하고 있어.
눈꺼풀 안쪽에 다음과 같은 보안 지침을 문신해야 합니다.
일반 텍스트 암호를 메모리에 보관하지 마십시오.
WPF/Silverlight의 PasswordBox
.Password
속성은 보안과 관련되어 있습니다.
를 WPF/Silverlight용으로 를 Password
패스워드 자체를 메모리에 암호화하지 않고 유지하는 프레임워크가 필요합니다.상당히 골치 아픈 보안 공격 벡터로 간주됩니다.PasswordBox
는 암호화된 메모리(종류)를 사용합니다.패스워드에 액세스 하는 유일한 방법은 CLR 속성을 사용하는 것입니다.
PasswordBox.Password
CLR 속성은 변수에 배치하거나 속성의 값으로 배치하지 않습니다.
클라이언트 머신의 RAM에 패스워드를 플레인텍스트로 유지하는 것은 보안상 금지입니다.
그거 .public string Password { get; set; }
저 위에 있어요.
할 때PasswordBox.Password
가능한 한 빨리 꺼내서 서버로 보내 주세요.패스워드의 값을 주변에 두지 말아 주세요.또, 다른 클라이언트 머신 텍스트와 같이 취급하지 말아 주세요.클리어 텍스트 비밀번호를 메모리에 보관하지 마십시오.
으로 MVVM 것은 , MVVM의 패턴, MVVM의 패턴, MVVM의 패턴에 할 수 PasswordBox.Password
첨부된 DP는 ViewModel 또는 기타 유사한 셰니건에 비밀번호를 저장합니다.
오버아키텍트 솔루션을 찾고 있는 경우는, 다음과 같습니다.
. 1. 을 작성합니다.IHavePassword
패스워드 클리어 텍스트를 반환하는1개의 메서드와 인터페이스합니다.
2개 . 고객님의UserControl
IHavePassword
인터페이스입니다.
3을 합니다.UserControl
하고 있는 IHavePassword
인터페이스입니다.
하는 서버 합니다.4 . c에 、 IoC 。IHavePassword
매우 탐나는 패스워드를 취득하는 것 이외에는 없습니다.
그냥 내 생각일 뿐이야
-- 저스틴
다음 XAML을 사용할 수 있습니다.
<PasswordBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PasswordBox}}" CommandParameter="{Binding ElementName=PasswordBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
이 명령어 실행 방식은 다음과 같습니다.
private void ExecutePasswordChangedCommand(PasswordBox obj)
{
if (obj != null)
Password = obj.Password;
}
를 는 " " " 를 추가해야 합니다.System.Windows.Interactivity
에 할 수 .xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
.
나는 다양한 해결책을 찾는데 많은 시간을 보냈다.데코레이터의 아이디어가 마음에 들지 않았고, 행동이 검증 UI를 엉망으로 만들고, 코드 배후에...정말?
을 고수하고 의 어태치드 입니다.SecureString
뷰 모델에서 속성을 선택합니다.가능한 한 오래 저 안에 두세요.일반 암호에 빠르게 액세스해야 할 때마다 다음 코드를 사용하여 암호를 일시적으로 안전하지 않은 문자열로 변환하십시오.
namespace Namespace.Extensions
{
using System;
using System.Runtime.InteropServices;
using System.Security;
/// <summary>
/// Provides unsafe temporary operations on secured strings.
/// </summary>
[SuppressUnmanagedCodeSecurity]
public static class SecureStringExtensions
{
/// <summary>
/// Converts a secured string to an unsecured string.
/// </summary>
public static string ToUnsecuredString(this SecureString secureString)
{
// copy&paste from the internal System.Net.UnsafeNclNativeMethods
IntPtr bstrPtr = IntPtr.Zero;
if (secureString != null)
{
if (secureString.Length != 0)
{
try
{
bstrPtr = Marshal.SecureStringToBSTR(secureString);
return Marshal.PtrToStringBSTR(bstrPtr);
}
finally
{
if (bstrPtr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstrPtr);
}
}
}
return string.Empty;
}
/// <summary>
/// Copies the existing instance of a secure string into the destination, clearing the destination beforehand.
/// </summary>
public static void CopyInto(this SecureString source, SecureString destination)
{
destination.Clear();
foreach (var chr in source.ToUnsecuredString())
{
destination.AppendChar(chr);
}
}
/// <summary>
/// Converts an unsecured string to a secured string.
/// </summary>
public static SecureString ToSecuredString(this string plainString)
{
if (string.IsNullOrEmpty(plainString))
{
return new SecureString();
}
SecureString secure = new SecureString();
foreach (char c in plainString)
{
secure.AppendChar(c);
}
return secure;
}
}
}
수 해야 GC 를 사용하는 .GC의 경우PasswordChanged
의 PasswordBox
, 이 UI를 UI를 않은 SecurePassword
, 를 에 하는 이유, 패스워드를하는 이유Password
★★★★★★ 。
namespace Namespace.Controls
{
using System.Security;
using System.Windows;
using System.Windows.Controls;
using Namespace.Extensions;
/// <summary>
/// Creates a bindable attached property for the <see cref="PasswordBox.SecurePassword"/> property.
/// </summary>
public static class PasswordBoxHelper
{
// an attached behavior won't work due to view model validation not picking up the right control to adorn
public static readonly DependencyProperty SecurePasswordBindingProperty = DependencyProperty.RegisterAttached(
"SecurePassword",
typeof(SecureString),
typeof(PasswordBoxHelper),
new FrameworkPropertyMetadata(new SecureString(),FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AttachedPropertyValueChanged)
);
private static readonly DependencyProperty _passwordBindingMarshallerProperty = DependencyProperty.RegisterAttached(
"PasswordBindingMarshaller",
typeof(PasswordBindingMarshaller),
typeof(PasswordBoxHelper),
new PropertyMetadata()
);
public static void SetSecurePassword(PasswordBox element, SecureString secureString)
{
element.SetValue(SecurePasswordBindingProperty, secureString);
}
public static SecureString GetSecurePassword(PasswordBox element)
{
return element.GetValue(SecurePasswordBindingProperty) as SecureString;
}
private static void AttachedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// we'll need to hook up to one of the element's events
// in order to allow the GC to collect the control, we'll wrap the event handler inside an object living in an attached property
// don't be tempted to use the Unloaded event as that will be fired even when the control is still alive and well (e.g. switching tabs in a tab control)
var passwordBox = (PasswordBox)d;
var bindingMarshaller = passwordBox.GetValue(_passwordBindingMarshallerProperty) as PasswordBindingMarshaller;
if (bindingMarshaller == null)
{
bindingMarshaller = new PasswordBindingMarshaller(passwordBox);
passwordBox.SetValue(_passwordBindingMarshallerProperty, bindingMarshaller);
}
bindingMarshaller.UpdatePasswordBox(e.NewValue as SecureString);
}
/// <summary>
/// Encapsulated event logic
/// </summary>
private class PasswordBindingMarshaller
{
private readonly PasswordBox _passwordBox;
private bool _isMarshalling;
public PasswordBindingMarshaller(PasswordBox passwordBox)
{
_passwordBox = passwordBox;
_passwordBox.PasswordChanged += this.PasswordBoxPasswordChanged;
}
public void UpdatePasswordBox(SecureString newPassword)
{
if (_isMarshalling)
{
return;
}
_isMarshalling = true;
try
{
// setting up the SecuredPassword won't trigger a visual update so we'll have to use the Password property
_passwordBox.Password = newPassword.ToUnsecuredString();
// you may try the statement below, however the benefits are minimal security wise (you still have to extract the unsecured password for copying)
//newPassword.CopyInto(_passwordBox.SecurePassword);
}
finally
{
_isMarshalling = false;
}
}
private void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
{
// copy the password into the attached property
if (_isMarshalling)
{
return;
}
_isMarshalling = true;
try
{
SetSecurePassword(_passwordBox, _passwordBox.SecurePassword.Copy());
}
finally
{
_isMarshalling = false;
}
}
}
}
}
XAML 사용방법:
<PasswordBox controls:PasswordBoxHelper.SecurePassword="{Binding LogonPassword, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
뷰 모델의 내 속성은 다음과 같습니다.
[RequiredSecureString]
public SecureString LogonPassword
{
get
{
return _logonPassword;
}
set
{
_logonPassword = value;
NotifyPropertyChanged(nameof(LogonPassword));
}
}
RequiredSecureString
한 커스텀 .
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class RequiredSecureStringAttribute:ValidationAttribute
{
public RequiredSecureStringAttribute()
:base("Field is required")
{
}
public override bool IsValid(object value)
{
return (value as SecureString)?.Length > 0;
}
}
여기 있습니다.완전하고 테스트된 순수 MVVM 솔루션.
이건 나한테 딱 맞아.
<Button Command="{Binding Connect}"
CommandParameter="{Binding ElementName=MyPasswordBox}"/>
MVVM 패턴을 위반하지 않는 간단한 해결책은 암호를 수집하는 이벤트(또는 위임)를 ViewModel에 도입하는 것입니다.
View Model에서:
public event EventHandler<HarvestPasswordEventArgs> HarvestPassword;
다음 EventArgs를 사용합니다.
class HarvestPasswordEventArgs : EventArgs
{
public string Password;
}
View에서 ViewModel 생성 시 이벤트를 구독하고 암호 값을 입력합니다.
_viewModel.HarvestPassword += (sender, args) =>
args.Password = passwordBox1.Password;
ViewModel에서는 패스워드가 필요할 때 이벤트를 기동하여 패스워드를 수집할 수 있습니다.
if (HarvestPassword == null)
//bah
return;
var pwargs = new HarvestPasswordEventArgs();
HarvestPassword(this, pwargs);
LoginHelpers.Login(Username, pwargs.Password);
MVVM을 중단하지 않고 OP 문제를 해결하려면 사용자 지정 값 변환기와 암호 상자에서 검색해야 하는 값(패스워드)의 래퍼를 사용합니다.
public interface IWrappedParameter<T>
{
T Value { get; }
}
public class PasswordBoxWrapper : IWrappedParameter<string>
{
private readonly PasswordBox _source;
public string Value
{
get { return _source != null ? _source.Password : string.Empty; }
}
public PasswordBoxWrapper(PasswordBox source)
{
_source = source;
}
}
public class PasswordBoxConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Implement type and value check here...
return new PasswordBoxWrapper((PasswordBox)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("No conversion.");
}
}
뷰 모델:
public string Username { get; set; }
public ICommand LoginCommand
{
get
{
return new RelayCommand<IWrappedParameter<string>>(password => { Login(Username, password); });
}
}
private void Login(string username, string password)
{
// Perform login here...
}
에서는 ★★★★★★★★★★★★★★★★★★★★」IWrappedParameter<T>
에 대한 됩니다.PasswordBoxWrapper
않다PasswordBoxConverter
, 「」, 「」를 분리할 수 PasswordBox
MVVM을 사용합니다.
보기:
<Window.Resources>
<h:PasswordBoxConverter x:Key="PwdConverter" />
</Window.Resources>
...
<PasswordBox Name="PwdBox" />
<Button Content="Login" Command="{Binding LoginCommand}"
CommandParameter="{Binding ElementName=PwdBox, Converter={StaticResource PwdConverter}}" />
여기에 GIST를 올렸습니다.그것은 바인딩 가능한 패스워드 박스입니다.
using System.Windows;
using System.Windows.Controls;
namespace CustomControl
{
public class BindablePasswordBox : Decorator
{
/// <summary>
/// The password dependency property.
/// </summary>
public static readonly DependencyProperty PasswordProperty;
private bool isPreventCallback;
private RoutedEventHandler savedCallback;
/// <summary>
/// Static constructor to initialize the dependency properties.
/// </summary>
static BindablePasswordBox()
{
PasswordProperty = DependencyProperty.Register(
"Password",
typeof(string),
typeof(BindablePasswordBox),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnPasswordPropertyChanged))
);
}
/// <summary>
/// Saves the password changed callback and sets the child element to the password box.
/// </summary>
public BindablePasswordBox()
{
savedCallback = HandlePasswordChanged;
PasswordBox passwordBox = new PasswordBox();
passwordBox.PasswordChanged += savedCallback;
Child = passwordBox;
}
/// <summary>
/// The password dependency property.
/// </summary>
public string Password
{
get { return GetValue(PasswordProperty) as string; }
set { SetValue(PasswordProperty, value); }
}
/// <summary>
/// Handles changes to the password dependency property.
/// </summary>
/// <param name="d">the dependency object</param>
/// <param name="eventArgs">the event args</param>
private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs)
{
BindablePasswordBox bindablePasswordBox = (BindablePasswordBox) d;
PasswordBox passwordBox = (PasswordBox) bindablePasswordBox.Child;
if (bindablePasswordBox.isPreventCallback)
{
return;
}
passwordBox.PasswordChanged -= bindablePasswordBox.savedCallback;
passwordBox.Password = (eventArgs.NewValue != null) ? eventArgs.NewValue.ToString() : "";
passwordBox.PasswordChanged += bindablePasswordBox.savedCallback;
}
/// <summary>
/// Handles the password changed event.
/// </summary>
/// <param name="sender">the sender</param>
/// <param name="eventArgs">the event args</param>
private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs)
{
PasswordBox passwordBox = (PasswordBox) sender;
isPreventCallback = true;
Password = passwordBox.Password;
isPreventCallback = false;
}
}
}
이 실장은 약간 다릅니다.입니다.PasswordBox
View Model 속성의 바인딩을 통해 View로 이동합니다.명령어 매개 변수를 사용하지 않습니다.View Model은 View를 인식하지 않습니다.SkyDrive에서 다운로드할 수 있는 VB VS 2010 프로젝트가 있습니다.WPF MVVM PassWordBox의 예지퍼
가 사용하고 PasswordBox
WPF MVVM 어플리케이션의 경우 매우 심플하고, 나에게도 잘 동작합니다.
으로는 공개를 .readonly
가 로 수 PasswordBox
「」
Private _thePassWordBox As PasswordBox
Public ReadOnly Property ThePassWordBox As PasswordBox
Get
If IsNothing(_thePassWordBox) Then _thePassWordBox = New PasswordBox
Return _thePassWordBox
End Get
End Property
자산의 자동 초기화를 수행하기 위해서만 backing 필드를 사용합니다.
그런 다음 Xaml에서 ContentControl 또는 Control Container의 내용을 바인딩합니다.
<ContentControl Grid.Column="1" Grid.Row="1" Height="23" Width="120" Content="{Binding Path=ThePassWordBox}" HorizontalAlignment="Center" VerticalAlignment="Center" />
여기서 Password Box를 완전히 제어할 수 있습니다.또한 로그인 시 또는 비밀번호가 필요한 경우 비밀번호 값을 반환하기 위해 PasswordAccessor(String의 함수일 뿐)를 사용합니다.이 예에서는 Generic User Object Model에 공용 속성이 있습니다.예:
Public Property PasswordAccessor() As Func(Of String)
은 "비밀번호"입니다.readonly
.Password Box(비밀번호) Password(비밀번호)§:
Public ReadOnly Property PassWord As String
Get
Return If((PasswordAccessor Is Nothing), String.Empty, PasswordAccessor.Invoke())
End Get
End Property
그런 다음 ViewModel에서 Accessor가 생성되고 PasswordBox로 설정되어 있는지 확인합니다.암호 속성:
Public Sub New()
'Sets the Accessor for the Password Property
SetPasswordAccessor(Function() ThePassWordBox.Password)
End Sub
Friend Sub SetPasswordAccessor(ByVal accessor As Func(Of String))
If Not IsNothing(VMUser) Then VMUser.PasswordAccessor = accessor
End Sub
Password 문자열 say for login이 필요한 경우 User Objects Password 속성을 얻으면 실제로 User Objects에 의해 비밀번호가 저장되지 않습니다.예: View Model에 있습니다.
Private Function LogIn() as Boolean
'Make call to your Authentication methods and or functions. I usally place that code in the Model
Return AuthenticationManager.Login(New UserIdentity(User.UserName, User.Password)
End Function
그 정도면 됐다.ViewModel에는 View의 컨트롤에 대한 지식이 필요하지 않습니다.View는 ViewModel의 속성에만 바인딩되며 이미지 또는 다른 리소스에 대한 View 바인딩과 다르지 않습니다.이 경우 리소스(프로퍼티)는 사용자 제어가 됩니다.ViewModel이 속성을 만들고 소유하며 속성이 View와 독립적이기 때문에 테스트를 수행할 수 있습니다.보안에 대해서는 이 구현이 얼마나 좋은지 모르겠습니다.그러나 함수를 사용하면 값이 속성에서 방금 액세스한 속성 자체에 저장되지 않습니다.
패스워드를 어디에 저장하지 않는 것도 중요하지만 뷰 없이 뷰 모델을 인스턴스화하고 이에 대한 테스트를 실행할 수 있는 기능이 필요합니다.
저에게 효과가 있었던 솔루션은 Password Box를 등록하는 것이었습니다.패스워드는 뷰 모델에서 기능하며, 로그인 코드를 실행할 때 뷰 모델이 이 패스워드를 호출하도록 합니다.
이는 보기의 코드 뒤에 있는 코드 줄을 의미합니다.
그래서 Login.xaml에는
<PasswordBox x:Name="PasswordBox"/>
Login.xaml.cs에는
LoginViewModel.PasswordHandler = () => PasswordBox.Password;
LoginViewModel.cs에서 PasswordHandler가 정의되어 있습니다.
public Func<string> PasswordHandler { get; set; }
로그인이 필요한 경우 코드는 핸들러를 호출하여 뷰에서 비밀번호를 가져옵니다.
bool loginResult = Login(Username, PasswordHandler());
이렇게 하면 뷰 모델을 테스트할 때 비밀번호 핸들러를 익명 방식으로 설정하면 테스트에서 사용할 비밀번호를 모두 전달할 수 있습니다.
난 내 해결책을 혼란에 빠뜨려야겠다고 생각했어. 이건 너무 흔한 문제니까...선택의 폭이 넓다는 것은 항상 좋은 일입니다.
했습니다.PasswordBox
in a a a a UserControl
'이행하다'DependencyProperty
결속할 수 있게 됩니다.을 다하고 때문에 은 선명한 텍스트가 에 저장되지 않도록 하고 있습니다.그래서 모든 것은 다음 명령을 통해 이루어집니다.SecureString
및PasswordBox.Password
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★중foreach
루프, 각 캐릭터가 노출되긴 하지만 아주 짧습니다.솔직히 WPF 애플리케이션이 이 짧은 노출로 인해 손상될 우려가 있다면 처리해야 할 더 큰 보안 문제가 있습니다.
입니다.MVVM 은 '입니다.MVVM은 '순수'이기 입니다.UserControl
코드 배후에 사용할 수 있습니다.할 때,을 할 수.View
★★★★★★★★★★★★★★★★★」ViewModel
너의 withoutVideModel
의 어느 하고 있는 것View
츠미야해 주세요.SecureString
안에서ViewModel
.
Bindable Password Box.xaml
<UserControl x:Class="BK.WPF.CustomControls.BindanblePasswordBox"
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" d:DesignHeight="22" d:DesignWidth="150">
<PasswordBox x:Name="PswdBox"/>
</UserControl>
BindablePasswordBox.xaml.cs (버전1 - 양방향 바인딩 지원 없음)
using System.ComponentModel;
using System.Security;
using System.Windows;
using System.Windows.Controls;
namespace BK.WPF.CustomControls
{
public partial class BindanblePasswordBox : UserControl
{
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(SecureString), typeof(BindanblePasswordBox));
public SecureString Password
{
get { return (SecureString)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public BindanblePasswordBox()
{
InitializeComponent();
PswdBox.PasswordChanged += PswdBox_PasswordChanged;
}
private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e)
{
var secure = new SecureString();
foreach (var c in PswdBox.Password)
{
secure.AppendChar(c);
}
Password = secure;
}
}
}
버전 1의 사용방법:
<local:BindanblePasswordBox Width="150" HorizontalAlignment="Center"
VerticalAlignment="Center"
Password="{Binding Password, Mode=OneWayToSource}"/>
BindablePasswordBox.xaml.cs (버전2 - 양방향 바인딩 지원)
public partial class BindablePasswordBox : UserControl
{
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(SecureString), typeof(BindablePasswordBox),
new PropertyMetadata(PasswordChanged));
public SecureString Password
{
get { return (SecureString)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public BindablePasswordBox()
{
InitializeComponent();
PswdBox.PasswordChanged += PswdBox_PasswordChanged;
}
private void PswdBox_PasswordChanged(object sender, RoutedEventArgs e)
{
var secure = new SecureString();
foreach (var c in PswdBox.Password)
{
secure.AppendChar(c);
}
if (Password != secure)
{
Password = secure;
}
}
private static void PasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var pswdBox = d as BindablePasswordBox;
if (pswdBox != null && e.NewValue != e.OldValue)
{
var newValue = e.NewValue as SecureString;
if (newValue == null)
{
return;
}
var unmanagedString = IntPtr.Zero;
string newString;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(newValue);
newString = Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
var currentValue = pswdBox.PswdBox.Password;
if (currentValue != newString)
{
pswdBox.PswdBox.Password = newString;
}
}
}
}
버전 2의 사용방법:
<local:BindanblePasswordBox Width="150" HorizontalAlignment="Center"
VerticalAlignment="Center"
Password="{Binding Password, Mode=TwoWay}"/>
나에게는 이 두 가지가 모두 잘못되었다고 생각한다.
- 일반 텍스트 암호 속성 구현
- 의
PasswordBox
ViewModelViewModel합니다.
CO의 Steve에 의해 기술된 SecurePassword(SecureString 인스턴스)의 전송은 허용됩니다.나는 더 좋다Behaviors
또한 뷰 모델에서 비밀번호를 재설정할 수 있어야 한다는 추가 요구 사항도 있었습니다.
Xaml)Password
속성 : View Model "View Model" (모델 표시)
<PasswordBox>
<i:Interaction.Behaviors>
<behaviors:PasswordBinding BoundPassword="{Binding Password, Mode=TwoWay}" />
</i:Interaction.Behaviors>
</PasswordBox>
동작:
using System.Security;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace Evidence.OutlookIntegration.AddinLogic.Behaviors
{
/// <summary>
/// Intermediate class that handles password box binding (which is not possible directly).
/// </summary>
public class PasswordBoxBindingBehavior : Behavior<PasswordBox>
{
// BoundPassword
public SecureString BoundPassword { get { return (SecureString)GetValue(BoundPasswordProperty); } set { SetValue(BoundPasswordProperty, value); } }
public static readonly DependencyProperty BoundPasswordProperty = DependencyProperty.Register("BoundPassword", typeof(SecureString), typeof(PasswordBoxBindingBehavior), new FrameworkPropertyMetadata(OnBoundPasswordChanged));
protected override void OnAttached()
{
this.AssociatedObject.PasswordChanged += AssociatedObjectOnPasswordChanged;
base.OnAttached();
}
/// <summary>
/// Link up the intermediate SecureString (BoundPassword) to the UI instance
/// </summary>
private void AssociatedObjectOnPasswordChanged(object s, RoutedEventArgs e)
{
this.BoundPassword = this.AssociatedObject.SecurePassword;
}
/// <summary>
/// Reacts to password reset on viewmodel (ViewModel.Password = new SecureString())
/// </summary>
private static void OnBoundPasswordChanged(object s, DependencyPropertyChangedEventArgs e)
{
var box = ((PasswordBoxBindingBehavior)s).AssociatedObject;
if (box != null)
{
if (((SecureString)e.NewValue).Length == 0)
box.Password = string.Empty;
}
}
}
}
부속된 자산으로 할 수 있습니다. 보세요.MVVM을 사용한 Password Box
이 방법을 사용하여 패스워드 박스를 전달했습니다만, MVVM에 위반되는 것은 아니지만, 복잡한 셸 환경인 셸 내에서 로그인을 위해 데이터 템플릿과 함께 콘텐츠 제어를 사용하고 있었기 때문에 필수가 되었습니다.그럼 껍데기 뒤에 있는 코드에 접속하는 건 쓰레기였을 거야
패스워드 박스를 건네주는 것은 코드 배후에 있는 액세스 제어와 같은 것이라고 생각합니다.비밀번호에 동의합니다.메모리에 보관하지 마십시오.이 구현에서는 뷰 모델에 비밀번호 속성이 없습니다.
버튼 명령어
Command="{Binding Path=DataContext.LoginCommand, ElementName=MyShell}" CommandParameter="{Binding ElementName=PasswordBox}"
뷰 모델
private void Login(object parameter)
{
System.Windows.Controls.PasswordBox p = (System.Windows.Controls.PasswordBox)parameter;
MessageBox.Show(p.Password);
}
저같은 이 여기 Konamiman
잘부탁드립니다.Konamiman
.
XAML
<PasswordBox x:Name="textBoxPassword"/>
<Button x:Name="buttonLogin" Content="Login"
Command="{Binding PasswordCommand}"
CommandParameter="{Binding ElementName=textBoxPassword}"/>
뷰 모델
public class YourViewModel : ViewModelBase
{
private ICommand _passwordCommand;
public ICommand PasswordCommand
{
get {
if (_passwordCommand == null) {
_passwordCommand = new RelayCommand<object>(PasswordClick);
}
return _passwordCommand;
}
}
public YourViewModel()
{
}
private void PasswordClick(object p)
{
var password = p as PasswordBox;
Console.WriteLine("Password is: {0}", password.Password);
}
}
SecureString
and Attached Behavior를 하여 뷰 합니다.ICommand
MVVM을 구현할 때 코드 배후에 문제가 없습니다.MVVM은 모델/비즈니스 로직에서 뷰를 분리하는 것을 목적으로 하는 아키텍처 패턴입니다.MVVM은 재현 가능한 방법으로 이 목표를 달성하는 방법을 설명합니다.뷰를 어떻게 구성하거나 구현하는지와 같은 구현 세부 사항에는 관심이 없습니다.이 패턴의 용어 관점에서 뷰, 뷰 모델 및 모델을 정의하고 경계를 그립니다.
C나 컴파일러MVVM)는 신경 partial
에 하지 않는 .언어에 의존하지 않는 것은 디자인 패턴의 필수 특성입니다.언어 중립이어야 합니다.
XAML과 C 사이에 등몇.그러나 C#에서 UI 로직이나 템플릿, 스타일, 트리거, 애니메이션 등의 오브젝트를 구현하는 가장 중요한 방법은 XAML을 사용하는 것보다 매우 복잡하고 읽기 어렵거나 읽기 어려운 것입니다.XAML은 태그와 네스트를 사용하여 오브젝트 계층을 시각화하는 마크업 언어입니다.XAML UI를 사용합니다.다만, C#(또는 코드 배후에 있는)에 UI 로직을 실장하는 것을 선택해도 문제가 없는 상황이 있습니다.의 취급PasswordBox
예를 들어 보겠습니다.
이 에, 「」의 을 합니다.PasswordBox
code-behind(코드-behind)를 (코드-behind)에서PasswordBox.PasswordChanged
MVVM을 사용합니다.
를 넘기다.PasswordBox
를 참조해 주세요. 많은 에서 이를 하고 있습니다. 예를 들어, 입니다.★★★★★★★★★★★★☆PasswordBox
as ~하듯이ICommand.CommandParameter
모델을 봅니다.뷰 모델로 이동합니다.분명히 매우 나쁘고 불필요한 권장 사항입니다.분명히 매우 나쁘고 불필요한 추천이다.
C#을 사용하는 것은 상관없지만 코드 이면 파일을 깨끗하게 유지하고 싶은 경우 또는 단순히 동작을 캡슐화하고 싶은 경우/UI 로직은 언제든지 연결된 속성을 사용하고 연결된 동작을 구현할 수 있습니다.
작 text 명 and bad anti security- risk behavior usespattern to), an수할스 에 스 악 이 이 드 서 은 opposed of wide있동와바드높ICommand
to send the password as 패스워드를 송신하다SecureString
to the view model, whenever the 뷰 모델로의 이행은 항상PasswordBox
을 올리다PasswordBox.PasswordChanged
Main Window.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<PasswordBox PasswordBox.Command="{Binding VerifyPasswordCommand}" />
</Window>
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
public ICommand VerifyPasswordCommand => new RelayCommand(VerifyPassword);
public void VerifyPassword(object commadParameter)
{
if (commandParameter is SecureString secureString)
{
IntPtr valuePtr = IntPtr.Zero;
try
{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
string plainTextPassword = Marshal.PtrToStringUni(valuePtr);
// Handle plain text password.
// It's recommended to convert the SecureString to plain text in the model, when really needed.
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
}
}
PasswordBox.cs
// Attached behavior
class PasswordBox : DependencyObject
{
#region Command attached property
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached(
"Command",
typeof(ICommand),
typeof(PasswordBox),
new PropertyMetadata(default(ICommand), PasswordBox.OnSendPasswordCommandChanged));
public static void SetCommand(DependencyObject attachingElement, ICommand value) =>
attachingElement.SetValue(PasswordBox.CommandProperty, value);
public static ICommand GetCommand(DependencyObject attachingElement) =>
(ICommand) attachingElement.GetValue(PasswordBox.CommandProperty);
#endregion
private static void OnSendPasswordCommandChanged(
DependencyObject attachingElement,
DependencyPropertyChangedEventArgs e)
{
if (!(attachingElement is System.Windows.Controls.PasswordBox passwordBox))
{
throw new ArgumentException("Attaching element must be of type 'PasswordBox'");
}
if (e.OldValue != null)
{
return;
}
WeakEventManager<object, RoutedEventArgs>.AddHandler(
passwordBox,
nameof(System.Windows.Controls.PasswordBox.PasswordChanged),
SendPassword_OnPasswordChanged);
}
private static void SendPassword_OnPasswordChanged(object sender, RoutedEventArgs e)
{
var attachedElement = sender as System.Windows.Controls.PasswordBox;
SecureString commandParameter = attachedElement?.SecurePassword;
if (commandParameter == null || commandParameter.Length < 1)
{
return;
}
ICommand sendCommand = GetCommand(attachedElement);
sendCommand?.Execute(commandParameter);
}
}
보시다시피 패스워드에 바인드 되어 있습니다만, 스태틱클래스에 바인드 되어 있을 가능성이 있습니다.
부속 재산입니다.이러한 종류의 속성은 모든 종류의 시스템에 적용될 수 있습니다.DependencyObject
선언된 유형뿐만이 아닙니다. 에, 에 만,PasswordHelper
클래스, 「」에 됩니다.PasswordBox
사용할 수 있습니다.
붙어있는 속성을 하려면 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,Password
[ : [ ]의 속성을 지정합니다.
<PasswordBox w:PasswordHelper.Attach="True"
w:PasswordHelper.Password="{Binding Password}"/>
앞서 설명한 바와 같이 VM은 View를 인식하지 않아야 하지만 PasswordBox 전체를 전달하는 것은 가장 간단한 접근 방식처럼 보입니다.따라서 패스된 파라미터를 PasswordBox에 캐스팅하는 대신 Reflection을 사용하여 Password 속성을 추출할 수 있습니다.이 경우 VM은 속성 암호가 포함된 일종의 암호 컨테이너가 필요합니다(MVMM Light-Toolkit에서 Relay Commands를 사용하고 있습니다).
public RelayCommand<object> SignIn
{
get
{
if (this.signIn == null)
{
this.signIn = new RelayCommand<object>((passwordContainer) =>
{
var password = passwordContainer.GetType().GetProperty("Password").GetValue(passwordContainer) as string;
this.authenticationService.Authenticate(this.Login, password);
});
}
return this.signIn;
}
}
익명의 클래스로 간단하게 테스트할 수 있습니다.
var passwordContainer = new
{
Password = "password"
};
WAF(WordBox) 프로젝트의 ViewModel 샘플 응용 프로그램에서 암호 상자에 대한 솔루션을 찾을 수 있습니다.
하지만 저스틴이 옳다.View와 ViewModel 사이에 일반 텍스트로 암호를 전달하지 마십시오.대신 SecureString을 사용합니다(MSDN PasswordBox 참조).
나는 다음과 같이 했다.
XAML:
<PasswordBox x:Name="NewPassword" PasswordChanged="NewPassword_PasswordChanged"/>
<!--change tablenameViewSource: yours!-->
<Grid DataContext="{StaticResource tablenameViewSource}" Visibility="Hidden">
<TextBox x:Name="Password" Text="{Binding password, Mode=TwoWay}"/>
</Grid>
C#:
private void NewPassword_PasswordChanged(object sender, RoutedEventArgs e)
{
try
{
//change tablenameDataTable: yours! and tablenameViewSource: yours!
tablenameDataTable.Rows[tablenameViewSource.View.CurrentPosition]["password"] = NewPassword.Password;
}
catch
{
this.Password.Text = this.NewPassword.Password;
}
}
나에게는 그게 효과가 있어요!
데이터 클래스에 패스워드를 쓰기 위해서, 인증 체크에 이어, 중개 클래스에 의해서 View(인증 체크도 실장)에 호출된 서브를 사용했습니다.
완벽한 솔루션은 아니지만 패스워드를 이동할 수 없는 문제를 해결했습니다.
저는 아직 언급되지 않은 간결한 MVVM 친화적인 솔루션을 사용하고 있습니다.먼저 XAML의 Password Box에 이름을 붙입니다.
<PasswordBox x:Name="Password" />
그런 다음 뷰 생성자에 단일 메서드 호출을 추가합니다.
public LoginWindow()
{
InitializeComponent();
ExposeControl<LoginViewModel>.Expose(this, view => view.Password,
(model, box) => model.SetPasswordBox(box));
}
그리고 이것이 마지막입니다.뷰 모델은 DataContext를 통해 뷰에 연결되면 알림을 받고, 분리되면 다른 알림을 받습니다.이 알림의 내용은 람다를 통해 구성할 수 있지만 일반적으로 뷰 모델에 대한 설정자 또는 메서드 호출일 뿐이며 문제가 있는 컨트롤을 매개 변수로 전달합니다.
뷰에서 하위 컨트롤 대신 인터페이스를 노출시킴으로써 MVVM 친화적으로 만들 수 있습니다.
위의 코드는 제 블로그에 게시된 도우미 클래스에 의존합니다.
난 이걸 작동시키기 위해 오랜 시간을 보냈다.결국 포기하고 DevExpress의 PasswordBoxEdit을 사용했습니다.
이것은 끔찍한 속임수를 쓰지 않고 바인딩할 수 있기 때문에 지금까지 가장 간단한 해결책입니다.
참고로 저는 DevExpress와 어떤 관계도 없습니다.
윈도 유니버설 앱
이 코드를 속성 "비밀번호" 및 modelView와 바인딩으로 사용할 수 있습니다.
<PasswordBox x:Uid="PasswordBox" Password="{Binding Waiter.Password, Mode=TwoWay}" Name="txtPassword" HorizontalAlignment="Stretch" Margin="50,200,50,0" VerticalAlignment="Top"/>
<UserControl x:Class="Elections.Server.Handler.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"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
Height="531" Width="1096">
<ContentControl>
<ContentControl.Background>
<ImageBrush/>
</ContentControl.Background>
<Grid >
<Border BorderBrush="#FFABADB3" BorderThickness="1" HorizontalAlignment="Left" Height="23" Margin="900,100,0,0" VerticalAlignment="Top" Width="160">
<TextBox TextWrapping="Wrap"/>
</Border>
<Border BorderBrush="#FFABADB3" BorderThickness="1" HorizontalAlignment="Left" Height="23" Margin="900,150,0,0" VerticalAlignment="Top" Width="160">
<PasswordBox x:Name="PasswordBox"/>
</Border>
<Button Content="Login" HorizontalAlignment="Left" Margin="985,200,0,0" VerticalAlignment="Top" Width="75">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="Login">
<cal:Parameter Value="{Binding ElementName=PasswordBox}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</ContentControl>
</UserControl>
using System;
using System.Windows;
using System.Windows.Controls;
using Caliburn.Micro;
namespace Elections.Server.Handler.ViewModels
{
public class LoginViewModel : PropertyChangedBase
{
MainViewModel _mainViewModel;
public void SetMain(MainViewModel mainViewModel)
{
_mainViewModel = mainViewModel;
}
public void Login(Object password)
{
var pass = (PasswordBox) password;
MessageBox.Show(pass.Password);
//_mainViewModel.ScreenView = _mainViewModel.ControlPanelView;
//_mainViewModel.TitleWindow = "Panel de Control";
//HandlerBootstrapper.Title(_mainViewModel.TitleWindow);
}
}
}
;) 간단해!
매우 간단합니다. 암호에 대한 다른 속성을 만들고 TextBox로 바인딩합니다.
그러나 모든 입력 작업은 실제 암호 속성을 사용하여 수행됩니다.
개인 문자열_패스워드;
public string PasswordChar
{
get
{
string szChar = "";
foreach(char szCahr in _Password)
{
szChar = szChar + "*";
}
return szChar;
}
set
{
_PasswordChar = value; NotifyPropertyChanged();
}
}
공용 문자열 암호 { get { return _ Password ;}
set
{
_Password = value; NotifyPropertyChanged();
PasswordChar = _Password;
}
}
이 구현으로 인해 발생할 수 있는 위험을 알고 있는 사용자는 ViewModel에 암호를 동기화하려면 Mode=OneWayToSource를 추가하십시오.
XAML
<PasswordBox
ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password, Mode=OneWayToSource}" />
음, MVVM 패턴의 경우 내 answerd가 더 단순합니다.
클래스 뷰 모델
public string password;
PasswordChangedCommand = new DelegateCommand<RoutedEventArgs>(PasswordChanged);
Private void PasswordChanged(RoutedEventArgs obj)
{
var e = (WatermarkPasswordBox)obj.OriginalSource;
//or depending or what are you using
var e = (PasswordBox)obj.OriginalSource;
password =e.Password;
}
Win이 제공하는 PasswordBox 또는 XCedtoolkit이 제공하는 WatermarkPasswordBox의 암호 속성이 RoutedEventArgs를 생성하여 바인드할 수 있습니다.
xmal 뷰에 표시됨
<Xceed:WatermarkPasswordBox Watermark="Input your Password" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Xceed:WatermarkPasswordBox>
또는
<PasswordBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="7" PasswordChar="*" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<prism:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path= DataContext.PasswordChangedCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path= Password}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
제 생각은 이렇습니다.
첨부된 속성을 사용하여 비밀번호를 바인드하면 비밀번호 보안의 목적이 상실됩니다.암호 상자의 암호 속성은 다음과 같은 이유로 바인딩할 수 없습니다.
암호 상자를 명령 매개 변수로 전달하면 ViewModel이 컨트롤을 인식할 수 있습니다.View Model을 플랫폼 간에 재사용할 계획이면 이 방법은 작동하지 않습니다.VM이 View 또는 기타 컨트롤을 인식하지 않도록 합니다.
새로운 속성이나 인터페이스를 도입하거나 패스워드 변경 이벤트에 가입하거나 기타 복잡한 것은 패스워드를 제공하는 간단한 작업에 필요하지 않다고 생각합니다.
XAML
<PasswordBox x:Name="pbPassword" />
<Button Content="Login" Command="{Binding LoginCommand}" x:Name="btnLogin"/>
코드 배후에 - 코드 배후에 사용하더라도 반드시 MVVM을 위반하는 것은 아닙니다.비즈니스 논리를 넣지 않는 한.
btnLogin.CommandParameter = new Func<string>(()=>pbPassword.Password);
뷰 모델
LoginCommand = new RelayCommand<Func<string>>(getpwd=> { service.Login(username, getpwd()); });
언급URL : https://stackoverflow.com/questions/1483892/how-to-bind-to-a-passwordbox-in-mvvm
'source' 카테고리의 다른 글
INT를 VARCHAR SQL로 변환 (0) | 2023.04.10 |
---|---|
Maven 프로젝트 버전을 bash 명령줄로 가져오는 방법 (0) | 2023.04.10 |
WPF 어플리케이션은 Linux 또는 Mac에서 실행할 수 있습니까?넷코어 3? (0) | 2023.04.10 |
아키텍처 암64에 대한 중복 기호 (0) | 2023.04.10 |
iOS: 앱에 사용자 이름/비밀번호를 저장하는 방법 (0) | 2023.04.10 |