【问题标题】:How can I make a TextBox be a "password box" and display stars when using MVVM?使用 MVVM 时,如何使 TextBox 成为“密码框”并显示星星?
【发布时间】:2026-01-24 21:00:01
【问题描述】:

如何在 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 属性。

【问题讨论】:

标签: c# wpf xaml mvvm textbox


【解决方案1】:

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

string password = PasswordBox.Password;

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

【讨论】:

【解决方案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(); } }
          

          【讨论】: