- PR -

仮想モードのDataGridViewでの描画について

投稿者投稿内容
hei
ベテラン
会議室デビュー日: 2006/09/07
投稿数: 78
投稿日時: 2006-09-14 21:41
他の掲示板でも質問したのですが、回答が全く得られないのでこちらでもお願いします。
仮想モードのDataGridViewでCellValueNeeded,CellValuePushedイベントを実装しても、
DataGridViewを通さずにデータに設定した値をDataGridViewに反映するにはどうしたらよいのでしょうか?
仮想モードでなければ、データを直接いじってもすぐに反映されるのですが、
仮想モードではなぜかCellValueNeeded,CellValuePushedイベントを設定しても反映されません。
次のように、ボタンを押すと直接データの値を設定する簡単な例を2つ書いてみました。
ボタンを押した後,マウスを動かすなどした後ではCellValueNeededは発生していますが、
なぜ反映されないのでしょうか???
ご存知の方いらっしゃいましたらよろしくお願いします。



’例1、Button1つと、DataGridView1つをフォームに追加
Public Class Form1
Private _list As List(Of String) = New List(Of String)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.DataGridView1.VirtualMode = True
Me.DataGridView1.Columns.Add("テスト", "テスト")
Me.DataGridView1.Rows.AddCopies(0, 100)

For i As Integer = 0 To 100
_list.Add(i.ToString)
Next
End Sub

Private Sub DataGridView1_CellValueNeeded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded

e.Value = _list(e.RowIndex)
Debug.Print(e.Value.ToString)
End Sub

Private Sub DataGridView1_CellValuePushed(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles DataGridView1.CellValuePushed
_list(e.RowIndex) = e.Value.ToString
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
_list(0) = "直接設定された値"
End Sub
End Class



’例2
’Public Class Form1
Private _button As Button
Private _inheritedDataGridView As InheritedDataGridView
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
_button = New Button
_inheritedDataGridView = New InheritedDataGridView(_button)
Me.Controls.Add(_button)
Me.Controls.Add(_inheritedDataGridView)
_inheritedDataGridView.Top = _button.Top + _button.Height
End Sub
End Class

Public Class InheritedDataGridView
Inherits DataGridView
Private WithEvents _btn As Button
Private _list As List(Of String) = New List(Of String)
Public Sub New(ByVal button As Button)
_btn = button
Me.VirtualMode = True
Me.Columns.Add("テスト", "テスト")
Me.Rows.AddCopies(0, 100)
For i As Integer = 0 To 100
_list.Add(i.ToString)
Next
End Sub
Private Sub _btn_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _btn.Click
_list(0) = "直接代入された値"
MyBase.OnCellValueNeeded(New DataGridViewCellValueEventArgs(0, 0))
End Sub

Private Sub InheritedDataGridView_CellValueNeeded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles Me.CellValueNeeded
e.Value = _list(e.RowIndex)
End Sub

Private Sub InheritedDataGridView_CellValuePushed(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles Me.CellValuePushed
_list(e.RowIndex) = e.Value.ToString
End Sub
End Class
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2006-09-15 00:49
今実行できる環境がないので記憶をたどっていますが、

> Me.DataGridView1.Rows.AddCopies(0, 100)

でなく、

Me.DataGridView1.VirtualRowCount = 100

としたらどうなりますか?
たしか、Virtualなんとか というプロパティで行数を指定したような気がします。
私は Rows.AddCopies は使いませんでした。



Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-09-15 01:44
OnHogehoge メソッドを誤解しているような気がします。
OnHogehoge メソッドは Hogehoge イベントを発生させると説明されますが、これは要するに Hogehoge イベントに登録されたイベントハンドラを実行させる、と言う意味であってそれ以上ではありません。
分かりやすい例だと OnMouseMove 。これを呼び出してもマウスポインタが勝手に動いたりはしませんよね?
同様に、OnCellValueNeeded を呼び出したからと言って勝手に再描画されるわけではありません。

再描画が必要になった時に CellValueNeeded も呼ばれるんですから、データを変更した際に強制的に再描画を行えば良いわけです。
DataGridView には、Control から継承する再描画メソッドの他、色々と用意されています。
多すぎて確認するのが大変だという向きは、Windows フォーム DataGridView コントロールでの仮想モード を見てみるのも良いかも知れません。




引用:

masaさんの書き込み (2006-09-15 00:49) より:
Me.DataGridView1.VirtualRowCount = 100

としたらどうなりますか?
たしか、Virtualなんとか というプロパティで行数を指定したような気がします。


RowCount プロパティですね。
hei
ベテラン
会議室デビュー日: 2006/09/07
投稿数: 78
投稿日時: 2006-09-15 09:16
InvalidateCellメソッドでできました!
RowCountも知らなかったのでとても参考になりました。

ありがとうございました。

masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2006-09-15 10:06
InvalidateCell は強制的に再描画するものですから、
1回余分に描画を行っていることになるかもしれませんね。

今回の質問とは直接関係はありませんが、
仮想モード時はちょっと操作しただけで描画イベントが発生しています。
ですから、CellValueNeeded のような値に関するイベントの処理は
できるだけ「軽い」内容にしておく必要があります。
Debug.WriteLine をいくつか仕込むだけでも「もっさり」することもあります。
hei
ベテラン
会議室デビュー日: 2006/09/07
投稿数: 78
投稿日時: 2006-09-15 16:11
>InvalidateCell は強制的に再描画するものですから、
>1回余分に描画を行っていることになるかもしれませんね。

他にもっといい方法がある、ということですか?

>仮想モード時はちょっと操作しただけで描画イベントが発生しています。
>ですから、CellValueNeeded のような値に関するイベントの処理は
>できるだけ「軽い」内容にしておく必要があります。

仮想モードにしても、描画は遅いですね。
25列×25行程度の表示でオートサイズはしていません。
CellValueNeededでの処理は、行インデックスと行インデックスのチェックだけですが、
スクロールするとパラパラ漫画のように描画処理が目に見えます。
(実用には問題にならない程度ですが、気になります・・・)
これは仕様かとあきらめていましたが、
解決する方法はありますか?






[ メッセージ編集済み 編集者: hei 編集日時 2006-09-15 16:16 ]
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2006-09-15 16:35
今手元にソースがないのですが、覚えている限り InvalidateCell は使っていません。
CellValueNeeded などの値要求イベントだけで表示していました。

描画自体にどれほど違いがあるかどうかわかりませんが、
まず、列オブジェクトに対してテンプレートセルを設定しました。
単純に Columns.Add としただけでは、テンプレートは設定されていないような気がします。
MSDNの仮想モードに関するページにも
できるだけテンプレートを使うように推奨されています。

それから、CellValueNeeded 内の

Debug.Print(e.Value.ToString)

は消している状態でしょうか。
あるとないとでもデバッグ実行上の描画速度は変わると思います。



hei
ベテラン
会議室デビュー日: 2006/09/07
投稿数: 78
投稿日時: 2006-09-15 17:21
全ての列に
CellTemplate = New DataGridViewTextBoxCell
してみましたが、体感的にはあまり変わりませんでした。

Debug.Print(e.Value.ToString)
はありません。

スキルアップ/キャリアアップ(JOB@IT)