ComponentOne Information

ComponentOne Studio/Wijmo/Xuniの最新情報を公開中

FlexGridで複数行テキストのコピー&貼り付けを考慮する

ComponentOne Studio for WPF の C1FlexGrid コントロールでは、クリップボードへのコピーやクリップボードからの貼り付けがサポートされています。セル範囲を選択し、[CTRL+C] キーを押下すると、選択されたセル範囲内のデータ値がクリップボード内にコピーされます。このとき、列の区切りは Tab(0x09) 、行の区切りは CrLf(0x0d、0x0a) の各制御文字に置き換わります。

このときに問題になるのが、セル内に複数行テキストが含まれている場合です。複数行テキストが含まれるセルの値をコピーし、別のセルに貼り付けようとすると、テキスト内の改行がセル範囲の行区切りとみなされてしまうため、複数行テキスト内の改行が正しく反映されません。

f:id:ComponentOne_JP:20171107111532p:plain
単一セル内の複数行テキストは複数のセルに展開されて貼り付けられます

複数行テキストを含むセルのコピー&貼り付けを考慮する場合は、クリップボード操作をコーディング上で処理する必要があります。

実装方法

実装は簡単です。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_Loadedfg_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 に設定されるため、既定のクリップボードからの貼り付け処理はキャンセルされる点にご注意ください。

実行してみる

では、プロジェクトを実行して動作を確認してみましょう。プロジェクトを起動したら、セル範囲を選択して [CTRL+C] キーを押下します。それから別のセルを選択し、[CTRL+V] キーを押下してみてください。正しく処理されていれば、データ内の改行を考慮してセルの値の貼り付けが行われます。

f:id:ComponentOne_JP:20171107115853p:plain
データ内の改行を考慮して貼り付けが行われます

上記で作成したサンプルは以下で公開しています。ご利用にあたっては、ComponentOne Studio for WPFの製品版もしくはトライアル版が必要です。

≫ ダウンロード(zipファイル:12KB)
≫ トライアル版はこちらから

ComponentOne