C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: DataGridViewでの入力値チェックとカーソル移動制御


(過去ログ 128 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■75893 / inTopicNo.1)  DataGridViewでの入力値チェックとカーソル移動制御
  
□投稿者/ kayo (1回)-(2015/05/14(Thu) 18:41:20)

分類:[VB.NET/VB2005 以降] 

開発環境:Windows7Pro(32bit)、Visual Studio 2013 試用版、.NET Framework4.5
元VB6.0プログラマーで、VB.NETは初心者です。よろしくお願いいたします。

【やりたい事】
DataGridViewにて、
・Tabキー押下でフォーカスが移動する際、入力可能なセルにフォーカスを移動する。(ReadOnly=TrueやVisible=Falseのセルはスキップする)
・Enterキー押下時はTabキーと同じ動作をする。
・できれば、
 最終行最終セルでTabキー押下時はDataGridViewの次(タブオーダー順での次)に配置されているコントロールに移動。
 先頭行先頭セルでShift+TAB押下時はDataGridViewの1つ前(タブオーダー順での1つ前)に配置されているコントロールに移動。

【参考にしたサイト】
・DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする
 http://dobon.net/vb/dotnet/datagridview/enterkeymoveright.html
・DataGridViewでTabStopを制御したい
 https://social.msdn.microsoft.com/Forums/ja-JP/c90ad027-95c3-430b-8ba1-8c16e5ba8873/datagridviewtabstop?forum=vbexpressja

【やったこと】
ProcessDialogKey と ProcessDataGridViewKey メソッドをオーバーライドする事で、やりたい事が実現できました。
以下が作成したProcessDialogKeyメソッドのソースです。

   Protected Overrides Function ProcessDialogKey(ByVal keyData As Keys) As Boolean

        If keyData = Keys.Tab OrElse keyData = Keys.Enter Then    '修飾キーなしで Tab もしくは Enter が押された
            Dim forward As Boolean = True
            Dim nextCell As DataGridViewCell = Me.GetNextCell(forward)    '←「GetNextCell」で次の入力可能なセルを取得しています
            If nextCell IsNot Nothing Then
                MyBase.CurrentCell = nextCell         '←★1 次の入力可能なセルに移動
            Else
                Me.SetNextControlOnParent(forward)    '←★2 DataGridViewの次に配置されているコントロールに移動
            End If
            Return True

        ElseIf (keyData = Keys.Tab + Keys.Shift) OrElse (keyData = Keys.Enter + Keys.Shift) Then
            Dim backward As Boolean = False
            Dim nextCell As DataGridViewCell = Me.GetNextCell(backward)
            If nextCell IsNot Nothing Then
                MyBase.CurrentCell = nextCell         '←★1 1つ前の入力可能なセルに移動
            Else
                Me.SetNextControlOnParent(backward)   '←★2 DataGridViewの1つ前に配置されているコントロールに移動
            End If
            Return True

        End If

        Return MyBase.ProcessDialogKey(keyData)

    End Function

  ★1 … MyBase の CurrentCell メソッドにてセルを移動
  ★2 … 「SetNextControlOnParent」内で、Form の SelectNextControl メソッドにてフォーカスを移動しています。


これで問題なく希望する動きをしてくれました。しかし、別の問題が生じてしまいました。
DataGridView の CellValidating イベントハンドラにて入力値チェックを行い、
不正な値が入力されたら入力を無かった事に(e.Cancel = True)しているのですが、
CellValidating はフォーカスが他に移ろうとする事によって発生するため、

(1) ProcessDialogKey にて セル(行1,列1) から セル(行1,列3) へフォーカスを移動させようとする …※まだ移動は確定していない
↓
(2) セル(行1,列1) の CellValidating が呼び出される
↓
(3) セル(行1,列1) の CellValidating が Cancel される
↓
(4) (1)のフォーカス移動が失敗する(エラーが発生する)
  エラー内容は「セル値の変更をコミットまたは中止できないため、操作は成功しませんでした。」

となってしまいます。(そりゃそうなるよね…という内容ですが、いざ完成して始めて気付いた次第です…。)

入力値のチェックも実装したい(不正な値の入力を未然に防ぎたい。不正な値が入力されたら e.Cancel=True としたい)のですが、
これを実現する方法はありますでしょうか?
つたない説明で申し訳ありません。
何卒よろしくお願いいたします。


 

引用返信 編集キー/
■75901 / inTopicNo.2)  Re[1]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ わくちゃん (1回)-(2015/05/15(Fri) 13:49:31)
私が何年か前に同じ問題にぶち当たった時の実装をご参考に。

ポイントはProcessDialogKeyメソッドでOnValidatingでの検証処理と同様な処理を実行し、
正しいデータ(e.Cancelがtrueにならないデータ)の場合だけ、タブ移動の独自ロジックを実行するようにすることです。



//コードここから
using System.ComponentModel;
using System.Windows.Forms;

namespace EnterTabDataGridViewSample
{

    public partial class CstDataGridView : DataGridView
    {
        public CstDataGridView()
        {
            InitializeComponent();
        }


        public CstDataGridView(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }


        protected override bool ProcessDialogKey(Keys keyData)
        {

            // 不正な入力の場合は通常処理
            if (this.Check((string)this.CurrentCell.EditedFormattedValue) == false)
            {
                return base.ProcessDialogKey(keyData);
            }


            if ((keyData == (Keys.Tab | Keys.Shift)) || (keyData == (Keys.Enter | Keys.Shift)))
            {
                DataGridViewCell nextCell = GetPrevCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, false, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }
            else if (keyData == Keys.Tab || keyData == Keys.Enter)
            {
                DataGridViewCell nextCell = GetNextCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, true, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }
            else
            {
                return base.ProcessDialogKey(keyData);
            }
        }



        protected override bool ProcessDataGridViewKey(KeyEventArgs e)
        {
            // 編集状態では呼ばれないのでチェック不要
            if ((e.KeyData == (Keys.Tab | Keys.Shift)) || (e.KeyData == (Keys.Enter | Keys.Shift)))
            {
                DataGridViewCell nextCell = GetPrevCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, false, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }
            else if (e.KeyData == Keys.Tab || e.KeyData == Keys.Enter)
            {
                DataGridViewCell nextCell = GetNextCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, true, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }

            return base.ProcessDataGridViewKey(e);
        }



        protected override void OnCellValidating(DataGridViewCellValidatingEventArgs e)
        {
            if (this.IsCurrentCellDirty)
            {
                e.Cancel = !this.Check((string)e.FormattedValue);
            }
        }


        // CellValidatingでのチェック処理を外出し
        private bool Check(string data)
        {
            int i;
            return int.TryParse(data, out i);
        }



        private DataGridViewCell GetNextCell()
        {
            if (this.CurrentCell == null)
            {
                return null;
            }

            for (int row = this.CurrentCell.RowIndex; row < this.RowCount; row++)
            {
                for (int col = 0; col < this.ColumnCount; col++)
                {
                    if (row == this.CurrentCell.RowIndex && col <= this.CurrentCell.ColumnIndex)
                    {
                        continue;
                    }

                    if (this[col, row].ReadOnly)
                    {
                        continue;
                    }

                    return this[col, row];
                }
            }

            return null;
        }



        private DataGridViewCell GetPrevCell()
        {
            if (this.CurrentCell == null)
            {
                return null;
            }

            for (int row = this.CurrentCell.RowIndex; row >= 0; row--)
            {
                for (int col = this.ColumnCount - 1; col >= 0; col--)
                {
                    if (row == this.CurrentCell.RowIndex && col >= this.CurrentCell.ColumnIndex)
                    {
                        continue;
                    }

                    if (this[col, row].ReadOnly)
                    {
                        continue;
                    }

                    return this[col, row];
                }
            }

            return null;
        }

    }
}
// ここまで



引用返信 編集キー/
■75906 / inTopicNo.3)  Re[2]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ kayo (2回)-(2015/05/16(Sat) 12:19:18)
No75901 (わくちゃん さん) に返信
>
> ポイントはProcessDialogKeyメソッドでOnValidatingでの検証処理と同様な処理を実行し、
> 正しいデータ(e.Cancelがtrueにならないデータ)の場合だけ、タブ移動の独自ロジックを実行するようにすることです。
>
なるほど、そういう発想が無かったのでとても参考になりました。
サンプルも提示していただきまして、ありがとうございました。

ただ、CstDataGridViewクラスの中にCheck処理を実装している点が、私が現在携わっているシステムには合わないかな…と感じました。
と言いますのは、Check処理は業務ロジックになりますので、業務ロジックをCstDataGridViewクラスに内包したくない為です。
(内包してしまうと、CstDataGridViewクラスはその画面でしか使えなくなってしまう為)
あと個人的に、業務ロジックをCstDataGridViewクラス内に書く事に違和感があります…。
引用返信 編集キー/
■75908 / inTopicNo.4)  Re[3]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ 魔界の仮面弁士 (325回)-(2015/05/16(Sat) 15:12:10)
No75906 (kayo さん) に返信
> 業務ロジックをCstDataGridViewクラス内に書く事に違和感があります…。
チェックロジックがどのような物か分かりませんが、クラス内に書きたくないなら、
ロジック部をイベントなりデリゲートなりで用意しておき、
その部分を利用する側(Form1)等で実装できるようにしておくとか。
引用返信 編集キー/
■75909 / inTopicNo.5)  Re[4]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ kayo (3回)-(2015/05/16(Sat) 21:26:39)
No75908 (魔界の仮面弁士 さん) に返信
> ■No75906 (kayo さん) に返信
> ロジック部をイベントなりデリゲートなりで用意しておき、
> その部分を利用する側(Form1)等で実装できるようにしておくとか。

恥ずかしながら「デリゲート」というものを始めて耳にしました。申し訳ございません。

現状、DataGridViewコントロールを継承したカスタムコントロール「DataGridViewEX」を Form1 に配置しております。
この場合、デリゲートするにはどのようにコーディングするのか、自分なりに調べてみたのですが、正直なところよく分からないでおります。
イメージとしては以下になるかと思うのですが、

----------------------------------------------------------------------------------------------------------------
'デリゲートの宣言
Public Delegate Function PreCheck(ByVal rowIndex As Integer, ByVal colIndex As Integer) As Boolean

'フォーム側の記述
Public Class Form1

    Private Sub DataGridViewEX1_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles DataGridViewEX1.CellValidating
        If e.ColumnIndex = 商品名の列の場合
       	    不正な値かチェックし、不正時は「e.Cancel = True」します
        ElseIf e.ColumnIndex = 数量の列の場合
	    同上
        ElseIf e.ColumnIndex = 単価の列の場合
	    同上
	:
	:
	:(チェックしたい列のチェック処理を記述)
	:
	:
	End If
    End Sub

    'DataGridViewEXクラスのProcessDialogKeyメソッドから実行させたいメソッド。
    '本来のCellValidatingイベントハンドラと同等の処理を行いますが、「e.Cancel=True」の代わりに「False(入力エラーの意味)」を返します。
    Public Function PreCellValidating(ByVal rowIndex As Integer, ByVal colIndex As Integer) As Boolean
        If colIndex = 商品名の列の場合
       	    不正な値かチェックし、不正時は「Return False」します
        ElseIf colIndex = 数量の列の場合
	    同上
        ElseIf colIndex = 単価の列の場合
	    同上
        :
        :
        :
	End If
	Return True    'エラーなしはTrueを返す
    End Sub

End Class

'データグリッドビュー側の記述
Public Class DataGridViewEX
    Inherits System.Windows.Forms.DataGridView

    Protected Overrides Function ProcessDialogKey(ByVal keyData As Keys) As Boolean

        If keyData = Keys.Tab OrElse keyData = Keys.Enter Then
	    '★ここで、フォーム(この例ではForm1)の PreCellValidating を実行したい
            


        ElseIf (keyData = Keys.Tab + Keys.Shift) OrElse (keyData = Keys.Enter + Keys.Shift) Then
	    '★ここで、フォーム(この例ではForm1)の PreCellValidating を実行したい



        End If

        Return MyBase.ProcessDialogKey(keyData)

    End Function

End Class
----------------------------------------------------------------------------------------------------------------

デリゲート宣言した「PreCheck」のインスタンスをどこで(Form1_Loadイベントで?)どのようにコーディングしたら良いのか、などが分からずにおります。
大変恐縮ですが、ご教示をお願いできませんでしょうか?

引用返信 編集キー/
■75917 / inTopicNo.6)  Re[5]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ わくちゃん (2回)-(2015/05/17(Sun) 16:26:19)
> デリゲート宣言した「PreCheck」のインスタンスをどこで(Form1_Loadイベントで?)どのようにコーディングしたら良いのか、などが分からずにおります。
> 大変恐縮ですが、ご教示をお願いできませんでしょうか?


デリゲート宣言は、新しい型を定義するイメージです。
メソッドの戻り値の型、引数の型及び数を定義します。

「PreCheck」を宣言しただけでは、新しい型を定義しただけにすぎませんので、PreCheck型の変数を用意する必要があります。

簡単に言うと、
・DataGridViewに検証メソッドのデリゲート宣言
・Form側でDataGridViewの検証メソッドへのデリゲートを設定
を実装します。


当方、VBの知識があまりありませんので、またまたC#で失礼しますが、ご参考になれば。
// Form
        public Form1()
        {
            InitializeComponent();
        }


        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // CstDataGridViewの検証処理にPreCellValidatingメソッドを設定します。
            this.cstDataGridView1.PreCheckProc = this.PreCellValidating;
        }


        // 検証に使用するメソッド
        // 戻り値、引数の型を CstDataGridView.PreCheckと合わせます。
        private bool PreCellValidating(int col, int row)
        {
            int i;
            return int.TryParse((string)this.cstDataGridView1[col, row].EditedFormattedValue, out i);
        }
    }
// Formここまで


// CstDataGridView
    public partial class CstDataGridView : DataGridView
    {
        // 検証メソッドのデリゲート宣言
        public delegate bool PreCheck(int colIndex, int rowIndex);


        public CstDataGridView()
        {
            InitializeComponent();
        }


        public CstDataGridView(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }


        // 検証メソッドを設定する変数
        public PreCheck PreCheckProc
        {
            get;
            set;
        }


        protected override bool ProcessDialogKey(Keys keyData)
        {
           

            // 不正な入力の場合は通常処理
            // 検証メソッドへのデリゲートが設定されている場合は検証処理を実行します。
            if (this.PreCheckProc != null && this.PreCheckProc(this.CurrentCell.ColumnIndex, this.CurrentCell.RowIndex) == false)
            {
                return base.ProcessDialogKey(keyData);
            }


            if ((keyData == (Keys.Tab | Keys.Shift)) || (keyData == (Keys.Enter | Keys.Shift)))
            {
                DataGridViewCell nextCell = GetPrevCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, false, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }
            else if (keyData == Keys.Tab || keyData == Keys.Enter)
            {
                DataGridViewCell nextCell = GetNextCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, true, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }
            else
            {
                return base.ProcessDialogKey(keyData);
            }
        }



        protected override bool ProcessDataGridViewKey(KeyEventArgs e)
        {
            // 編集状態では呼ばれないのでチェック不要
            if ((e.KeyData == (Keys.Tab | Keys.Shift)) || (e.KeyData == (Keys.Enter | Keys.Shift)))
            {
                DataGridViewCell nextCell = GetPrevCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, false, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }
            else if (e.KeyData == Keys.Tab || e.KeyData == Keys.Enter)
            {
                DataGridViewCell nextCell = GetNextCell();
                if (nextCell == null)
                {
                    this.Parent.SelectNextControl(this, true, true, true, true);
                }
                else
                {
                    this.CurrentCell = nextCell;
                }
                return true;
            }

            return base.ProcessDataGridViewKey(e);
        }



        protected override void OnCellValidating(DataGridViewCellValidatingEventArgs e)
        {
            if (this.IsCurrentCellDirty)
            {
                // 検証へのデリゲートが設定されている場合は検証処理を実行します。
                if (this.PreCheckProc != null && this.PreCheckProc(e.ColumnIndex, e.RowIndex) == false)
                {
                    e.Cancel = true;
                }
            }

            base.OnCellValidating(e);
        }


        private DataGridViewCell GetNextCell()
        {
            if (this.CurrentCell == null)
            {
                return null;
            }

            for (int row = this.CurrentCell.RowIndex; row < this.RowCount; row++)
            {
                for (int col = 0; col < this.ColumnCount; col++)
                {
                    if (row == this.CurrentCell.RowIndex && col <= this.CurrentCell.ColumnIndex)
                    {
                        continue;
                    }

                    if (this[col, row].ReadOnly)
                    {
                        continue;
                    }

                    return this[col, row];
                }
            }

            return null;
        }



        private DataGridViewCell GetPrevCell()
        {
            if (this.CurrentCell == null)
            {
                return null;
            }

            for (int row = this.CurrentCell.RowIndex; row >= 0; row--)
            {
                for (int col = this.ColumnCount - 1; col >= 0; col--)
                {
                    if (row == this.CurrentCell.RowIndex && col >= this.CurrentCell.ColumnIndex)
                    {
                        continue;
                    }

                    if (this[col, row].ReadOnly)
                    {
                        continue;
                    }

                    return this[col, row];
                }
            }

            return null;
        }

    }
// CstDataGridViewここまで

引用返信 編集キー/
■75918 / inTopicNo.7)  Re[6]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ kayo (4回)-(2015/05/17(Sun) 17:47:59)
わくちゃん様

ご教示ありがとうございました。
サンプル通りコーディングしたところ(VBに書き換えてはいます)、フォーム側の下記★印のところでコンパイルエラーになりました。

>         protected override void OnLoad(EventArgs e)
>         {
>             base.OnLoad(e);
> 
>             // CstDataGridViewの検証処理にPreCellValidatingメソッドを設定します。
>             this.cstDataGridView1.PreCheckProc = this.PreCellValidating;     ←★この部分でコンパイルエラー
>         }

エラー内容は以下になります。

'Private Function PreCellValidating(colIndex As Integer, rowIndex As Integer) As Boolean' のパラメーター 'colIndex' に対して引数が指定されていません。
'Private Function PreCellValidating(colIndex As Integer, rowIndex As Integer) As Boolean' のパラメーター 'rowIndex' に対して引数が指定されていません。


確かにその通りですが、かと言ってどうコーディングすれば良いのやら、私にはお手上げです…(汗)



引用返信 編集キー/
■75919 / inTopicNo.8)  Re[7]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ わくちゃん (4回)-(2015/05/17(Sun) 18:13:09)
No75918 (kayo さん) に返信
> わくちゃん様
>
> ご教示ありがとうございました。
> サンプル通りコーディングしたところ(VBに書き換えてはいます)、フォーム側の下記★印のところでコンパイルエラーになりました。
>
>> protected override void OnLoad(EventArgs e)
>> {
>> base.OnLoad(e);
>>
>> // CstDataGridViewの検証処理にPreCellValidatingメソッドを設定します。
>> this.cstDataGridView1.PreCheckProc = this.PreCellValidating;     ←★この部分でコンパイルエラー
>> }
>
> エラー内容は以下になります。
>
> 'Private Function PreCellValidating(colIndex As Integer, rowIndex As Integer) As Boolean' のパラメーター 'colIndex' に対して引数が指定されていません。
> 'Private Function PreCellValidating(colIndex As Integer, rowIndex As Integer) As Boolean' のパラメーター 'rowIndex' に対して引数が指定されていません。
>
>
> 確かにその通りですが、かと言ってどうコーディングすれば良いのやら、私にはお手上げです…(汗)
>
>
>

おそらく文法が間違っているのではないでしょうか

this.cstDataGridView1.PreCheckProc = this.PreCellValidating;

はVBで書くと

Me.cstDataGridView1.PreCheckProc = new CstDataGridView.PreCheck(AddressOf Me.PreCellValidating)

こんな感じになるかと思います。

引用返信 編集キー/
■75920 / inTopicNo.9)  Re[5]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ 魔界の仮面弁士 (326回)-(2015/05/18(Mon) 09:38:10)
2015/05/18(Mon) 15:50:04 編集(投稿者)

# キャンセル時の動作を間違えていたので修正:
## 修正前: Return e.Cancel
## 修正後: If e.Cancel Then Return True

No75909 (kayo さん) に返信
> 恥ずかしながら「デリゲート」というものを始めて耳にしました。

利用側としては「イベント」で実装するのが楽ですよ。
もちろんデリゲートでも良いですけど。


Public Class DataGridViewEX
 Inherits DataGridView

 Public Event PreCellValidating As DataGridViewCellCancelEventHandler

 Protected Overrides Function ProcessDialogKey(ByVal keyData As Keys) As Boolean
  Dim pos = Me.CurrentCellAddress
  If keyData = Keys.Tab OrElse keyData = Keys.Enter Then
   Dim e As New DataGridViewCellCancelEventArgs(pos.X, pos.Y)
   RaiseEvent PreCellValidating(Me, e)
   If e.Cancel Then Return True
  ElseIf (keyData = Keys.Tab Or Keys.Shift) OrElse (keyData = Keys.Enter Or Keys.Shift) Then
   Dim e As New DataGridViewCellCancelEventArgs(pos.X, pos.Y)
   RaiseEvent PreCellValidating(Me, e)
   If e.Cancel Then Return True
  End If
  Return MyBase.ProcessDialogKey(keyData)
 End Function
End Class


たとえば上記のようにしておけば、Form1 側にて、
DataGridViewEX1 に PreCellValidating イベントが現れます。

Private Sub DataGridViewEX1_PreValidating(sender As Object, e As DataGridViewCellCancelEventArgs) Handles DataGridViewEX1.PreValidating

DataGridViewEX1 の CellValidating イベントと使い方は同様です。
まぁ、ProcessDialogKey で拾い上げている都合上、
CellValidating と違って e.FormattedValue は無いですけどね。

もしも e.FormattedValue の処理が必要な場合は、DataGridViewEX にて
OnCellValidating メソッドをオーバーライドして、そこの冒頭で
RaiseEvent すれば OK です。今回は使わないでしょうけれども。
引用返信 編集キー/
■75924 / inTopicNo.10)  Re[8]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ kayo (5回)-(2015/05/18(Mon) 15:26:22)
No75919 (わくちゃん さん) に返信
>
> おそらく文法が間違っているのではないでしょうか
>
> this.cstDataGridView1.PreCheckProc = this.PreCellValidating;
>
> はVBで書くと
>
> Me.cstDataGridView1.PreCheckProc = new CstDataGridView.PreCheck(AddressOf Me.PreCellValidating)
>
> こんな感じになるかと思います。
>

返信が遅くなり申し訳ございません。
わくちゃん様のおっしゃる通りでした。
そのように修正するとコンパイルも通り、プレチェック処理も正常に動作しました。
ありがとうございました。

引用返信 編集キー/
■75925 / inTopicNo.11)  Re[6]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ kayo (6回)-(2015/05/18(Mon) 15:51:43)
No75920 (魔界の仮面弁士 さん) に返信
>
> 利用側としては「イベント」で実装するのが楽ですよ。
> もちろんデリゲートでも良いですけど。
>

本当ですね。
こちらはソースを追うのも楽で、理解がしやすかったです。
デリゲートは初心者には少々難解に思えました…(汗)

>
> DataGridViewEX1 の CellValidating イベントと使い方は同様です。
> まぁ、ProcessDialogKey で拾い上げている都合上、
> CellValidating と違って e.FormattedValue は無いですけどね。
>

今のところ EditedFormattedValue が参照できれば支障は無く、実際参照できましたので問題ありませんでした。

カスタムコントロールのクラス内に業務ロジックを書くことなく(=カスタムコントロールに汎用性を持たせたまま)、
件名の「DataGridViewでの入力値チェックとカーソル移動制御」が実現可能という事が分かり、嬉しいです。
Form側は CellValidating と PreCellValidating の2本立てになってしまいますが、これは妥協するしかないかなと思っております。
(それよりも入力不可のセルにカーソルが当たる事の方が、私は受け入れ難いので…。)
私は下請けで開発している身なので、こういう方法で実現可能ですという事を元請けの会社に説明し、そちらに最終判断をしてもらおうと思います。

アドバイスをいただきました わくちゃん さん、魔界の仮面弁士 さんには本当に感謝しています。ありがとうございました。m(_ _)m


解決済み
引用返信 編集キー/
■75926 / inTopicNo.12)  Re[7]: DataGridViewでの入力値チェックとカーソル移動制御
□投稿者/ 魔界の仮面弁士 (327回)-(2015/05/18(Mon) 18:36:42)
解決済みですが、以下、蛇足情報。
解決済みチェックは付けておきます。


No75925 (kayo さん) に返信
>>利用側としては「イベント」で実装するのが楽ですよ。
> 本当ですね。
> こちらはソースを追うのも楽で、理解がしやすかったです。
> デリゲートは初心者には少々難解に思えました…(汗)

デリゲートは一見複雑に見えるかもしれませんが、実際のところ、
イベントも、内部ではデリゲートを用いて処理されていますよ。


実際、先の私のコードでも
 Public Event PreCellValidating As DataGridViewCellCancelEventHandler
の部分の『DataGridViewCellCancelEventHandler』は「デリゲート型」だったりしますし。

※ なお、上記は以下のようにも書けます。
 Public Event PreCellValidating(sender As Object, e As DataGridViewCellCancelEventArgs)


--------------------

上記を、イベントではなくデリゲートとして実装する場合は、
 'Public Event PreCellValidating As DataGridViewCellCancelEventHandler 'これを
 Public PreCellValidating As DataGridViewCellCancelEventHandler 'このように変更
のように宣言します。この部分だけ見れば、イベントの場合と大差無いですよね。(※注1)


そしてデリゲートインスタンスの呼び出しは、イベントでいうところの
 RaiseEvent PreCellValidating(Me, e)
の代わりに
 Me.PreCellValidating(Me, e)
あるいは
 Me.PreCellValidating.Invoke(Me, Nothing)
で呼び出せば OK です。(※注2)


上記二点を比較してみれば、イベントとデリゲートの類似性が見えてくるのでは無いでしょうか。

とはいえ、イベントならばデリゲートという物の存在を利用者に意識させずに済みますので、
やはり今回は、Event として実装する方が使い勝手が良いでしょうね。(※注3, ※注4)



--------------------
※注1:
ここでは説明のために、Public なフィールド変数として簡易的に書いていますが、
カプセル化の観点からすれば、実際には No75917 のようにプロパティ化するか、
あるいは Private なフィールド変数にしておき、メソッド(あるいはコンストラクタ)の引数にて
それらを受け渡しさせた方が望ましいです。

 'DataGridViewEX 側
 Public Sub SetPreCellValidating(callback As DataGridViewCellCancelEventHandler)
  Me.PreCellValidating = callback
 End Sub


 'Form1 側
 Private Sub Form1_Load(sender As System.Object, e As EventArgs) Handles Me.Load
  Me.DataGridViewEX1.SetPreCellValidating(AddressOf Me.DataGridViewEX1_PreCellValidating)
 End Sub
 Private Sub DataGridViewEX1_PreCellValidating(a As Object, a As DataGridViewCellCancelEventArgs)
 End Sub


--------------------
※注2
ただし、Me.PreCellValidating が未割当の場合に備えて、
 If Me.PreCellValidating IsNot Nothing Then
での事前チェックが必要になってきます。
イベント(RaiseEvent 呼び出し)なら気にする必要は無いのですけれどね。

--------------------
※注3
「イベントならばデリゲートという物の存在を意識しなくて済む」とは書きましたが、
イベントでデリゲートインスタンスを明示的に管理する手法も、一応用意されています。

Public Class DataGridViewEX
 Inherits DataGridView

 Public Custom Event PreCellValidating As DataGridViewCellCancelEventHandler
  AddHandler(value As DataGridViewCellCancelEventHandler)
   Me.Events.AddHandler("PreCellValidating", value)
  End AddHandler
  RemoveHandler(value As DataGridViewCellCancelEventHandler)
   Me.Events.RemoveHandler("PreCellValidating", value)
  End RemoveHandler
  RaiseEvent(sender As Object, e As DataGridViewCellCancelEventArgs)
   DirectCast(Me.Events("PreCellValidating"), DataGridViewCellCancelEventHandler)(Me, e)
  End RaiseEvent
 End Event
End Class

--------------------
※注4
デリゲートに関して追加の情報。
https://code.msdn.microsoft.com/windowsdesktop/28-23f36a02
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -