一键导入
dotnet-wpf-employee-input
こんなときに使う: WPFアプリケーションに社員番号入力ダイアログを追加し、 DPAPIで暗号化された設定として社員IDを安全に保存したいとき。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
こんなときに使う: WPFアプリケーションに社員番号入力ダイアログを追加し、 DPAPIで暗号化された設定として社員IDを安全に保存したいとき。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
モダン C#(12+)で record、パターンマッチング、合成、Result 型エラーハンドリングを使った 慣用的で高性能なコードを書く。こんなときに使う: 新規 C# コードの作成、API 設計、 または C# 12+ イディオムへのリファクタリング。
こんなときに使う: 繰り返し発生する業務問い合わせ(監査、アンケート、コンプライアンス調査)に対して、 過去の回答実績とエビデンスを活用して回答するためのテンプレートスキル。 再利用可能な7ステップワークフローとスキャフォールディングファイルを提供する。
こんなときに使う: PDFテキスト抽出、Optical Character Recognition (OCR)、結合/分割、フォーム処理をuvベースの再現可能コマンドで実行したいときに使う。
こんなときに使う: Migrate Access SQL to Oracle, generate .NET C# code. Use when converting Access queries to Oracle.
こんなときに使う: .NETドメイン層で汎用的な重み付きフィールドマッチングとスコアリングを実装。
こんなときに使う: dotnet-tools.json によるローカル .NET ツールの管理。開発環境と CI/CD パイプライン全体で バージョン固定された一貫したツール環境を構築。リポジトリ単位の CLI ツール管理時に使用。
| name | dotnet-wpf-employee-input |
| description | こんなときに使う: WPFアプリケーションに社員番号入力ダイアログを追加し、 DPAPIで暗号化された設定として社員IDを安全に保存したいとき。 |
| license | MIT |
| metadata | {"author":"RyoMurakami1983","tags":["dotnet","wpf","csharp","mvvm","employee","dpapi","configuration"],"invocable":false} |
WPFアプリケーションに社員番号(社員番号)入力ダイアログを追加するためのエンドツーエンドワークフロー:4桁バリデーション、SecureConfigServiceによるDPAPI暗号化保存、MVVM設定UI、メニューバー統合。
以下の場合にこのスキルを使用してください:
dotnet-wpf-secure-config — 必須:DPAPI暗号化基盤(先に適用)dotnet-wpf-dify-api-integration — Dify API呼び出しのuserフィールドに社員番号を使用dotnet-oracle-wpf-integration — 同じアプリでSecureConfigServiceを共有tdd-standard-practice — Red-Green-Refactorで生成コードをテストgit-commit-practices — 各ステップをアトミックな変更としてコミットdotnet-wpf-secure-config 適用済みプロジェクトに社員番号ファイルを追加するときに使用します。
前提条件(先に完了必須):
dotnet-wpf-secure-config スキル適用済みInfrastructure/Configuration/ フォルダに以下が存在:
DpapiEncryptor.csSecureConfigService.csISecureConfigService.csAppConfigModel.cs追加するファイル(社員番号固有):
Presentation/
├── ViewModels/
│ └── EmployeeNumberConfigViewModel.cs 🆕
└── Views/
├── EmployeeNumberConfigDialog.xaml 🆕
└── EmployeeNumberConfigDialog.xaml.cs 🆕
NuGetパッケージ(未インストールの場合):
Install-Package CommunityToolkit.Mvvm
Install-Package Microsoft.Extensions.DependencyInjection
Values: 基礎と型 / 成長の複利
バリデーション、保存、リセット機能を持つ社員番号入力ロジックを実装するときに使用します。
フォーマット検証、オープン時の読み込み、保存、リセット機能を持つEmployeeNumberConfigViewModelを作成します。ViewModelはすべての永続化をISecureConfigServiceに委譲します。
EmployeeNumberConfigViewModel.cs:
public partial class EmployeeNumberConfigViewModel : ObservableObject
{
private readonly ISecureConfigService _configService;
[ObservableProperty] private string employeeNumber = string.Empty;
[ObservableProperty] private string statusMessage = string.Empty;
public EmployeeNumberConfigViewModel(ISecureConfigService configService)
=> _configService = configService;
public async Task LoadConfigAsync()
{
var config = await _configService.LoadDifyConfigAsync();
EmployeeNumber = config.EmployeeNumber;
StatusMessage = "Settings loaded.";
}
[RelayCommand]
private async Task SaveAsync()
{
// ✅ Validate format before persisting
if (!IsValidEmployeeNumber(EmployeeNumber))
{ StatusMessage = "Enter a 4-digit employee number."; return; }
var config = await _configService.LoadDifyConfigAsync();
config.EmployeeNumber = EmployeeNumber.Trim();
await _configService.SaveDifyConfigAsync(config);
StatusMessage = "Saved.";
}
[RelayCommand]
private async Task ResetAsync()
{
var config = await _configService.LoadDifyConfigAsync();
config.EmployeeNumber = string.Empty;
await _configService.SaveDifyConfigAsync(config);
EmployeeNumber = string.Empty;
StatusMessage = "Reset complete.";
}
/// <summary>
/// Validates employee number format: exactly 4 digits.
/// </summary>
private static bool IsValidEmployeeNumber(string number)
=> !string.IsNullOrWhiteSpace(number)
&& number.Trim().Length == 4
&& number.Trim().All(char.IsDigit);
}
ViewModelでバリデーションを行う理由: Viewをロジックフリーに保ち、実行中のWPFウィンドウなしでバリデーションをテスト可能にします。IsValidEmployeeNumberメソッドはstaticなので単体テストで分離テストできます。
Values: 基礎と型 / ニュートラル
社員番号入力用のWPFウィンドウを構築するときに使用します。
入力フィールド、ステータスメッセージ、アクションボタンを持つコンパクトなモーダルダイアログを作成します。すべてのコントロールはViewModelプロパティにバインド — x:Name操作は不要です。
EmployeeNumberConfigDialog.xaml:
<Window Title="Employee Number Settings"
Height="260" Width="420"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize"
Loaded="Window_Loaded">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<TextBlock Text="Employee Number"
FontSize="16" FontWeight="Bold"/>
<!-- Input -->
<StackPanel Grid.Row="1" Margin="0,10,0,0">
<TextBlock Text="Employee Number *"/>
<TextBox Text="{Binding EmployeeNumber, UpdateSourceTrigger=PropertyChanged}"
Margin="0,4,0,0"/>
<TextBlock Text="Enter 4-digit number"
Foreground="Gray" FontSize="10" Margin="0,2,0,0"/>
</StackPanel>
<!-- Status -->
<TextBlock Grid.Row="2"
Text="{Binding StatusMessage}"
Foreground="Blue"
VerticalAlignment="Bottom" Margin="0,0,0,8"/>
<!-- Actions -->
<StackPanel Grid.Row="3" Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="Save"
Command="{Binding SaveCommand}"
Margin="0,0,8,0" Padding="16,4"/>
<Button Content="Reset"
Command="{Binding ResetCommand}"
Margin="0,0,8,0" Padding="16,4"/>
<Button Content="Close"
Click="Close_Click"
Padding="16,4"/>
</StackPanel>
</Grid>
</Window>
UpdateSourceTrigger=PropertyChangedを使う理由: これがないと、WPFはフォーカス喪失時のみバインディングを更新します。リアルタイムバリデーションにはViewModelへの文字単位の更新が必要です。
Values: 基礎と型 / 成長の複利
最小限のcode-behindでダイアログウィンドウをViewModelに接続するときに使用します。
code-behindは2つのことだけを処理します:Window_Loadedでの設定読み込みとウィンドウのクローズ。すべてのビジネスロジックはViewModelに残ります。
EmployeeNumberConfigDialog.xaml.cs:
public partial class EmployeeNumberConfigDialog : Window
{
public EmployeeNumberConfigDialog(EmployeeNumberConfigViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
=> await ((EmployeeNumberConfigViewModel)DataContext).LoadConfigAsync();
private void Close_Click(object sender, RoutedEventArgs e)
=> Close();
}
Window_Loadedで設定を読み込む理由: コンストラクタでの読み込みはUIスレッドをブロックし、ウィンドウ描画を遅延させます。Window_Loadedはウィンドウ表示後に発火するため、視覚的な遅延なく非同期読み込みが可能です。
Values: 基礎と型 / 継続は力
MainWindowから社員番号ダイアログを起動するメニュー項目を追加するときに使用します。
ViewModelをDIに登録し、メニューコマンドからダイアログを起動します。
App.xaml.cs — DI登録の追加:
// App.xaml.cs — add to OnStartup
services.AddTransient<EmployeeNumberConfigViewModel>();
MainWindowメニュー — メニュー項目の追加:
<MenuItem Header="Settings">
<MenuItem Header="Employee Number..."
Command="{Binding OpenEmployeeNumberConfigCommand}"/>
</MenuItem>
MainViewModel — 起動コマンドの追加:
[RelayCommand]
private void OpenEmployeeNumberConfig()
{
var vm = _serviceProvider.GetRequiredService<EmployeeNumberConfigViewModel>();
new EmployeeNumberConfigDialog(vm) { Owner = Application.Current.MainWindow }
.ShowDialog();
}
Values: 成長の複利 / 継続は力
組織の要件に合わせて社員番号フォーマットを調整するときに使用します。
⚠️ ユーザーに確認 — 社員IDフォーマットに使用する桁数とバリデーションルールを確認してください。
組織の要件に基づいてこれらのデフォルトを置き換えてください:
| 項目 | ファイル | デフォルト | 変更内容 |
|---|---|---|---|
| 桁数 | IsValidEmployeeNumber | 4桁 | フォーマットに合わせてLength == 4を調整 |
| バリデーションルール | IsValidEmployeeNumber | 数字のみ | 必要に応じてプレフィックス/サフィックスルールを追加 |
| 保存場所 | DifyConfigModel | EmployeeNumberプロパティ | 必要に応じてプロパティ名を変更 |
| フィールドラベル | Dialog.xaml | "Employee Number" | ローカライズまたはリネーム |
| ウィンドウタイトル | Dialog.xaml | "Employee Number Settings" | アプリの命名規則に合わせる |
カスタマイズ例:
// 6-digit employee number
private static bool IsValidEmployeeNumber(string number)
=> !string.IsNullOrWhiteSpace(number)
&& number.Trim().Length == 6
&& number.Trim().All(char.IsDigit);
// Alphanumeric with prefix (e.g., "EMP-1234")
private static bool IsValidEmployeeNumber(string number)
=> !string.IsNullOrWhiteSpace(number)
&& Regex.IsMatch(number.Trim(), @"^EMP-\d{4}$");
Values: ニュートラル / 基礎と型
What: SaveDifyConfigAsync呼び出し前に、ViewModelで桁数と文字種をチェックします。
Why: 無効なデータが設定ファイルに到達するのを防ぎ、ユーザーに即座にフィードバックを提供します。
Values: 基礎と型(バリデーションを型として定着)
What: Window_LoadedでLoadConfigAsync()を呼び出し、保存済みの値でTextBoxを表示します。
Why: ユーザーが現在の設定を確認・更新できます。空フィールドによる混乱を回避します。
Values: 継続は力(既存設定の継続性を保つ)
What: SecureConfigService経由で保存値をクリアするリセットボタンを含めます。
Why: ユーザーが設定ファイルを手動編集せずに社員番号を削除できます。
Values: ニュートラル(安全なリセット手段を標準提供)
Problem: 値が既に保存されているにもかかわらず、ダイアログが空のTextBoxで開きます。
Solution: コンストラクタではなく、必ずWindow_LoadedイベントでLoadConfigAsync()を呼び出します。
// ❌ WRONG — Blocks UI thread, may miss async completion
public EmployeeNumberConfigDialog(EmployeeNumberConfigViewModel vm)
{
InitializeComponent();
DataContext = vm;
vm.LoadConfigAsync().Wait(); // Deadlock risk
}
// ✅ CORRECT — Async load after window renders
private async void Window_Loaded(object sender, RoutedEventArgs e)
=> await ((EmployeeNumberConfigViewModel)DataContext).LoadConfigAsync();
Problem: バリデーションがキーストロークごとではなく、TextBoxのフォーカス喪失時にのみトリガーされます。
Solution: TextBoxバインディングにUpdateSourceTrigger=PropertyChangedを設定します。
<!-- ❌ WRONG — Updates only on LostFocus -->
<TextBox Text="{Binding EmployeeNumber}"/>
<!-- ✅ CORRECT — Updates on every keystroke -->
<TextBox Text="{Binding EmployeeNumber, UpdateSourceTrigger=PropertyChanged}"/>
Problem: ViewModelプロパティを更新したが、config.jsonに保存していない。
Solution: 設定モデル変更後は必ずSaveDifyConfigAsync()を呼び出します。
// ❌ WRONG — Property updated but not persisted
EmployeeNumber = "1234";
// ✅ CORRECT — Persist through SecureConfigService
var config = await _configService.LoadDifyConfigAsync();
config.EmployeeNumber = EmployeeNumber.Trim();
await _configService.SaveDifyConfigAsync(config);
What: 社員番号をappsettings.jsonやカスタム.txtファイルに書き込む。
Why It's Wrong: 平文ファイルはファイルシステムにアクセスできる誰でも読み取り可能。保存時の暗号化がない。
Better Approach: SecureConfigServiceとDPAPI暗号化を使用して%LOCALAPPDATA%に保存。
What: 保存/バリデーション/リセットロジックを.xaml.csのイベントハンドラに直接記述。
Why It's Wrong: 実行中のWPFウィンドウなしではテスト不可能。MVVM分離に違反。ロジックがファイル間に散在。
Better Approach: [RelayCommand]とデータバインディングですべてのロジックをViewModelに委譲。code-behindはWindow_LoadedとClose_Clickのみを処理。
dotnet-wpf-secure-config スキル適用済み(前提条件)AppConfigModelにEmployeeNumberフィールドあり(DifyConfigModelまたは専用モデル経由)EmployeeNumberConfigViewModel.csを作成(Load / Save / Reset)(Step 2)EmployeeNumberConfigDialog.xamlをバインドされたコントロールで作成(Step 3)EmployeeNumberConfigDialog.xaml.csを最小限のcode-behindで作成(Step 4)| フォーマット | バリデーションルール | 例 |
|---|---|---|
| 4桁数値 | Length == 4 && All(IsDigit) | 1234 |
| 6桁数値 | Length == 6 && All(IsDigit) | 001234 |
| 英数字プレフィックス | Regex(@"^EMP-\d{4}$") | EMP-1234 |
| フリーフォーム | !IsNullOrWhiteSpace | 任意の非空文字列 |
dotnet-wpf-secure-config — このスキルが使用するDPAPI暗号化基盤dotnet-wpf-dify-api-integration — Dify APIのuserフィールドに社員番号を使用