一键导入
dotnet-wpf-ocr-parameter-input
こんなときに使う: WPFにOCR実行パラメータ入力UIタブを構築。進捗表示付き。OCR処理タブに設定可能な入力フィールドを追加する際に使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
こんなときに使う: WPFにOCR実行パラメータ入力UIタブを構築。進捗表示付き。OCR処理タブに設定可能な入力フィールドを追加する際に使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | dotnet-wpf-ocr-parameter-input |
| description | こんなときに使う: WPFにOCR実行パラメータ入力UIタブを構築。進捗表示付き。OCR処理タブに設定可能な入力フィールドを追加する際に使用。 |
.NET WPFアプリケーションにOCR実行パラメータ入力UIタブを追加するエンドツーエンドワークフロー:設定可能な入力フィールド(ComboBox、TextBox、CheckBox)、IProgress<T>による非同期OCR実行、リアルタイム進捗バーとログ表示、イベントベースの結果ハンドオフ(親ViewModelへの受け渡し)。
以下の場合にこのスキルを使用してください:
dotnet-wpf-pdf-preview — PDFアップロードとWebView2プレビュー(PDFパス入力を提供)dotnet-wpf-dify-api-integration — OCR抽出バックエンド用Dify API連携dotnet-oracle-wpf-integration — OCR結果をOracleデータベースに保存dotnet-wpf-comparison-view — OCR結果を元のPDFと並べて比較表示git-commit-practices — 各ステップをアトミックな変更としてコミットCommunityToolkit.Mvvm (ObservableObject, [ObservableProperty], [RelayCommand])IOcrUseCase)とOCRバックエンド(Dify等)IProgress<T>を使用(継続は力)コード作成前にOCRタブに必要な入力フィールドを決定するときに使用します。
⚠️ ユーザーに確認してください — 必要な入力フィールドを確認します。具体的なフィールドはユースケースにより異なるため、仮定しないでください。まず要件を収集し、それからコードを生成します。
一般的なフィールドタイプ:
フィールド定義テンプレート:
public class OcrInputField
{
public string Label { get; set; }
public string FieldType { get; set; } // "ComboBox", "TextBox", "CheckBox"
public List<string>? Options { get; set; } // For ComboBox
}
要件収集の例:
| フィールド名 | タイプ | オプション | 必須 |
|---|---|---|---|
| カテゴリ | ComboBox | ユーザーに確認 | ✅ |
| ドキュメントタイプ | ComboBox | ユーザーに確認 | ✅ |
| 備考 | TextBox | 自由入力 | ❌ |
| 輸出フラグ | CheckBox | オン/オフ | ❌ |
YourApp/
├── Views/
│ └── OcrProcessTabView.xaml # 🆕 入力フィールド+進捗付きタブUI
│ └── OcrProcessTabView.xaml.cs # 🆕 最小限のcode-behind
├── ViewModels/
│ └── OcrProcessTabViewModel.cs # 🆕 入力状態+OCR実行+進捗
└── Models/
└── ProgressLogItem.cs # 🆕 進捗ログエントリモデル
Values: ニュートラル / 基礎と型
入力フィールド、OCR実行、進捗追跡を管理するViewModelを実装するときに使用します。
CommunityToolkit.Mvvmを使用してOcrProcessTabViewModelを作成します。入力フィールドのプロパティはユースケースごとにカスタマイズします(Step 1の結果)。進捗追跡とOCR実行は固定パターンに従います。
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace YourApp.ViewModels
{
public partial class OcrProcessTabViewModel : ObservableObject
{
private readonly IOcrUseCase _useCase;
// --- Input fields (customize per use case from Step 1) ---
[ObservableProperty] private string selectedCategory = "";
[ObservableProperty] private string selectedType = "";
[ObservableProperty] private string remarks = "";
// --- Progress tracking (fixed pattern) ---
[ObservableProperty] private int progressValue;
[ObservableProperty] private string progressMessage = "";
[ObservableProperty] private bool isProcessing;
[ObservableProperty] private bool canStartOcr;
// --- Collections ---
public ObservableCollection<string> CategoryItems { get; } = new();
public ObservableCollection<string> TypeItems { get; } = new();
public ObservableCollection<ProgressLogItem> ProgressItems { get; } = new();
/// <summary>
/// Raised when OCR completes. Parent ViewModel subscribes to handle results.
/// </summary>
public event EventHandler<IEnumerable<object>>? OcrCompleted;
public OcrProcessTabViewModel(IOcrUseCase useCase)
=> _useCase = useCase;
[RelayCommand(CanExecute = nameof(CanStartOcr))]
private async Task StartOcrAsync()
{
IsProcessing = true;
ProgressValue = 0;
ProgressItems.Clear();
var progress = new Progress<(int percent, string message)>(p =>
{
ProgressValue = p.percent;
ProgressMessage = p.message;
ProgressItems.Add(new ProgressLogItem(DateTime.Now, "🔄", p.message, "Running"));
});
try
{
var results = await _useCase.ExecuteAsync(/* params */, progress);
ProgressItems.Add(new ProgressLogItem(DateTime.Now, "✅", "OCR completed", "Done"));
ProgressValue = 100;
OcrCompleted?.Invoke(this, results);
}
catch (Exception ex)
{
ProgressItems.Add(new ProgressLogItem(DateTime.Now, "❌", ex.Message, "Error"));
}
finally
{
IsProcessing = false;
}
}
/// <summary>
/// Called by parent ViewModel when a PDF is uploaded.
/// Enables the Start button.
/// </summary>
public void OnPdfUploaded(string pdfPath)
{
CanStartOcr = true;
StartOcrCommand.NotifyCanExecuteChanged();
}
/// <summary>
/// Resets all progress state for re-execution.
/// </summary>
public void Reset()
{
ProgressItems.Clear();
ProgressValue = 0;
ProgressMessage = "";
CanStartOcr = false;
StartOcrCommand.NotifyCanExecuteChanged();
}
}
}
CanExecuteをコマンドに使用する理由: PDFがアップロードされるまでStartボタンは無効化されます。CanStartOcrが変更されたとき、NotifyCanExecuteChanged()がボタンの状態を更新します。
Values: 基礎と型 / 継続は力
入力フィールド、進捗バー、進捗ログ、Startボタンを持つタブUIを作成するときに使用します。
タブレイアウトは4行Gridを使用:入力フィールドセクション、パーセンテージオーバーレイ付き進捗バー、スクロール可能な進捗ログ(GridViewカラム付きListView)、PDFアップロード後に有効化されるStartボタン。
<UserControl x:Class="YourApp.Views.OcrProcessTabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Input Fields -->
<RowDefinition Height="Auto"/> <!-- Progress Bar -->
<RowDefinition Height="*"/> <!-- Progress Log -->
<RowDefinition Height="Auto"/> <!-- Start Button -->
</Grid.RowDefinitions>
<!-- Input Fields (customize per use case) -->
<StackPanel Grid.Row="0" Margin="10">
<TextBlock Text="Category" FontWeight="Bold"/>
<ComboBox ItemsSource="{Binding CategoryItems}"
SelectedItem="{Binding SelectedCategory}"
Margin="0,4,0,10"/>
<TextBlock Text="Document Type" FontWeight="Bold"/>
<ComboBox ItemsSource="{Binding TypeItems}"
SelectedItem="{Binding SelectedType}"
Margin="0,4,0,10"/>
<TextBlock Text="Remarks" FontWeight="Bold"/>
<TextBox Text="{Binding Remarks, UpdateSourceTrigger=PropertyChanged}"
AcceptsReturn="True" Height="60"
Margin="0,4,0,0"/>
</StackPanel>
<!-- Progress Bar with Percentage Overlay -->
<Grid Grid.Row="1" Margin="10,5">
<ProgressBar Value="{Binding ProgressValue}" Maximum="100" Height="20"/>
<TextBlock Text="{Binding ProgressValue, StringFormat='{}{0}%'}"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontWeight="Bold"/>
</Grid>
<!-- Progress Log -->
<ListView Grid.Row="2" ItemsSource="{Binding ProgressItems}" Margin="10,5">
<ListView.View>
<GridView>
<GridViewColumn Header="Time" Width="80"
DisplayMemberBinding="{Binding Timestamp, StringFormat='{}{0:HH:mm:ss}'}"/>
<GridViewColumn Header="" Width="30"
DisplayMemberBinding="{Binding Icon}"/>
<GridViewColumn Header="Message" Width="200"
DisplayMemberBinding="{Binding Message}"/>
<GridViewColumn Header="Status" Width="80"
DisplayMemberBinding="{Binding Status}"/>
</GridView>
</ListView.View>
</ListView>
<!-- Start Button (enabled after PDF upload) -->
<Button Grid.Row="3" Content="Start OCR"
Command="{Binding StartOcrCommand}"
Background="#4CAF50" Foreground="White" FontWeight="Bold"
Margin="10" Padding="15,8" FontSize="14"/>
</Grid>
</UserControl>
WindowではなくUserControlを使用する理由: タブは親のTabControlに埋め込まれます。UserControlは自然に統合されますが、Windowは別ウィンドウ管理が必要になります。
Values: 基礎と型 / ニュートラル
ListViewに表示される個々の進捗ログエントリのデータモデルを定義するときに使用します。
進捗ログの各行に対するシンプルなイミュータブルモデルを作成します。コンストラクタにより、作成時にすべてのフィールドが設定されることを保証します。
namespace YourApp.Models
{
public class ProgressLogItem
{
public DateTime Timestamp { get; }
public string Icon { get; }
public string Message { get; }
public string Status { get; }
public ProgressLogItem(DateTime timestamp, string icon, string message, string status)
{
Timestamp = timestamp;
Icon = icon;
Message = message;
Status = status;
}
}
}
アイコン規約:
| アイコン | 意味 |
|---|---|
| 🔄 | 処理中 / 進行中 |
| ✅ | 正常完了 |
| ❌ | エラー発生 |
| ⚠️ | 警告 |
Values: 基礎と型 / 成長の複利
OCRタブを親ViewModelに接続し、TabControlに統合するときに使用します。
親ViewModelがタブViewModelを作成し、OcrCompletedをサブスクライブしてタブ切り替えを管理します。PDFアップロードイベントはOnPdfUploaded経由で親からOCRタブに流れます。
親ViewModelの接続 — OcrCompletedをサブスクライブし、OnPdfUploadedを呼び出す:
OcrTab = new OcrProcessTabViewModel(useCase);
OcrTab.OcrCompleted += OnOcrCompleted;
イベントフロー:
PDF Upload → Parent.NotifyPdfUploaded() → OcrTab.OnPdfUploaded()
↓ (enables Start button)
User clicks Start → OcrTab.StartOcrAsync() → IProgress updates UI
↓ (on completion)
OcrTab.OcrCompleted event → Parent.OnOcrCompleted() → Switch to results tab
完全な接続例(親ViewModel、TabControl、状態リセット): references/detailed-patterns.md
Values: ニュートラル / 継続は力
Step 1で収集した具体的なユースケース要件に合わせて、生成されたスケルトンを適用するときに使用します。
⚠️ プレースホルダーフィールドを置換してください — Step 1で特定した実際のフィールドに置き換えます。以下の表がカスタマイズのガイドです:
| カスタマイズ項目 | ファイル | 変更内容 |
|---|---|---|
| 入力フィールドプロパティ | OcrProcessTabViewModel.cs | [ObservableProperty]フィールドの追加/削除 |
| ComboBoxオプション | OcrProcessTabViewModel.cs | ObservableCollectionアイテムの設定 |
| XAML入力セクション | OcrProcessTabView.xaml | ComboBox、TextBox、CheckBoxコントロールの追加/削除 |
| ユースケースパラメータ | StartOcrAsync() | _useCase.ExecuteAsync()に正しい入力値を渡す |
| バリデーションルール | OcrProcessTabViewModel.cs | OCR実行前のフィールドバリデーション追加 |
CheckBoxトグルフィールドの追加:
// ViewModel
[ObservableProperty] private bool isExport;
<!-- XAML -->
<CheckBox Content="Export" IsChecked="{Binding IsExport}" Margin="0,10,0,0"/>
必須フィールドバリデーションの追加:
[RelayCommand(CanExecute = nameof(CanStartOcr))]
private async Task StartOcrAsync()
{
// ✅ Validate required fields before execution
if (string.IsNullOrWhiteSpace(SelectedCategory))
{
ProgressItems.Add(new ProgressLogItem(DateTime.Now, "⚠️", "Category is required", "Validation"));
return;
}
// ... proceed with OCR
}
Values: ニュートラル / 基礎と型
What: スレッドセーフな進捗コールバックのためにIProgress<(int percent, string message)>をユースケースに渡します。
Why: IProgress<T>は作成時にSynchronizationContextをキャプチャし、UIスレッドへのコールバックディスパッチを自動的に行います。手動のDispatcher.Invokeは不要です。
Values: 継続は力(非同期の型を正しく使う)
What: コールバックが自動的にマーシャリングされるよう、UIスレッド上でProgress<T>インスタンスを作成します。
Why: Progress<T>がバックグラウンドスレッドで作成されると、コールバックはそのスレッドで実行され、ObservableCollectionの更新時に例外をスローします。
// ✅ CORRECT — Created on UI thread, callbacks auto-dispatch
var progress = new Progress<(int percent, string message)>(p =>
{
ProgressValue = p.percent;
ProgressItems.Add(new ProgressLogItem(DateTime.Now, "🔄", p.message, "Running"));
});
// ❌ WRONG — Created inside Task.Run, callbacks on background thread
await Task.Run(() =>
{
var progress = new Progress<(int, string)>(...); // Wrong thread
});
Values: 基礎と型(スレッド安全の型)
What: 開始時にIsProcessing = trueを設定し、CanExecuteで重複実行を防止します。
Why: OCR実行中にStartをダブルクリックすると、並列プロセスが起動し、結果が破損し、進捗表示が混乱する可能性があります。
Values: ニュートラル(安全なUI操作)
What: 新しいPDFがアップロードされたときにProgressItemsをクリアし、ProgressValueをリセットし、CanStartOcrを更新します。
Why: 前回実行の古い進捗がユーザーを誤解させます。クリーンな状態により、各実行が新鮮な状態で開始されます。
Values: 継続は力(再実行の信頼性)
Problem: バックグラウンドスレッドからObservableCollectionやObservablePropertyを更新するとInvalidOperationExceptionがスローされます。
Solution: Progress<T>をUIスレッド上(awaitの前)で作成します。バックグラウンドスレッドからのIProgress<T>.Report()呼び出しは、キャプチャされたSynchronizationContextに自動的にディスパッチされます。
// ❌ WRONG — Direct collection update from background thread
await Task.Run(() =>
{
ProgressItems.Add(new ProgressLogItem(...)); // Throws!
});
// ✅ CORRECT — IProgress<T> handles marshaling
var progress = new Progress<(int percent, string message)>(p =>
{
ProgressItems.Add(new ProgressLogItem(DateTime.Now, "🔄", p.message, "Running"));
});
await _useCase.ExecuteAsync(progress); // Reports from background thread safely
Problem: IsProcessingがtrueに設定されたまま例外時にリセットされず、Startボタンが永久に無効化されます。
Solution: 常にfinallyブロックでIsProcessingをリセットします。
// ❌ WRONG — IsProcessing stuck on exception
IsProcessing = true;
var results = await _useCase.ExecuteAsync(progress);
IsProcessing = false; // Never reached on exception
// ✅ CORRECT — finally guarantees reset
try { var results = await _useCase.ExecuteAsync(progress); }
finally { IsProcessing = false; }
Problem: 前回実行のログエントリが新しい実行と混在し、ユーザーが混乱します。
Solution: 実行開始時に毎回ProgressItems.Clear()とProgressValue = 0を呼び出します。
[RelayCommand(CanExecute = nameof(CanStartOcr))]
private async Task StartOcrAsync()
{
// ✅ Always clear before starting
ProgressItems.Clear();
ProgressValue = 0;
// ... execute OCR
}
What: UIスレッドから非同期OCR操作に対して.Wait()や.Resultを呼び出すこと。
Why It's Wrong: UIスレッドをブロックし、ウィンドウがフリーズし、進捗バーの更新が妨げられ、SynchronizationContextでデッドロックを引き起こす可能性があります。
Better Approach: 全体を通してasync Taskとawaitを使用します。[RelayCommand]属性は非同期実行を正しく処理するIAsyncRelayCommandを生成します。
// ❌ WRONG — Blocks UI, no progress updates
[RelayCommand]
private void StartOcr()
{
var results = _useCase.ExecuteAsync(progress).Result; // Deadlock risk
}
// ✅ CORRECT — Non-blocking, progress updates flow
[RelayCommand(CanExecute = nameof(CanStartOcr))]
private async Task StartOcrAsync()
{
var results = await _useCase.ExecuteAsync(progress);
}
What: ユーザーに確認せずに、特定のフィールド名とオプションをViewModelに直接埋め込むこと。
Why It's Wrong: ユースケースごとに入力要件が異なります。ハードコードされたフィールドは、要件変更時にタブ全体のリファクタリングを強制します。
Better Approach: Step 1に従い、ユーザーに必要なフィールドを確認します。ユーザーの要件からViewModelとXAMLを生成します。硬直的な実装ではなく、スケルトンパターンを提供してください。
ProgressLogItemモデルクラスを作成(Step 4)OcrProcessTabViewModelを作成(Step 2)OcrProcessTabView.xamlを作成(Step 3)OcrCompletedイベントを接続(Step 5)TabControlに統合(Step 5)OnPdfUploadedを接続(Step 5)| ファイル | 目的 | レイヤー |
|---|---|---|
OcrProcessTabView.xaml | 入力フィールド+進捗表示付きタブUI | View |
OcrProcessTabView.xaml.cs | 最小限のcode-behind | View (code-behind) |
OcrProcessTabViewModel.cs | 入力状態+OCR実行+進捗 | ViewModel |
ProgressLogItem.cs | 進捗ログエントリモデル | Model |
| アイコン | 用途 | タイミング |
|---|---|---|
| 🔄 | 進行中 | 各進捗コールバック |
| ✅ | 成功 | OCR完了 |
| ❌ | エラー | 例外キャッチ |
| ⚠️ | 警告 | バリデーション失敗 |
dotnet-wpf-pdf-preview — このタブに入力を提供するPDFアップロードdotnet-wpf-dify-api-integration — OCR実行用Dify APIバックエンド[RelayCommand]と[ObservableProperty])モダン C#(12+)で record、パターンマッチング、合成、Result 型エラーハンドリングを使った 慣用的で高性能なコードを書く。こんなときに使う: 新規 C# コードの作成、API 設計、 または C# 12+ イディオムへのリファクタリング。
こんなときに使う: WPFアプリケーションに社員番号入力ダイアログを追加し、 DPAPIで暗号化された設定として社員IDを安全に保存したいとき。
こんなときに使う: 繰り返し発生する業務問い合わせ(監査、アンケート、コンプライアンス調査)に対して、 過去の回答実績とエビデンスを活用して回答するためのテンプレートスキル。 再利用可能な7ステップワークフローとスキャフォールディングファイルを提供する。
こんなときに使う: PDFテキスト抽出、Optical Character Recognition (OCR)、結合/分割、フォーム処理をuvベースの再現可能コマンドで実行したいときに使う。
こんなときに使う: Migrate Access SQL to Oracle, generate .NET C# code. Use when converting Access queries to Oracle.
こんなときに使う: .NETドメイン層で汎用的な重み付きフィールドマッチングとスコアリングを実装。