WPF -- PasswordBox數據綁定方法


本文介紹下PasswordBox進行數據綁定的方法,本文參考鏈接

本文完整示例程序見GitHub

問題描述

PasswordBox的Password屬性不是依賴屬性,因此無法進行數據綁定。

解決辦法

該問題的解決辦法有多種,本文介紹如何通過添加附加屬性解決該問題。

附加屬性是說一個屬性本不屬於某個對象,但由於某種需求附加到該對象上,通過附加屬性可以實現將屬性與宿主解耦的目的。附加屬性本質上就是依賴屬性,只是它們在屬性包裝器和注冊時有區別。注冊附加屬性使用RegisterAttached方法,注冊依賴屬性使用Register方法,這兩個方法的參數差別並不大。

首先添加一個PasswordBoxBindingHelper類,該類包含一個附加屬性(snippet:propa+兩次tab),通過設置該屬性的PropertyChangedCallback將改變通知到PasswordBox.Password,並通過添加對PasswordBox.PasswordChanged事件的響應來響應PasswordBox.Password的改變。有了該附加屬性,即可進行數據綁定。

public static string GetPasswordContent(DependencyObject obj) => (string)obj.GetValue(PasswordContentProperty);

public static void SetPasswordContent(DependencyObject obj, string value) => obj.SetValue(PasswordContentProperty, value);

public static readonly DependencyProperty PasswordContentProperty =
    DependencyProperty.RegisterAttached("PasswordContent", typeof(string), typeof(PasswordBoxBindingHelper),
    new PropertyMetadata(string.Empty, OnPasswordContentPropertyChanged));

private static void OnPasswordContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var box = d as PasswordBox;
    box.PasswordChanged -= OnPasswordChanged;
    var password = (string)e.NewValue;
    if (box != null && box.Password != password)
        box.Password = password;
    box.PasswordChanged += OnPasswordChanged;
}

private static void OnPasswordChanged(object sender, RoutedEventArgs e)
{
    var box = sender as PasswordBox;
    SetPasswordContent(box, box.Password);
}

然后在View中使用該附加屬性進行數據綁定,本文示例中主窗口包含一個PasswordBox控件及一個Button按鈕:

// xaml 綁定附加屬性
<Window ...
        xmlns:local="clr-namespace:PasswordBoxBinding"
        Title="PasswordBoxBinding" Height="300" Width="450" WindowStartupLocation="CenterScreen">

    <Grid>
        <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <PasswordBox MinWidth="200" Height="30" BorderBrush="LightGray" BorderThickness="2"
                         local:PasswordBoxBindingHelper.PasswordContent="{Binding Password,Mode=TwoWay}"/>
            <Rectangle Width="20"/>
            <Button Width="80" Height="30" Content="查看密碼" Command="{Binding ClickedCommand}"/>
        </StackPanel>
    </Grid>
</Window>

//xaml.cs 設置綁定源
public MainWindow()
{
    InitializeComponent();
    this.DataContext = new MainWindowViewModel();
}

最后創建ViewModel進行邏輯處理:

// ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
    public string Password
    {
        get => _password;
        set
        {
            _password = value;
            OnPropertyChanged();
        }
    }

    public DelegateCommand ClickedCommand => _clickedCommand ?? (_clickedCommand = new DelegateCommand { ExecuteAction = OnClicked });

    // 使用CallerMemberName特性簡化代碼,並可以避免手動輸入錯誤
    public void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    private void OnClicked(object o) => MessageBox.Show($"password: {Password}");

    public event PropertyChangedEventHandler PropertyChanged;

    private DelegateCommand _clickedCommand;
    private string _password;
}

// 實現ICommand
public class DelegateCommand : ICommand
{
    public bool CanExecute(object parameter) => CanExecuteAction?.Invoke(parameter) ?? true;

    public void Execute(object parameter) => ExecuteAction?.Invoke(parameter);

    public event EventHandler CanExecuteChanged;

    public Action<object> ExecuteAction { get; set; }
    public Func<object, bool> CanExecuteAction { get; set; }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM