ComponentOne Studio for WPF の C1FlexGrid コントロールでは、クリップボードへのコピーやクリップボードからの貼り付けがサポートされています。セル範囲を選択し、[CTRL+C] キーを押下すると、選択されたセル範囲内のデータ値がクリップボード内にコピーされます。このとき、列の区切りは Tab(0x09)
、行の区切りは CrLf(0x0d、0x0a)
の各制御文字に置き換わります。
このときに問題になるのが、セル内に複数行テキストが含まれている場合です。複数行テキストが含まれるセルの値をコピーし、別のセルに貼り付けようとすると、テキスト内の改行がセル範囲の行区切りとみなされてしまうため、複数行テキスト内の改行が正しく反映されません。
複数行テキストを含むセルのコピー&貼り付けを考慮する場合は、クリップボード操作をコーディング上で処理する必要があります。
実装方法
実装は簡単です。C1FlexGrid コントロールの PreviewKeyDown
イベントにて [CTRL+C]、[CTRL+V] キーの押下を検出し、既定のクリップボード処理に代わるカスタマイズされた方法によるテキストのコピーおよび貼り付け処理を行うようにします。
実際にサンプルを作成して確認してみましょう。以下は、検証用の C# プロジェクトの作成手順です。
1.新規プロジェクトを作成し、Xamlデザイナー上で MainWindow.xaml のウィンドウ上に C1FlexGrid コントロールを配置したら、以下のように設定します。
<c1:C1FlexGrid x:Name="fg" Margin="10" AutoGenerateColumns="False" ClipboardCopyMode="ExcludeHeader" ClipboardPasteMode="ExcludeHeader" Loaded="fg_Loaded" PreviewKeyDown="fg_PreviewKeyDown"/>
これにより、既定のクリップボード操作が許可されます。また、fg_Loaded
、fg_PreviewKeyDown
が自動生成されます。
2.MainWindow.xaml.cs を開き、コピーするデータを一時的に退避するための変数を定義します。
/// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { List<List<string>> copyData = null; // この行を追加 ~
3.fg_Loaded
内に、以下のコードを追加します。これは、グリッドの行・列を初期化し、テストデータを各セルに登録するための処理となります。
for (int colIndex = 0; colIndex < 4; colIndex++) fg.Columns.Add(new Column()); for (int rowIndex = 0; rowIndex < 10; rowIndex++) { fg.Rows.Add(new Row()); for (int colIndex = 0; colIndex < 2; colIndex++) fg[rowIndex, colIndex] = string.Format("複数行\rテキスト\r[{0}, {1}]", rowIndex, colIndex); } fg.AutoSizeRows(0, fg.Rows.Count - 1, 0);
4.fg_PreviewKeyDown
内に、以下のコードを追加します。これは、指定されたセル範囲のデータを一時的に copyData
変数に退避するための処理となります。
if (e.Key == Key.C && Keyboard.Modifiers == ModifierKeys.Control) { if (copyData == null) copyData = new List<List<string>>(); copyData.Clear(); for (int rowIndex = fg.Selection.TopRow; rowIndex <= fg.Selection.BottomRow; rowIndex++) { copyData.Add(new List<string>()); for (int colIndex = fg.Selection.LeftColumn; colIndex <= fg.Selection.RightColumn; colIndex++) copyData[rowIndex - fg.Selection.TopRow].Add( fg[rowIndex, colIndex].ToString()); } }
この処理により、選択された範囲のデータが copyData
に退避されます。
なおこのとき、e.Handled
引数は False のままなので、既定のクリップボードへのコピー処理はキャンセルされずに実行されます。そのため、メモ帳などの外部アプリに対するクリップボードからの貼り付け処理は引き続き利用できます。
5.続けて、以下のコードを追加します。これは、現在のセル位置を開始位置として、退避されたデータセル範囲に設定するための処理となります。
else if (e.Key == Key.V && Keyboard.Modifiers == ModifierKeys.Control) { if (copyData == null) return; e.Handled = true; for (int rowIndex = 0; rowIndex < copyData.Count && fg.Selection.Row + rowIndex < fg.Rows.Count; rowIndex++) { for (int colIndex = 0; colIndex < copyData[rowIndex].Count && fg.Selection.Column + colIndex < fg.Columns.Count; colIndex++) { fg[fg.Selection.Row + rowIndex, fg.Selection.Column + colIndex] = copyData[rowIndex][colIndex]; } } }
これにより、copyData
に退避されていたデータが各セルに設定されます。
なおこのとき、e.Handled
引数が True に設定されるため、既定のクリップボードからの貼り付け処理はキャンセルされる点にご注意ください。