使用 MVVM 时,如何使 TextBox 成为“密码框”并显示星星?

Posted

技术标签:

【中文标题】使用 MVVM 时,如何使 TextBox 成为“密码框”并显示星星?【英文标题】:How can I make a TextBox be a "password box" and display stars when using MVVM? 【发布时间】:2010-11-10 07:33:13 【问题描述】:

如何在 XAML 中执行此操作:

伪代码:

<TextBox Text="Binding Password" Type="Password"/>

以便用户在输入密码时看到星号或圆点。

我试过 various examples 建议 PasswordCharPasswordBox 但无法让这些工作。

例如我可以这样做,如图here:

<PasswordBox Grid.Column="1" Grid.Row="1"
    PasswordChar="*"/>

但我当然想将 Text 属性绑定到我的 ViewModel,以便在单击按钮时将值发送到绑定的 TextBox(不使用后面的代码),我想这样做:

<TextBox Grid.Column="1" Grid.Row="0" 
    Text="Binding Login" 
    Style="StaticResource FormTextBox"/>
<PasswordBox Grid.Column="1" Grid.Row="1"
    Text="Binding Password" 
    PasswordChar="*"
    Style="StaticResource FormTextBox"/>

但是 PasswordBox 没有 Text 属性。

【问题讨论】:

您能否详细说明为什么 PasswordChar 和 PasswordBox 不起作用? 使用MVVM似乎不是那么直接,我在这里发现了一个类似的问题:***.com/questions/1097235/passwordbox-with-mvvm 【参考方案1】:

要获取或设置 PasswordBox 中的密码,请使用 Password 属性。比如

string password = PasswordBox.Password;

据我所知,这不支持数据绑定,所以你必须在代码隐藏中设置值,并相应地更新它。

【讨论】:

可以提一下: 我认为这实际上行不通,至少在我尝试的时候不行。 文章正确地指出“不能使用数据绑定是一种耻辱”,但它确实提供了一个 2 页的附加属性解决方法,让我们看看它是否真的有效:blog.functionalfun.net/2008/06/…跨度> 不允许在 PasswordBox 上进行数据绑定的原因似乎是这里讨论的安全问题:social.msdn.microsoft.com/forums/en-US/wpf/thread/… 我测试了这个解决方案,效果很好:blog.functionalfun.net/2008/06/…【参考方案2】:

正如 Tasnim Fabiha 所提到的,可以更改 TextBox 的字体以便仅显示点/星号。但是我找不到他的字体……所以我给你我的工作示例:

<TextBox Text="Binding Password" 
     FontFamily="pack://application:,,,/Resources/#password" />

只是复制粘贴是行不通的。首先你必须下载提到的字体“password.ttf” 链接:https://github.com/davidagraf/passwd/blob/master/public/ttf/password.ttf 然后将其复制到您的项目资源文件夹(项目->属性->资源->添加资源->添加现有文件)。然后将其 Build Action 设置为:Resource。

之后你只会看到点,但你仍然可以从中复制文本,因此需要禁用 CTRL+C 快捷键,如下所示:

<TextBox Text="Binding Password" 
     FontFamily="pack://application:,,,/Resources/#password" > 
    <TextBox.InputBindings>
        <!--Disable CTRL+C (COPY) -->
        <KeyBinding Command="ApplicationCommands.NotACommand"
            Key="C"
            Modifiers="Control" />
        <!--Disable CTRL+X (CUT) -->
        <KeyBinding Command="ApplicationCommands.NotACommand"
            Key="X"
            Modifiers="Control" />
    </TextBox.InputBindings>
    <TextBox.ContextMenu>
        <!--Hide context menu where you could copy/cut as well -->
        <ContextMenu Visibility="Collapsed" />
    </TextBox.ContextMenu>
</TextBox>

编辑: 添加了基于@CodingNinja评论的Ctrl+X和上下文菜单禁用,谢谢。

【讨论】:

这个字体不适合我。文本保持完全相同,而不是密码字符...如果您有任何提示,我将不胜感激。谢谢 对我来说它有效(也在 .NET 4.8 上测试过)。尝试使用 FontFamily 位置,我认为它可能会略有不同,并确保您将其作为 RESOURCE。 谢谢!非常适合我。能够显示点并禁用 CTRL-C。真的很感激! 不客气。为了使其 100% 安全,还禁用 CTRL+X (CUT) 快捷方式。 @ssamko 不要忘记在上下文菜单中复制/粘贴! ***.com/a/3484929/4380178【参考方案3】:

将密码框控件作为参数发送到您的登录命令。

<Button Command="Binding LoginCommand" CommandParameter="Binding ElementName=PasswordBox"...>

然后你可以在你的视图模型中调用CType(parameter, PasswordBox).Password

【讨论】:

这违反了 MVVM 模式。【参考方案4】:

这里有一种绑定 PasswordBox 的方法:PasswordBox Databinding

【讨论】:

【参考方案5】:

谢谢科迪,这很有帮助。我刚刚为使用 C# 中的委托命令的人添加了一个示例

<PasswordBox x:Name="PasswordBox"
             Grid.Row="1" Grid.Column="1"
             HorizontalAlignment="Left" 
             Width="300" Height="25"
             Margin="6,7,0,7" />
<Button Content="Login"
        Grid.Row="4" Grid.Column="1"
        Style="StaticResource StandardButton"
        Command="Binding LoginCommand"
        CommandParameter="Binding ElementName=PasswordBox"
        Height="31" Width="92"
        Margin="5,9,0,0" />

 

public ICommand LoginCommand

   get
   
        return new DelegateCommand<object>((args) =>
        
            // Get Password as Binding not supported for control-type PasswordBox
            LoginPassword = ((PasswordBox) args).Password;

            // Rest of code here
        );
   

【讨论】:

【参考方案6】:

您只需将以下值添加到您的TextBox 控件的FontFamily 属性中,即可将您的TextBox 设为自定义PasswordBox

<TextBox
    Text="Binding Password"
    FontFamily="ms-appx:///Assets/PassDot.ttf#PassDot"
    FontSize="35"/>

就我而言,这非常有效。这将显示点代替实际文本(不是星号(*))。

【讨论】:

这家伙是个英雄!一个奇怪的人,但仍然是一个英雄! 我希望这会起作用,但对我来说它仍然显示文本。我必须下载 PassDot.ttf 吗? @rabejens 是的,你必须下载它。 您可以捆绑字体并将其作为资源加载。 @TasnimFabiha 下载链接?【参考方案7】:

使用 PasswordBox 的问题在于它对 MVVM 不是很友好,因为它可以与 SecureString 一起使用,因此需要一个 shim 将其绑定到字符串。您也不能使用剪贴板。虽然所有这些东西都是有原因的,但您可能不需要那种级别的安全性。这是一种适用于剪贴板的替代方法,没什么特别的。您使 TextBox 文本和背景透明,并将文本绑定到其下方的 TextBlock。此文本块使用指定的转换器将字符转换为 *。

<Window.Resources>
    <local:TextToPasswordCharConverter x:Key="TextToPasswordCharConverter" />
</Window.Resources>

<Grid Width="200">
    <TextBlock Margin="5,0,0,0" Text="Binding Text, Converter=StaticResource TextToPasswordCharConverter, UpdateSourceTrigger=PropertyChanged, Mode=OneWay" FontFamily="Consolas" VerticalAlignment="Center" />
    <TextBox Foreground="Transparent" Text="Binding Text, UpdateSourceTrigger=PropertyChanged" FontFamily="Consolas" Background="Transparent" />
</Grid>

这里是值转换器:

class TextToPasswordCharConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        return new String('*', value?.ToString().Length ?? 0);
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        throw new NotImplementedException();
    

确保视图模型上的 Text 属性实现 INotifyPropertyChanged

【讨论】:

【参考方案8】:

我从 Views 代码隐藏中执行了以下操作,以在视图模型中设置我的属性。不确定它是否真的“打破”了 MVVM 模式,但它是找到的最佳且最简单的解决方案。

  var data = this.DataContext as DBSelectionViewModel;

        data.PassKey = txtPassKey.Password;

【讨论】:

【参考方案9】:

对我有用的一个简单解决方案是将文本框绑定到显示重复 * 的转换值的 LocalPassword。任何条目都存储在 _localPassword 变量中。

<TextBox Text="Binding LocalPassword" />

private string _localPassword = null;
private string _localPasswordDisplayed  get => new string('*', _localPassword.Length); 
public string LocalPassword  get => _localPasswordDisplayed; set  _localPassword = value; OnPropertyChanged();  

【讨论】:

以上是关于使用 MVVM 时,如何使 TextBox 成为“密码框”并显示星星?的主要内容,如果未能解决你的问题,请参考以下文章

如何连接 TextBox 的 TextChanged 事件和命令以便在 Silverlight 中使用 MVVM 模式

MVVM 和 TextBox 的 SelectedText 属性

Mvvm KeyDown的实现以及TextBox绑定的属性不更新问题的解决

WPF MVVM - 如何绑定自定义控件->ToggleButton.IsChecked 到 View->TextBox.Text

使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索

MVVM DEVDataColumn中的TextBox与ComboBox的并存