トップ回答者
標準の DataGridViewCell より大きい UserControl を常時ホストする場合、行の高さや列の幅を調整するには

質問
-
下記を参考に DataGridView でホスト可能な Column/Cell を作成してみようと
試みています。
(1) 方法 : Windows フォーム DataGridView コントロールのセルと列を、それぞれの動作と外観を拡張してカスタマイズする
このサンプルや他のサイトなどで紹介されているものは、標準的な
DataGridViewCell の中にすっぽり入る程度の大きさのものしか挙げられていません。
今回は、標準的な DataGridViewCell の大きさよりも大きい UserControl をホ
ストしてみようと考えています。
とすると気になるのは、どうやって行の高さや列の幅を調整するか、です。
DataGridViewImageCellは割り当てられているイメージの高さや幅に合わせて、のソースコードを参考に読みました。
行の高さや列の幅が調整されているので、そ※ DataGridViewImageColumn/Cell で内包するイメージのサイズに合わせて行
の高さや列の幅が調整される、という私の認識は間違いでした。明らかに
Cell よりも大きいイメージを挿入してみたら、標準ではイメージの一部しか Cell
内に表示されませんでした。が、どうもよく分かりません。何処で調整されているのかお分かりの方がいらっしゃったら、教えていただけませんか? Paint() -> PaintPrivate() の何処かだと思うのですが。
お聞きしたいのは、
新しくホストする Cell から、どうやって行の高さや列の幅を Cell に合わせられるのか、
ということです。お分かりの方がいらっしゃったら、教えていただけませんか。
ちなみに、UserControl の高さに合わせて Cell.Paint() の定義内で
Cell.OwningRow.Height を書き換えようとしたら、共有行の Height を触るの
はよくない旨のメッセージが出てしまいました。
# このエラーの意味もよく分かりませんが。参考
(2) Windows Forms Data Controls and Databinding FAQ
(3) DataGridView に ProgressBar を表示する: .NET Tips: C#, VB.NET, Visual Studio
(4) Windows Forms Documentation Updates : DataGridView Watermark Cell
(5) 方法 : Windows フォーム DataGridView Cells でコントロールをホストする
回答
-
custar さんからの引用 とすると気になるのは、どうやって行の高さや列の幅を調整するか、です。 ユーザーが列境界をダブルクリックした場合や、プログラムから DataGridView の
AutoResize系メソッドを呼び出した場合に、それぞれのセルの内容に合わせて、
セルを適切なサイズに自動調整させたい、という意味であれば、
DataGridViewCell.GetPreferredSize
DataGridViewRow.GetPreferredHeight
DataGridViewColumn.GetPreferredWidth
などをオーバーライドすることによって実装可能かと思います。http://msdn2.microsoft.com/ja-jp/library/74b2wakt.aspx
custar さんからの引用 ちなみに、UserControl の高さに合わせて Cell.Paint() の定義内で
Cell.OwningRow.Height を書き換えようとしたら、共有行の Height を触るの
はよくない旨のメッセージが出てしまいました。データバインドしている場合、各行のスタイルはほぼ同一になりますよね。
たとえばデータが1000行あった時に、1000行分のインスタンスを個別に作るのは
効率が悪いので、同じ設定値(スタイルやイベント割り当てなど)を持つ行は、
「共有行」として、可能な限り使いまわすように設計されています。
http://msdn2.microsoft.com/ja-jp/library/ha5xt0d9.aspxcustar さんからの引用 # このエラーの意味もよく分かりませんが。 セルの高さが変われば描画エリアも変わりますので、再度 Paint の必要が生じます。
処理が循環してしまう可能性があるため、Paint からセルサイズを操作すべきでは無いかと。 -
custar さんからの引用 常時 UserControl のサイズに合わせた表示にするつもりです。 たとえば「固定で 50 x 50 にしたい」セルと「固定で 120 x 30 にしたい」セルが、
同じ行(または同じ列)にあった場合、どちらに合わせるべきとも言えませんよね。ですから通常、セルのサイズを調整するのは、子(セル側)の仕事としてではなく、
親によって管理される物になっているかと思います。「内容に基づいて自動的にサイズ変更するモード」も用意されてはいますが、それとて
セル側が、親に対して「このぐらいの領域が欲しい」と訴えかけているだけであって、
セル側が直接、親の高さ/幅を直接コントロールしているわけではありません。
custar さんからの引用 Cell.Paint() 内部からのサイズ変更だとループになるのならば、視点を変えて、
大元である DataGridView の CellPainting イベントで調整すべきなのかな?『描画系の処理』と、『サイズ調整/サイズ測定系の処理』は、それぞれ分けて考えてみてください。
『サイズ』については、先ほど紹介した Windows フォーム DataGridView コントロールのサイズ変更オプション を
参照してみてください。『内容に基づくサイズ変更動作のカスタマイズ』のあたりが相当するかと。custar さんからの引用 標準の DataGridViewCell より大きいサイズの UserControl を常時ホストする場合、どうやって行の高さや列の幅を調整するのか サイズ固定というわけではありませんが、「最小限必要なサイズ」については、
たとえば、行の MinimumHeight や列の MinimumWidth などが利用できます。
『描画』についてセル側でやるべきことは、親に与えられた領域内に描画するという作業です。
(たとえばテキスト列だと、狭い幅に対して "..." の省略表記を行うようになっていますね)
領域が広すぎれば、余白を作るなり、拡大するなりといった対応になるでしょうし、
逆に狭すぎれば、たとえばクリッピング/縮小/スクロール表示などを行えば OK かと。
すべての返信
-
custar さんからの引用 とすると気になるのは、どうやって行の高さや列の幅を調整するか、です。 ユーザーが列境界をダブルクリックした場合や、プログラムから DataGridView の
AutoResize系メソッドを呼び出した場合に、それぞれのセルの内容に合わせて、
セルを適切なサイズに自動調整させたい、という意味であれば、
DataGridViewCell.GetPreferredSize
DataGridViewRow.GetPreferredHeight
DataGridViewColumn.GetPreferredWidth
などをオーバーライドすることによって実装可能かと思います。http://msdn2.microsoft.com/ja-jp/library/74b2wakt.aspx
custar さんからの引用 ちなみに、UserControl の高さに合わせて Cell.Paint() の定義内で
Cell.OwningRow.Height を書き換えようとしたら、共有行の Height を触るの
はよくない旨のメッセージが出てしまいました。データバインドしている場合、各行のスタイルはほぼ同一になりますよね。
たとえばデータが1000行あった時に、1000行分のインスタンスを個別に作るのは
効率が悪いので、同じ設定値(スタイルやイベント割り当てなど)を持つ行は、
「共有行」として、可能な限り使いまわすように設計されています。
http://msdn2.microsoft.com/ja-jp/library/ha5xt0d9.aspxcustar さんからの引用 # このエラーの意味もよく分かりませんが。 セルの高さが変われば描画エリアも変わりますので、再度 Paint の必要が生じます。
処理が循環してしまう可能性があるため、Paint からセルサイズを操作すべきでは無いかと。 -
魔界の仮面弁士 さんからの引用 custar さんからの引用 とすると気になるのは、どうやって行の高さや列の幅を調整するか、です。
ユーザーが列境界をダブルクリックした場合や、プログラムから DataGridView
の AutoResize 系メソッドを呼び出した場合に、それぞれのセルの内容に合わ
せて、セルを適切なサイズに自動調整させたい、という意味であれば、
常時 UserControl のサイズに合わせた表示にするつもりです。
イメージのサイズに合わせて Cell のサイズを変更するとして、それを行の高
さ、列の幅にどう反映させれば良いのか、分かりません。
勝手に FillRectangle() で Cell の領域を塗りつぶしたとしても、それは
Cell の勝手な行動で、Column や Row にはそれが反映されないように思えてい
ます。
どうやるのかなぁ?
魔界の仮面弁士 さんからの引用
custar さんからの引用 ちなみに、UserControl の高さに合わせて Cell.Paint() の定義内で
Cell.OwningRow.Height を書き換えようとしたら、共有行の Height を触るの
はよくない旨のメッセージが出てしまいました。
データバインドしている場合、各行のスタイルはほぼ同一になりますよね。た
とえばデータが 1000行あった時に、1000行分のインスタンスを個別に作るのは
効率が悪いので、同じ設定値(スタイルやイベント割り当てなど)を持つ行は、
「共有行」として、可能な限り使いまわすように設計されています。
なるほど。下記ドキュメントを読んで解せなかったのですが、ご説明から大凡
(おおよそ) 分かりかけてきました。
- Windows フォーム DataGridView コントロールを拡張するための推奨される手順
ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ja/dv_fxmclictl/html/8321a8a6-6340-4fd1-b475-fa090b905aaf.htm魔界の仮面弁士 さんからの引用 custar さんからの引用
# このエラーの意味もよく分かりませんが。
セルの高さが変われば描画エリアも変わりますので、再度 Paint の必要が生じ
ます。処理が循環してしまう可能性があるため、Paint からセルサイズを操作
すべきでは無いかと。
ご指摘ありがとうございます。言われてみれば、そうですね。ループするでしょう。Cell.Paint() 内部からのサイズ変更だとループになるのならば、視点を変えて、
大元である DataGridView の CellPainting イベントで調整すべきなのかな?※ タイトルを変更します。
(前) DataGridViewImageCell はどうやって行の高さや列の幅を調整しているのか
(後) 標準の DataGridViewCell より大きいサイズの UserControl を常時ホストする場合、どうやって行の高さや列の幅を調整するのか
-
custar さんからの引用 常時 UserControl のサイズに合わせた表示にするつもりです。 たとえば「固定で 50 x 50 にしたい」セルと「固定で 120 x 30 にしたい」セルが、
同じ行(または同じ列)にあった場合、どちらに合わせるべきとも言えませんよね。ですから通常、セルのサイズを調整するのは、子(セル側)の仕事としてではなく、
親によって管理される物になっているかと思います。「内容に基づいて自動的にサイズ変更するモード」も用意されてはいますが、それとて
セル側が、親に対して「このぐらいの領域が欲しい」と訴えかけているだけであって、
セル側が直接、親の高さ/幅を直接コントロールしているわけではありません。
custar さんからの引用 Cell.Paint() 内部からのサイズ変更だとループになるのならば、視点を変えて、
大元である DataGridView の CellPainting イベントで調整すべきなのかな?『描画系の処理』と、『サイズ調整/サイズ測定系の処理』は、それぞれ分けて考えてみてください。
『サイズ』については、先ほど紹介した Windows フォーム DataGridView コントロールのサイズ変更オプション を
参照してみてください。『内容に基づくサイズ変更動作のカスタマイズ』のあたりが相当するかと。custar さんからの引用 標準の DataGridViewCell より大きいサイズの UserControl を常時ホストする場合、どうやって行の高さや列の幅を調整するのか サイズ固定というわけではありませんが、「最小限必要なサイズ」については、
たとえば、行の MinimumHeight や列の MinimumWidth などが利用できます。
『描画』についてセル側でやるべきことは、親に与えられた領域内に描画するという作業です。
(たとえばテキスト列だと、狭い幅に対して "..." の省略表記を行うようになっていますね)
領域が広すぎれば、余白を作るなり、拡大するなりといった対応になるでしょうし、
逆に狭すぎれば、たとえばクリッピング/縮小/スクロール表示などを行えば OK かと。 -
魔界の仮面弁士 さんからの引用 custar さんからの引用
常時 UserControl のサイズに合わせた表示にするつもりです。
たとえば「固定で 50 x 50 にしたい」セルと「固定で 120 x 30 にしたい」セ
ルが、同じ行(または同じ列)にあった場合、どちらに合わせるべきとも言えま
せんよね。
ですから通常、セルのサイズを調整するのは、子(セル側)の仕事としてではな
く、親によって管理される物になっているかと思います。
なるほど。
現在の UserControl は全てのセルで同じサイズという前提ですが、もっと先に
は個々に変更する予定ですから、留意すべきですね。
魔界の仮面弁士 さんからの引用
「内容に基づいて自動的にサイズ変更するモード」も用意されてはいますが、
それとてセル側が、親に対して「このぐらいの領域が欲しい」と訴えかけてい
るだけであって、セル側が直接、親の高さ/幅を直接コントロールしているわけ
ではありません。
分かりやすい。了解。
魔界の仮面弁士 さんからの引用
『描画系の処理』と、
『サイズ調整/サイズ測定系の処理』は、
それぞれ分けて考えてみてください。『サイズ』については、先ほど紹介した Windows フォーム DataGridView コン
トロールのサイズ変更オプション を参照してみてください。『内容に基づくサ
イズ変更動作のカスタマイズ』のあたりが相当するかと。
ありがとうございます。魔界の仮面弁士 さんからの引用
サイズ固定というわけではありませんが、「最小限必要なサイズ」については、
たとえば、行の MinimumHeight や列の MinimumWidth などが利用できます。
ふむ。
魔界の仮面弁士 さんからの引用
『描画』についてセル側でやるべきことは、
親に与えられた領域内に描画するという作業です。
この役割分担には気をつけます。
では、早速教えてもらった情報を元にまた調査します。
魔界の仮面弁士 さん、ありがとうございます。DataGridView ..... セルのサイズ調整
Cell ............. 親に与えられた領域内への描画