4

サンプル プログラムを含めます。Tab キーを押して PasswordBox に移動すると、テキストを入力してから Tab キーを押すと、PasswordBox が空白になるようです。ただし、PasswordBox をダブルクリックしてテキストを入力し、タブで移動することはできません。なぜこれが起こるのですか?

編集:これは TextBox でも発生することがわかったため、PasswordBox に固有のバグではありません。

各シナリオを再作成する手順:

パスワードを非表示にする

  • [新規] をクリックします。
  • 名フィールドを 1 回クリックします。
  • 何かを入力
  • TAB キーを押します
  • 何かを入力
  • TAB キーを押します
  • TAB キーを押します (はいを 2 回押すと、Save イベントが発生します)。
  • 何かを入力
  • テキストの代わりにドットがあることに注意してください -PasswordBox が機能しています!
  • Tab キーを押します。
  • PasswordBox が空白になるので、友達を驚かせましょう!!

パスワードが消えないようにする

  • [新規] をクリックします。
  • 名フィールドを 1 回クリックします。
  • 何かを入力
  • TAB キーを押します
  • 何かを入力
  • パスワード欄をダブルクリックします。
  • 何かを入力
  • テキストの代わりにドットがあることに注意してください -PasswordBox が機能しています!
  • Tab キーを押します。
  • あなたの友人を驚かせて..待って、PasswordBox が空ではありませんか? なんてこと?

サンプルコード:

using System;
using System.Collections.ObjectModel;
namespace WpfApplication1 {
    public sealed class MyData    {
        private ObservableCollection<MyDataRow> dataList;
        public ObservableCollection<MyDataRow> DataList { get { return dataList; } }
        public MyData() { dataList = new ObservableCollection<MyDataRow>(); }
        public void AddBlankRow() { DataList.Add(new MyDataRow(this)); }
    }
    public sealed class MyDataRow     {
        private readonly MyData myData;
        public MyDataRow(MyData myData) { this.myData = myData; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Password { get; set; }
    }
}

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfApplication1 {
    public partial class MainWindow : Window  {
        private MyData Data { get { return (MyData)DataContext; } }

        public MainWindow() { InitializeComponent(); }

        private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)  {
            PasswordBox pb = (PasswordBox)sender;
            if (pb != null) {
                MyDataRow row = pb.DataContext as MyDataRow;
                if (row != null) { row.Password = pb.Password; }
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e) { DataContext = new MyData(); }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { }
        private void SaveExecute(object sender, ExecutedRoutedEventArgs e) { }
        private void NewExecute(object sender, ExecutedRoutedEventArgs e) { Data.AddBlankRow(); }
        private void CancelExecute(object sender, ExecutedRoutedEventArgs e) { Close(); }
    }
}

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" WindowStartupLocation="CenterScreen" Closing="Window_Closing">
    <Window.CommandBindings>
        <CommandBinding Command="Save" Executed="SaveExecute" />
        <CommandBinding Command="New" Executed="NewExecute" />
        <CommandBinding Command="Close" Executed="CancelExecute" />
    </Window.CommandBindings>
    <Grid Margin="0,10,0,0">
        <DataGrid ItemsSource="{Binding DataList}" ColumnWidth="*" Margin="10,0,9,38" HorizontalAlignment="Stretch" 
                  AutoGenerateColumns="False" GridLinesVisibility="Horizontal"
                  HeadersVisibility="Column" HorizontalGridLinesBrush="LightGray" CanUserReorderColumns="False" Background="White" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="First Name"  Binding="{Binding FirstName}"/>
                <DataGridTextColumn Header="Last Name"  Binding="{Binding LastName}"/>
                <DataGridTemplateColumn Header="Password" >
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <PasswordBox PasswordChanged="PasswordBox_PasswordChanged"   BorderThickness="0"
                                     Height="23" HorizontalAlignment="Stretch"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Button  
            Content="_New" Command="New"
            Width="75" Height="23" Margin="10,10,10,10"
            HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
        <Button 
            Content="_Save" Command="Save"
            IsDefault="True"
            IsEnabled="True"
            Width="75" Height="23" Margin="10,10,91,10"
            HorizontalAlignment="Right" VerticalAlignment="Bottom" />
        <Button
            Content="Cancel" Command="Close"
            IsEnabled="True"
            Width="75" Height="23" Margin="10,10,10,10"
            HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
    </Grid>
</Window>

編集

CellTemplate と EditingCellTemplate の両方にデータ テンプレートを使用する場合、私の回避策は単純に一貫性を保つことです。常に何かを表示します (この場合は楕円)。そうすれば、何があっても、PasswordBox がフォーカスを失うと、楕円に戻ります。これは、ときどき黒丸の文字を見たり、ときどき空白を見たりするよりも優れていると思います。David Edey の DataGrid_PreparingCellForEdit は、二重タブの問題を解決するのに最適です。

これが私のデータテンプレートです。

    <Grid.Resources>
        <DataTemplate x:Key="PasswordTemplate" >
            <Label BorderThickness="0" Height="23" HorizontalAlignment="Stretch" Content="..."/>
        </DataTemplate>
        <DataTemplate x:Key="EditingPasswordTemplate" >
            <PasswordBox PasswordChanged="PasswordBox_PasswordChanged"   BorderThickness="0" 
                                 Height="23" HorizontalAlignment="Stretch" />
        </DataTemplate>
    </Grid.Resources>
4

1 に答える 1

3

CellEditingTemplateこの問題は、編集用 ( ) と表示用 ( )の 2 つの個別のテンプレートがあることに関連していると思いますCellTemplateこれを回避する通常の方法は、http: //msdn.microsoft.com/en-us/library/system.windows.controlsに従って、バインディングを使用し、2 つの別々のテンプレートを両方とも同じデータにバインドすることです。 datagridtemplatecolumn.celltemplate(v=vs.110).aspx

ただし、もちろん、セキュリティ上の理由から(依存関係プロパティではないため)PasswordBoxにバインドすることはできません。それが大きな懸念事項ではない場合 (理由は完全にはわかりませんが、彼らが何をしているのかを人々が認識せずにバインディングでプレーンテキストのパスワードが飛び交うのを望んでいないと思います)、次のようにバインディングを作成できます。ここの記事の後半: http://wpftutorial.net/PasswordBox.html - カスタムの静的依存関係プロパティを使用します。PasswordPassword

そのため、以下のコードでその手順を実装しました。また、 https ://stackoverflow.com/ に従ってPreparingCellForEditイベントにハンドラーを追加することで、パスワード ボックスが正しくフォーカスされず、2 つのタブが必要になるというバグも修正しました。 a/2835464/3940783

全体として、私の作業サンプルのサンプル コードは次のとおりです。

using System;
using System.Collections.ObjectModel;
namespace WpfApplication1 {
    public sealed class MyData    {
        private ObservableCollection<MyDataRow> dataList;
        public ObservableCollection<MyDataRow> DataList { get { return dataList; } }
        public MyData() { dataList = new ObservableCollection<MyDataRow>(); }
        public void AddBlankRow() { DataList.Add(new MyDataRow(this)); }
    }
    public sealed class MyDataRow     {
        private readonly MyData myData;
        public MyDataRow(MyData myData) { this.myData = myData; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Password { get; set; }
    }
}

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfApplication1 {
    public partial class MainWindow : Window
    {
        public MainWindow() { InitializeComponent(); }
        private MyData Data { get { return (MyData)DataContext; } }

        void DataGrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
        {
            var inputElement = VisualTreeHelper.GetChild(e.EditingElement, 0) as PasswordBox;
            if (inputElement != null)
            {
                Keyboard.Focus(inputElement);
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e) { DataContext = new MyData(); }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { }
        private void SaveExecute(object sender, ExecutedRoutedEventArgs e) { }
        private void NewExecute(object sender, ExecutedRoutedEventArgs e) { Data.AddBlankRow(); }
        private void CancelExecute(object sender, ExecutedRoutedEventArgs e) { Close(); }
    }

そしてxamlは次のとおりです。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:w="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" WindowStartupLocation="CenterScreen" Closing="Window_Closing">
    <Window.CommandBindings>
        <CommandBinding Command="Save" Executed="SaveExecute" />
        <CommandBinding Command="New" Executed="NewExecute" />
        <CommandBinding Command="Close" Executed="CancelExecute" />
    </Window.CommandBindings>
    <Grid Margin="0,10,0,0">
        <DataGrid ItemsSource="{Binding DataList, Mode=OneTime}" ColumnWidth="*" Margin="10,0,9,38" HorizontalAlignment="Stretch"
                  AutoGenerateColumns="False" GridLinesVisibility="Horizontal"
                  HeadersVisibility="Column" HorizontalGridLinesBrush="LightGray" CanUserReorderColumns="False" Background="White"
                  PreparingCellForEdit="DataGrid_PreparingCellForEdit">
            <DataGrid.Resources>
                <DataTemplate x:Key="PasswordTemplate">
                    <PasswordBox w:PasswordHelper.Attach="True" w:PasswordHelper.Password="{Binding Password, Mode=TwoWay}" 
                                 BorderThickness="0" Height="23" HorizontalAlignment="Stretch" Width="130" />
                </DataTemplate>
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn Header="First Name"  Binding="{Binding FirstName}"/>
                <DataGridTextColumn Header="Last Name"  Binding="{Binding LastName}"/>
                <DataGridTemplateColumn Header="Password" CellTemplate="{StaticResource PasswordTemplate}"
                                        CellEditingTemplate="{StaticResource PasswordTemplate}" />
            </DataGrid.Columns>
        </DataGrid>
        <Button
            Content="_New" Command="New"
            Width="75" Height="23" Margin="10,10,10,10"
            HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
        <Button
            Content="_Save" Command="Save"
            IsDefault="True"
            IsEnabled="True"
            Width="75" Height="23" Margin="10,10,91,10"
            HorizontalAlignment="Right" VerticalAlignment="Bottom" />
        <Button
            Content="Cancel" Command="Close"
            IsEnabled="True"
            Width="75" Height="23" Margin="10,10,10,10"
            HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
    </Grid>
</Window>

そして、http:PasswordHelper //wpftutorial.net/PasswordBox.html のクラスを名前空間に追加すると、出来上がりです。

于 2014-09-12T19:37:31.880 に答える