none
DataGridViewのイベントキャンセルについて RRS feed

  • 質問

  • はじめまして、新人PGです。

    少々というか大変困っているのでお知恵をお貸しください。

    AというプログラムでBというプログラムのDataGridViewのHeadertextを変更します。

    その際Bでは

    DataGridViewのHeadertextが変わったのでCellValueChangedが発生します

    CellValueChangedにはe.indexとe.RowIndexを参照して値を取ってくるという処理が入っています。

    しかし、Headertextを変更し発生したCellValueChangedにはe.indexは整数なのですが、e.RowIndexは-1を格納しています。

    この状況で値を取るとエラーが発生します。

    このエラーを解決するために

    Aというプログラムに

    ※ここにBというプログラムのCellValueChangedをキャンセルするコード

    e.HeaderText = "hugahuga";

    ※ここにBというプログラムのCellValueChangedを登録するコード

    という処理をしたいのですが、キャンセルするコードと登録するコードはどのようにすればよいでしょうか?

    2014年4月8日 15:02

回答

  • RowIndexがマイナスの時は値をとらないという選択は無いのでしょうか?

    CellValueChangedは値が変化済みだから発生するイベントであり、発生してしまってからキャンセルしても手遅れです。

    そもそもHeaderTextを変更できないようにする方法として、SetValueをOverridesしたHeaderCellにしてしまう方法。(DataGridViewRow.HeaderCellの差し替えも同様)

    Public Class Form1
    
        Private dgv As DataGridView
    
        Public Sub New()
            InitializeComponent()
    
            Dim btnA As New Button() With {.Text = "Test"}
            AddHandler btnA.Click, AddressOf btnA_Click
            Me.Controls.Add(btnA)
    
            dgv = New DataGridViewEx()
            dgv.Columns.Add(New DataGridViewTextBoxColumn() With _
                            {
                                .HeaderCell = New DataGridViewColumnHeaderCellEx()
                            })
            dgv.Columns.Add(New DataGridViewTextBoxColumn() With _
                            {
                                .HeaderCell = New DataGridViewColumnHeaderCellEx()
                            })
            dgv.Top = btnA.Height + 10
            dgv.Height = Me.ClientSize.Height - dgv.Top
            dgv.Width = Me.ClientSize.Width
            dgv.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
    
            AddHandler dgv.CellValueChanged, AddressOf dgv_CellValueChanged
    
            dgv.Columns(0).HeaderCell = New DataGridViewColumnHeaderCellEx()
    
            Me.Controls.Add(dgv)
    
        End Sub
    
        Class DataGridViewColumnHeaderCellEx
            Inherits DataGridViewColumnHeaderCell
            Protected Overrides Function SetValue(rowIndex As Integer, value As Object) As Boolean
                If (rowIndex >= 0) Then
                    Return MyBase.SetValue(rowIndex, value)
                Else
                    Return False
                End If
            End Function
        End Class
    
        Private Sub btnA_Click(ByVal sender As Object, ByVal e As EventArgs)
            dgv.Columns(0).HeaderText = DateTime.Now.ToString()
            dgv.Rows(0).Cells(0).Value = 1.23
        End Sub
    
        Private Sub dgv_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs)
            If (e.RowIndex < 0 OrElse e.ColumnIndex < 0) Then
                Return 'ヘッダの時は処理しない
            End If
    
            MessageBox.Show(dgv(e.ColumnIndex, e.RowIndex).Value)
        End Sub
    
    End Class

    値は変更されてしまうけどヘッダの時はCellValueChangedを発生させない方法として、DataGridViewのOnCellValueChangedをOverridesする方法

    Class DataGridViewEx
        Inherits DataGridView
    
        Protected Overrides Sub OnCellValueChanged(e As System.Windows.Forms.DataGridViewCellEventArgs)
            If (e.ColumnIndex >= 0 AndAlso e.RowIndex >= 0) Then
                'DataGridView::OnCellValueChangedがCellValueChangedイベントを発生させるので
                'Overridesして呼ばなければイベントは発生しない
                MyBase.OnCellValueChanged(e)
            End If
        End Sub
    End Class

    以上のように対処はできますが、そもそもAがBを無制限に操作できるのは良くないので、操作できる内容をインターフェースにするなどして制限する方が良いとは思います。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2014年4月8日 19:25
    • 回答としてマーク Load1001 2014年4月9日 15:55
    2014年4月8日 19:18
  • イベントハンドラを登録および解除するのは、AddHandlerおよびRemoveHandlerを使いますが、これで事足りるのでしょうか?

    AddHandler と RemoveHandler
    http://msdn.microsoft.com/ja-jp/library/6yyk8z93(v=vs.90).aspx


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク Load1001 2014年4月9日 15:55
    2014年4月9日 0:51
    モデレータ

すべての返信

  • RowIndexがマイナスの時は値をとらないという選択は無いのでしょうか?

    CellValueChangedは値が変化済みだから発生するイベントであり、発生してしまってからキャンセルしても手遅れです。

    そもそもHeaderTextを変更できないようにする方法として、SetValueをOverridesしたHeaderCellにしてしまう方法。(DataGridViewRow.HeaderCellの差し替えも同様)

    Public Class Form1
    
        Private dgv As DataGridView
    
        Public Sub New()
            InitializeComponent()
    
            Dim btnA As New Button() With {.Text = "Test"}
            AddHandler btnA.Click, AddressOf btnA_Click
            Me.Controls.Add(btnA)
    
            dgv = New DataGridViewEx()
            dgv.Columns.Add(New DataGridViewTextBoxColumn() With _
                            {
                                .HeaderCell = New DataGridViewColumnHeaderCellEx()
                            })
            dgv.Columns.Add(New DataGridViewTextBoxColumn() With _
                            {
                                .HeaderCell = New DataGridViewColumnHeaderCellEx()
                            })
            dgv.Top = btnA.Height + 10
            dgv.Height = Me.ClientSize.Height - dgv.Top
            dgv.Width = Me.ClientSize.Width
            dgv.Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
    
            AddHandler dgv.CellValueChanged, AddressOf dgv_CellValueChanged
    
            dgv.Columns(0).HeaderCell = New DataGridViewColumnHeaderCellEx()
    
            Me.Controls.Add(dgv)
    
        End Sub
    
        Class DataGridViewColumnHeaderCellEx
            Inherits DataGridViewColumnHeaderCell
            Protected Overrides Function SetValue(rowIndex As Integer, value As Object) As Boolean
                If (rowIndex >= 0) Then
                    Return MyBase.SetValue(rowIndex, value)
                Else
                    Return False
                End If
            End Function
        End Class
    
        Private Sub btnA_Click(ByVal sender As Object, ByVal e As EventArgs)
            dgv.Columns(0).HeaderText = DateTime.Now.ToString()
            dgv.Rows(0).Cells(0).Value = 1.23
        End Sub
    
        Private Sub dgv_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs)
            If (e.RowIndex < 0 OrElse e.ColumnIndex < 0) Then
                Return 'ヘッダの時は処理しない
            End If
    
            MessageBox.Show(dgv(e.ColumnIndex, e.RowIndex).Value)
        End Sub
    
    End Class

    値は変更されてしまうけどヘッダの時はCellValueChangedを発生させない方法として、DataGridViewのOnCellValueChangedをOverridesする方法

    Class DataGridViewEx
        Inherits DataGridView
    
        Protected Overrides Sub OnCellValueChanged(e As System.Windows.Forms.DataGridViewCellEventArgs)
            If (e.ColumnIndex >= 0 AndAlso e.RowIndex >= 0) Then
                'DataGridView::OnCellValueChangedがCellValueChangedイベントを発生させるので
                'Overridesして呼ばなければイベントは発生しない
                MyBase.OnCellValueChanged(e)
            End If
        End Sub
    End Class

    以上のように対処はできますが、そもそもAがBを無制限に操作できるのは良くないので、操作できる内容をインターフェースにするなどして制限する方が良いとは思います。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2014年4月8日 19:25
    • 回答としてマーク Load1001 2014年4月9日 15:55
    2014年4月8日 19:18
  • イベントハンドラを登録および解除するのは、AddHandlerおよびRemoveHandlerを使いますが、これで事足りるのでしょうか?

    AddHandler と RemoveHandler
    http://msdn.microsoft.com/ja-jp/library/6yyk8z93(v=vs.90).aspx


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク Load1001 2014年4月9日 15:55
    2014年4月9日 0:51
    モデレータ