GrapeCity.devlog

グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉の、製品のTIPSや発売などに関する最新情報をお届けします。

コードからセルを移動したときもLeaveCellイベントを発生させるには?

SPREAD for Windows Formsのシートでセルを移動するときには、LeaveCellイベントとEnterCellイベントが発生します。中でもLeaveCellイベントには、セルの移動を制限したり移動先を変更できるなど、いろいろと便利な機能があります。

製品ヘルプ:LeaveCellイベント

しかし、LeaveCellイベントは、ヘルプやナレッジ文書にも記載されているように、ユーザーがマウスやキーボードを操作したときにしか発生しません。

つまり、SetActiveCellメソッドなどコードでセルを移動した場合はLeaveCellイベントが発生しない仕様なのですが、実はコードでセルを移動するときにもLeaveCellイベントを利用する方法があるのをご存知でしょうか?

今回はLeaveCellイベントの機能を簡単におさらいしながら、その方法をご紹介したいと思います。

  1. LeaveCellイベントの基本
  2. LeaveCellイベント発生に関する制約
  3. コードからLeaveCellイベントを発生させる
  4. LeaveCellイベントを発生させるもう一つの方法

1. LeaveCellイベントの基本

ユーザーがマウスで他のセルをクリックしたときや矢印キーを押下して隣のセルへ移動したときには、SPREADコントロールのLeaveCellイベントが発生します。このイベントは、例えば、次のような機能を実装するときなどに役立ちます。

  • 移動先のセルを変更する
  • 値に応じてセルの移動を禁止する

移動先を変更する例としては、現在のセルの値に応じて移動先を右隣のセルにしたり、さらにその次のセルに変更したりすることが考えられます。また、場合によっては、セルの移動そのものを禁止したいこともあります。このようなときには、LeaveCellイベントの引数のe.NewColumne.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イベントが発生します
ユーザー操作でセルを移動したときには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);
    }
}

SetActiveCellメソッドでセルを移動したときにはLeaveCellイベントが発生しません
SetActiveCellメソッドでセルを移動したときにはLeaveCellイベントが発生しません

この制約については、ヘルプやリリースノートそして冒頭で紹介したナレッジ文書で公開されていますので、ご確認いただければと思います。

【メモ】
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セルへアクティブセルが移動しています。

LeaveCellイベントでセルの移動を許可する例
LeaveCellイベントでセルの移動を許可する例

メッセージボックスでキャンセルボタンをクリックした場合も、セルの移動がキャンセルされ、セルがA1の位置から移動しないことが分かります。

LeaveCellイベントでセルの 移動を禁止する例
LeaveCellイベントでセルの移動を禁止する例

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のように細かな制御ができるさまざまな機能が数多く用意されていますので、以下より是非お試しください。

  • グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉ではエンジニア経験者を幅広く募集しています。
  • グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉の製品のデモアプリケーションをお試しください。