2017-11-03 18 views
0

私はWPFアプリケーションを持っており、MVVMパターンを使用しています。ユーザーコントロールの1つに、ユーザーが入力したパスワードを比較する2つのPasswordBoxがあります。 ViewModelで送信ボタンを有効にするか無効にするかを決定する比較動作を実装しようとしています。私はちょっと固まっている。WPF MVVMでの2つのパスワードの比較

編集: これはコメントに記載されている@Dblと重複する質問ではありません。彼のコメントで述べられている重複した質問は、2つのSecureStringデータ型を比較す​​る方法です。私の質問はまったく違う。ある要素に関連付けられたビヘイビアーがビヘイビアー内の別の要素の値を知る必要があるMVVMパターンを破ることなく、2つのオブジェクト値を比較します(それらがSecureStringかどうかは関係ありません)。また、この動作は、要素の基になるViewModelにアクセスし、ViewModelのINPCプロパティを更新できる必要があります。ここで

私のXAMLである(簡潔にするための要素のかなりを削除):

<UserControl 
x:Class="DynaProPOS.WPF.Views.AppUser" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:prism="http://prismlibrary.com/" 
xmlns:syncfusion="http://schemas.syncfusion.com/wpf" 
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:behavior="clr-namespace:DynaProPOS.WPF.Behaviors" 
xmlns:custProps="clr-namespace:DynaProPOS.WPF.CustomProperties" 
prism:ViewModelLocator.AutoWireViewModel="True" 
Background="{DynamicResource BackgroundBrush}"> 
<Border Width="750" Height="260" BorderBrush="White" BorderThickness="2"> 
    <Grid x:Name="grid" KeyboardNavigation.TabNavigation="Cycle" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="Auto" Width="Auto"> 
     <PasswordBox TabIndex="3" Grid.Row="3" Grid.Column="1" Margin="2" x:Name="Password1" HorizontalAlignment="Stretch" VerticalAlignment="Center"> 
      <i:Interaction.Behaviors> 
       <behavior:PasswordBoxBindingBehavior Password="{Binding Password}" /> 
      </i:Interaction.Behaviors> 
     </PasswordBox> 
     <PasswordBox TabIndex="4" Grid.Row="4" Grid.Column="1" Margin="2,18,2,4" x:Name="Password2" HorizontalAlignment="Stretch" VerticalAlignment="Center"> 
      <i:Interaction.Behaviors> 
       <behavior:ComparePasswordBehavior OriginalPassword="{Binding ElementName=Password1, Path=Password}"/> 
      </i:Interaction.Behaviors> 
     </PasswordBox> 
     <Grid Grid.Column="3" Grid.RowSpan="5" VerticalAlignment="Stretch"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="10*" /> 
       <RowDefinition Height="90*" /> 
      </Grid.RowDefinitions> 
     </Grid> 
     <syncfusion:ButtonAdv TabIndex="6" x:Name="RegisterButton" Grid.Row="5" Grid.Column="4" Margin="5" HorizontalAlignment="Right" Label="Submit" VerticalAlignment="Center" /> 
    </Grid> 
</Border> 

そして、ここでは私のViewModelに(再び、簡潔にするために多くのコードを削除します)です。

public class AppUserViewModel : BindableBase 
{ 
    private bool isEnabled; 
    public AppUserViewModel(IAuthenticationService _authService) 
    { 
     authService = _authService; 
     RegisterCommand = new DelegateCommand(async() => await RegisterUserAsync()); 
    } 

    public bool IsEnabled 
    { 
     get { return isEnabled; } 
     set { SetProperty(ref isEnabled, value); } 
    } 
} 

最後に、Behaviorクラスがあります。

public class ComparePasswordBehavior : Behavior<PasswordBox> 
{ 
    protected override void OnAttached() 
    { 
     AssociatedObject.LostFocus += OnComparePasswordLostFocus; 
     base.OnAttached(); 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.LostFocus -= OnComparePasswordLostFocus; 
     base.OnDetaching(); 
    } 

    public static readonly DependencyProperty OriginalPasswordProperty = 
     DependencyProperty.Register("OriginalPassword", typeof(SecureString), typeof(ComparePasswordBehavior), new PropertyMetadata(null)); 

    private static void OnComparePasswordLostFocus(object sender, RoutedEventArgs e) 
    { 
     PasswordBox pswdBox = sender as PasswordBox; 
     var behavior = Interaction.GetBehaviors(pswdBox).OfType<ComparePasswordBehavior>().FirstOrDefault(); 

     if (behavior != null) 
     { 
      var binding = BindingOperations.GetBindingExpression(behavior, OriginalPasswordProperty); 
      PropertyInfo propInfo = binding.DataItem.GetType().GetProperty(binding.ParentBinding.Path.Path); 
      // at this point I am stumped. I don't seems to be able to 
      // retrieve the value from the original password box element. 
      // I am also not able to set the IsEnabled property of the ViewModel. 
     } 
    } 

    public SecureString OriginalPassword 
    { 
     get { return (SecureString)GetValue(OriginalPasswordProperty); } 
     set { SetValue(OriginalPasswordProperty, (SecureString)value); } 
    } 
} 

元のパスワードボックスからパスワードの値を保持するために、私の動作に依存プロパティが定義されています。私の振る舞いのlostfocusイベントでは、2つのパスワードを比較し、それに応じてViewModelのIsEnabledプロパティを設定する必要があります。

私はここで2つのことをする必要があります。 Password1 PasswordBox要素からパスワード値を取得する必要があります パスワード比較結果に基づいてViewModelのIsEnabledプロパティを設定する必要があります。誰か助けてもらえますか?私はここで一日ここで立ち往生しています。ありがとう。

+0

可能な重複が - EQの2 SecureStringsを比較uality](https:// stackoverflow。com/questions/4502676/c-sharp-compare-two-securestrings-for-equality) – Dbl

+0

あなたの質問を削除しないでください - この質問が検索エンジンからの訪問数を増やすと予想しています – Dbl

答えて

1

ComparePasswordBehaviorのインスタンスは、PasswordBoxBindingBehaviorのインスタンスについては何も知らず、その逆もありません。また、パスワードを比較してIsEnabledプロパティを設定するのは、ビューモデルの再配置性です。

この動作では、パスワードをPasswordBoxからビューモデルに転送するだけです。ビューモデルにSecureStringsを格納し、そこで比較を行う必要があります。

次のサンプルコードを参照してください。

行動:

public class PasswordBehavior : Behavior<PasswordBox> 
{ 
    protected override void OnAttached() 
    { 
     AssociatedObject.LostFocus += OnComparePasswordLostFocus; 
     base.OnAttached(); 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.LostFocus -= OnComparePasswordLostFocus; 
     base.OnDetaching(); 
    } 

    public static readonly DependencyProperty PasswordProperty = 
     DependencyProperty.Register("Password", typeof(SecureString), typeof(PasswordBehavior), new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = true }); 


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

    private static void OnComparePasswordLostFocus(object sender, RoutedEventArgs e) 
    { 
     PasswordBox pswdBox = sender as PasswordBox; 
     PasswordBehavior behavior = Interaction.GetBehaviors(pswdBox).OfType<PasswordBehavior>().FirstOrDefault(); 
     if (behavior != null) 
     { 
      behavior.Password = pswdBox.SecurePassword; 
     } 
    } 
} 

ビューモデル:

public class AppUserViewModel : BindableBase 
{ 
    private bool isEnabled; 
    public bool IsEnabled 
    { 
     get { return isEnabled; } 
     set { SetProperty(ref isEnabled, value); } 
    } 

    private SecureString _password1; 
    public SecureString Password1 
    { 
     get { return _password1; } 
     set 
     { 
      if (SetProperty(ref _password1, value)) 
       ComparePasswords(); 
     } 
    } 

    private SecureString _password2; 
    public SecureString Password2 
    { 
     get { return _password2; } 
     set 
     { 
      if (SetProperty(ref _password2, value)) 
       ComparePasswords(); 
     } 
    } 

    private void ComparePasswords() 
    { 
     IsEnabled = (_password1 != null || _password2 != null) 
      && SecureStringToString(_password1) == SecureStringToString(_password2); 
    } 

    private string SecureStringToString(SecureString value) 
    { 
     IntPtr valuePtr = IntPtr.Zero; 
     try 
     { 
      valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value); 
      return Marshal.PtrToStringUni(valuePtr); 
     } 
     finally 
     { 
      Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); 
     } 
    } 
} 

表示:[C#2の

<PasswordBox> 
    <i:Interaction.Behaviors> 
     <behavior:PasswordBehavior Password="{Binding Password1}" /> 
    </i:Interaction.Behaviors> 
</PasswordBox> 
<PasswordBox> 
    <i:Interaction.Behaviors> 
     <behavior:PasswordBehavior Password="{Binding Password2}"/> 
    </i:Interaction.Behaviors> 
</PasswordBox> 
+0

完璧に作業しました!ありがとうございました。私は確かに "行動"の行動について新しいことを学んだ。 –

関連する問題