SPREAD for Windows Formsのシートでセルを移動するときには、LeaveCell
イベントとEnterCell
イベントが発生します。中でもLeaveCell
イベントには、セルの移動を制限したり移動先を変更できるなど、いろいろと便利な機能があります。
しかし、LeaveCell
イベントは、ヘルプやナレッジ文書にも記載されているように、ユーザーがマウスやキーボードを操作したときにしか発生しません。
ナレッジベースの「SetActiveCellメソッド呼び出し後にLeaveCellイベントおよびEnterCellイベントが発生しません」を見る
つまり、SetActiveCell
メソッドなどコードでセルを移動した場合はLeaveCell
イベントが発生しない仕様なのですが、実はコードでセルを移動するときにもLeaveCell
イベントを利用する方法があるのをご存知でしょうか?
今回はLeaveCell
イベントの機能を簡単におさらいしながら、その方法をご紹介したいと思います。
1. LeaveCellイベントの基本
ユーザーがマウスで他のセルをクリックしたときや矢印キーを押下して隣のセルへ移動したときには、SPREADコントロールのLeaveCell
イベントが発生します。このイベントは、例えば、次のような機能を実装するときなどに役立ちます。
- 移動先のセルを変更する
- 値に応じてセルの移動を禁止する
移動先を変更する例としては、現在のセルの値に応じて移動先を右隣のセルにしたり、さらにその次のセルに変更したりすることが考えられます。また、場合によっては、セルの移動そのものを禁止したいこともあります。このようなときには、LeaveCell
イベントの引数のe.NewColumn
やe.NewRow
を使って移動先を指定したり、e.Cancel
にTrueを設定して移動を禁止することができます。
次の例では、第1列のセルに「a」が入力されている場合には、次の行の第1列へ移動し、「b」の場合には同じ行の第3列へ移動します。また、第1列のセルに「c」が設定されているときには、セルの移動をキャンセルして現在のセルを編集状態にします。
private void fpSpread1_LeaveCell(object sender, FarPoint.Win.Spread.LeaveCellEventArgs e) { // 第1列のセルから同じ行の第2列のセルへ移動しようとした場合 if (e.Column == 0 && e.NewColumn == 1 && e.NewRow == e.Row) { // 移動元のセルの値に応じて移動先を変更します switch (fpSpread1.ActiveSheet.GetText(e.Row, e.Column)) { case "a": // 次の行の第1列のセルへ移動します e.NewColumn = 0; int newRow = e.Row + 1; if (newRow < fpSpread1.ActiveSheet.RowCount) { e.NewRow = newRow; } break; case "b": // 同じ行の第3列のセルへ移動します e.NewColumn = 2; break; case "c": // セルの移動をキャンセルして移動元のセルを編集状態にします e.Cancel = true; fpSpread1.StartCellEditing(e, false); break; } } }
※別の用途として、フォーカス枠以外の方法でアクティブセルを明示する(背景色を変更するなど)ためにLeaveCell
イベントを使うことも考えられますが、条件によっては直前のアクティブセルのスタイルをリセットできない可能性があるので、そのような利用方法はあまりお勧めできません。
2. LeaveCellイベント発生に関する制約
こんなに便利なLeaveCell
イベントですが、冒頭でご紹介したように、SetActiveCell
メソッドを呼び出してセルを移動したときには発生しません。そのため、ユーザー操作に加えてボタンのクリックなどを契機にしてSetActiveCell
メソッドでセルを移動する場合には、LeaveCell
イベントの機能を使うことができません。
例えば、LeaveCell
イベントでメッセージボックスを表示してユーザーにセル移動の可否を問い合わせ、許可された場合に限ってセルを移動する場合を考えます。ユーザー操作によるセル移動だけでなく、ボタンがクリックされたときには次の行の先頭列のセルへ移動するという動作が求められている場合、SetActiveCell
メソッドを呼び出したときにもLeaveCell
イベント内の処理を行いたいと誰しも考えると思いますが、残念なことに、このような場合にはLeaveCell
イベントが発生してくれません。
下のコードを実行したときには、前述のLeaveCell
イベントは発生しません。
private void button1_Click(object sender, EventArgs e) { int nextRow = fpSpread1.ActiveSheet.ActiveRowIndex + 1; if (nextRow < fpSpread1.ActiveSheet.RowCount) { // SetActiveCellメソッドを使ってアクティブセルを移動します fpSpread1.ActiveSheet.SetActiveCell(nextRow, 0); } }
この制約については、ヘルプやリリースノートそして冒頭で紹介したナレッジ文書で公開されていますので、ご確認いただければと思います。
【メモ】
ActiveX版のSPREADから.NET版のSPREADへ移行する際に、LeaveCellイベントの発生の仕方が異なっていることで戸惑うことがあります。
リリースノートの制限事項と注意点(イベント/メソッド)で公開されているように、SPREADから他のコントロールへフォーカスを移動した場合には、シート上ではセル移動が行われていないためLeaveCellイベントは発生しないので、この場合には.NET FrameworkのControlクラスのLeaveイベントを使う必要があります。
3. コードからLeaveCellイベントを発生させる
LeaveCell
イベントの発生に関する制約ですが、実はこれを回避する方法があります。
SPREADでは、LeaveCell
イベントの引数のLeaveCellEventArgs
クラスのコンストラクタが公開されているので、それを使ってLeaveCellEventHandler
を明示的に呼び出すことができます。
つまり、任意のタイミングでLeaveCell
イベントを発生させることが可能なのです。
では、具体的なコードを見てみましょう。下のSetSpreadActiveCell
という独自に作成したメソッドでは、SetActiveCell
メソッドを呼び出す直前にLeaveCell
イベントを発生させて、ユーザーの判断でセル移動の可否を決定できるようにしています。そして、このメソッドをbutton1_Click
イベントで呼び出すだけで、コードによるセル移動とLeaveCell
イベント内の処理の両方を実行することができます。
private void button1_Click(object sender, EventArgs e) { int nextRow = fpSpread1.ActiveSheet.ActiveRowIndex + 1; if (nextRow < fpSpread1.ActiveSheet.RowCount) { // LeaveCellイベントを発生してアクティブセルを移動します SetSpreadActiveCell(fpSpread1, nextRow, 0); } } private void SetSpreadActiveCell(FarPoint.Win.Spread.FpSpread spread, int newRow, int newCol) { // LeaveCellイベントの引数を作成します FarPoint.Win.Spread.LeaveCellEventArgs param = new FarPoint.Win.Spread.LeaveCellEventArgs(spread.GetRootWorkbook(), spread.ActiveSheet.ActiveRowIndex, spread.ActiveSheet.ActiveColumnIndex, newRow, newCol); // LeaveCellイベントを発生します spread.Invoke(new FarPoint.Win.Spread.LeaveCellEventHandler(fpSpread1_LeaveCell), new object[] { spread, param }); //' LeaveCellをキャンセルしない場合は、アクティブセルを移動します if (!param.Cancel) { spread.ActiveSheet.SetActiveCell(newRow, newCol); } } private void fpSpread1_LeaveCell(object sender, FarPoint.Win.Spread.LeaveCellEventArgs e) { // ユーザーの判断でセル移動の可否を決定します string strMsg = string.Format("アクティブセルを移動しますか?" + "\r\n現在のセル :({0}, {1})\r\n移動先のセル:({2}, {3})", e.Row, e.Column, e.NewRow, e.NewColumn); if (MessageBox.Show(strMsg, "", MessageBoxButtons.OKCancel) == DialogResult.Cancel) { e.Cancel = true; } }
上記のコードを実行したときの結果を以下に示します。LeaveCell
イベントで表示したメッセージボックスでOKボタンをクリックしてセル移動を許可したときのもので、A1セルからA2セルへアクティブセルが移動しています。
メッセージボックスでキャンセルボタンをクリックした場合も、セルの移動がキャンセルされ、セルがA1の位置から移動しないことが分かります。
4. LeaveCellイベントを発生させるもう一つの方法
これまでにご紹介したように、SetActiveCell
メソッドを呼び出した場合にはLeaveCell
イベントは発生しませんが、実はコードを使ってセルを移動したときにもLeaveCell
イベントが発生する場合があります。それは、SPREADのアクションマップの機能を使って組み込みの機能を呼び出した場合です。
下記のコードでは、組み込みのFarPoint.Win.Spread.Action
の機能(この例ではMoveToNextRowFirstColumn
の機能)を実行することで、セルを次の行の先頭の列へ移動しています。前述のbutton1_Click
イベントのコードをこちらに置き換えたときにも全く同じ動作になりますので、時間があればご確認いただければと思います。
private void button1_Click(object sender, EventArgs e) { FarPoint.Win.Spread.SpreadView spreadView = fpSpread1.GetRootWorkbook(); FarPoint.Win.Spread.Action action = spreadView.GetActionMap().Get(FarPoint.Win.Spread.SpreadActions.MoveToNextRowFirstColumn); action.PerformAction(spreadView); }
また、他のFarPoint.Win.Spread.Action
の機能を呼び出した場合でも、MoveToNextRowFirstColumn
のときと同じようにイベントが発生します。SPREADに備えられているアクションマップの機能については、こちらのヘルプをご参照ください。
おわりに
製品の仕様によってイベントが発生しない場合でも任意のタイミングでイベントを発生させる方法について解説してきました。また、SPREADでは、FarPoint.Win.Spread.Action
の機能を呼び出した場合には、ユーザー操作が行われたときと同じようにイベントが発生することもご紹介いたしました。これらの方法を使ってLeaveCell
イベントの便利な機能を活用していただければ幸いです。
製品Webサイトでは、SPREAD for Windows Formsのデモアプリケーションを公開しています。今回紹介したLeaveCell
のように細かな制御ができるさまざまな機能が数多く用意されていますので、以下より是非お試しください。