こんにちは人々stackoverflow。私はMVVMを使用していますが、ViewModelにプロパティパスワードを使用してUserViewModelを呼び出させています。ビューには、コントロールPasswordBoxがあります。
<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />
しかし、このxamlは機能しません。どのようにバインディングを行いますか?助けてください!!
こんにちは人々stackoverflow。私はMVVMを使用していますが、ViewModelにプロパティパスワードを使用してUserViewModelを呼び出させています。ビューには、コントロールPasswordBoxがあります。
<PasswordBox x:Name="txtPassword" Password="{Binding Password}" />
しかし、このxamlは機能しません。どのようにバインディングを行いますか?助けてください!!
セキュリティ上の理由から、Passwordプロパティは依存関係プロパティではないため、バインドすることはできません。残念ながら、昔ながらの方法の背後にあるコードでバインディングを実行する必要があります(OnPropertyChangedイベントに登録し、コードを介して値を更新します...)
すばやく検索すると、このブログ投稿に移動します。このブログ投稿では、問題を回避するために添付プロパティを作成する方法を示しています。これを行う価値があるかどうかは、実際にはコードビハインドへの嫌悪感に依存します。
Passwordをラップし、Passwordプロパティの依存関係プロパティを追加するコントロールをいつでも作成できます。
私はコードビハインドを使用しますが、必要な場合は次のようなことができます。
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;
}
}
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;
}
}
パスワードがいつでもプレーンテキストとしてメモリ内で使用できるようにするために、コマンドのパラメータとして値を指定します。
<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}">
パスワードボックスの別のスレッドをチェックします。DPまたはパブリックプロパティにパスワードを保持しない方がよいでしょう。