DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ListViewの境界線色の設定

環境/言語:[WindoesXP]
分類:[.NET]

Listviewの境界線の色を変えるため悪戦苦闘しています。現在はBorderStyle=Noneに設定してOnPaintで境界線を描画していますが別のフォームが重なったりすると境界線が消えてしまいます。このような手法では根本的な解決にならないと思いListViewを継承する新しいクラスを作りその中で境界線の色を設定するプロパティを追加したいと思います。どなたか解決策をご存知の方ヒントでも結構ですのでお助けください。
ことぶきさん、こんにちは。深山と申します。

> Listviewの境界線の色を変えるため悪戦苦闘しています。

 もし見た目だけの問題でしたら、次のような方法でお茶を濁すというのはどうでしょう?

1. ListView と同じサイズの Panel を作成する
2. ListView をこの Panel の子コントロールにする
3. ListView の BorderStyle を None 、 Location を ( 1 , 1 ) 、 Width と Height を
  それぞれ元の値 -2 にする
4. Panel の BackColor に境界線の色として使用する色を設定する

‥‥という感じで。
 ListView の Anchor と Panel の Dock を設定することでリサイズにも対応できるものの
Splitter と組み合わせるとイマイチだったりしますが。
# やっぱり安直過ぎるかなぁ(^_^;)
■No6099に返信(ことぶきさんの記事)
> 現在はBorderStyle=Noneに設定してOnPaintで境界線を描画していますが別のフォームが重なったりすると境界線が消えてしまいます。

こんにちは、antと申します。
一度描いた線が消えるということはOnPaintが正しくオーバーライドできてきない
のではないでしょうか?通常ListViewのOnPaintはオーバーライドしてもそのまま
では呼び出されないはずです。従って、WndProcもオーバーライドしてWM_PAINT
をきゃっちした時に呼び出しておく必要があります。

Borderの描画にはControlPaint.DrawBorder()が使えると思います。
■No6162に返信(深山さんの記事)
>  ことぶきさん、こんにちは。深山と申します。
>
>>Listviewの境界線の色を変えるため悪戦苦闘しています。
>
>  もし見た目だけの問題でしたら、次のような方法でお茶を濁すというのはどうでしょう?
>
> 1. ListView と同じサイズの Panel を作成する
> 2. ListView をこの Panel の子コントロールにする
> 3. ListView の BorderStyle を None 、 Location を ( 1 , 1 ) 、 Width と Height を
>   それぞれ元の値 -2 にする
> 4. Panel の BackColor に境界線の色として使用する色を設定する
>
> ‥‥という感じで。
>  ListView の Anchor と Panel の Dock を設定することでリサイズにも対応できるものの
> Splitter と組み合わせるとイマイチだったりしますが。
> # やっぱり安直過ぎるかなぁ(^_^;)

深山さん。お助け頂きまして有難うございます。
自分でも出来るだけ簡単な方法でプログラミングするように日頃から
心がけていますが、深山さんから教えて頂いた方法は目からうろこです。
これならVB.NET初心者の私にも理解できますので早速試してみます。
■No6179に返信(antさんの記事)
> ■No6099に返信(ことぶきさんの記事)
>>現在はBorderStyle=Noneに設定してOnPaintで境界線を描画していますが別のフォームが重なったりすると境界線が消えてしまいます。
>
> こんにちは、antと申します。
> 一度描いた線が消えるということはOnPaintが正しくオーバーライドできてきない
> のではないでしょうか?通常ListViewのOnPaintはオーバーライドしてもそのまま
> では呼び出されないはずです。従って、WndProcもオーバーライドしてWM_PAINT
> をきゃっちした時に呼び出しておく必要があります。
>
> Borderの描画にはControlPaint.DrawBorder()が使えると思います。

antさん。お助け頂きまして有難うございます。
ご指摘のようにOnPaintは最初に1度だけ実行されるだけす。描いた線が消える
可能性のあるところでは再描画していますがそれでは追いつきません。
出来ましたらもう少し詳しく教えて頂きたいのですが、
「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。
> 「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
> が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。

具体的なサンプルとしては次のような方法が考えられます。
(ListViewを継承したクラス内に書き込みます)

---------------------------
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint (e);
ControlPaint.DrawBorder(e.Graphics,
               this.ClientRectangle ,
               Color.Red, ButtonBorderStyle.Solid);
}

private const int WM_PAINT = 0x000F;

protected override void WndProc(ref Message m)
{
base.WndProc (ref m);
if(m.Msg == WM_PAINT)
{
this.OnPaint(new PaintEventArgs(this.CreateGraphics(),this.Bounds));
}
}

---------------------------
■No6191に返信(antさんの記事)
>>「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
>>が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。
>
> 具体的なサンプルとしては次のような方法が考えられます。
> (ListViewを継承したクラス内に書き込みます)
>
> ---------------------------
> protected override void OnPaint(PaintEventArgs e)
> {
> base.OnPaint (e);
> ControlPaint.DrawBorder(e.Graphics,
>                this.ClientRectangle ,
>                Color.Red, ButtonBorderStyle.Solid);
> }
>
> private const int WM_PAINT = 0x000F;
>
> protected override void WndProc(ref Message m)
> {
> base.WndProc (ref m);
> if(m.Msg == WM_PAINT)
> {
> this.OnPaint(new PaintEventArgs(this.CreateGraphics(),this.Bounds));
> }
> }
>
> ---------------------------

具体的なサンプルまで教えて頂きまして有難うございます。
教えて頂いた方法を取り入れて再挑戦してみます。
■No6191に返信(antさんの記事)
>>「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
>>が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。
>
> 具体的なサンプルとしては次のような方法が考えられます。
> (ListViewを継承したクラス内に書き込みます)
>
> ---------------------------
> protected override void OnPaint(PaintEventArgs e)
> {
> base.OnPaint (e);
> ControlPaint.DrawBorder(e.Graphics,
>                this.ClientRectangle ,
>                Color.Red, ButtonBorderStyle.Solid);
> }
>
> private const int WM_PAINT = 0x000F;
>
> protected override void WndProc(ref Message m)
> {
> base.WndProc (ref m);
> if(m.Msg == WM_PAINT)
> {
> this.OnPaint(new PaintEventArgs(this.CreateGraphics(),this.Bounds));
> }
> }
>
> ---------------------------

教えて頂いたサンプルを自分の開発環境であるVB.NETを下記のように
書き直しました。
---------------------------------------------------------
Public Class sListView
Inherits ListView

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
ControlPaint.DrawBorder(e.Graphics,Me.ClientRectangle, Color.Red, ButtonBorderStyle.Solid)
End Sub

Private Const WM_PAINT As Integer = &HF

Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = WM_PAINT Then
Me.OnPaint(New PaintEventArgs(Me.CreateGraphics(), Bounds))
End If
End Sub
End Class
---------------------------------------------------------
フォームにListViewコントロールを配置してデザイナで生成されたコード内の
ListViewの部分を下記のようにSListViewに変更して実行しましたが
「トップレベルのコントロールをコントロールに追加できません。」
のエラーが発生します。
継承したコントロールをフォームに配置する方法が間違っているのでしょうか?
---------------------------------------------------------
Friend WithEvents ListView1 As sListView
Me.ListView1 = New sListView
Me.SuspendLayout()
'
'ListView1
'
Me.ListView1.Location = New System.Drawing.Point(64, 56)
Me.ListView1.Name = "ListView1"
Me.ListView1.Size = New System.Drawing.Size(256, 120)
Me.ListView1.TabIndex = 0

Me.Controls.Add(Me.ListView1)
---------------------------------------------------------
引き続きご指導を宜しくお願い致します。
■No6205に返信(ことぶきさんの記事)
> ■No6191に返信(antさんの記事)
> >>「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
> >>が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。
>>
>>具体的なサンプルとしては次のような方法が考えられます。
>>(ListViewを継承したクラス内に書き込みます)
>>
>>---------------------------
>>protected override void OnPaint(PaintEventArgs e)
>>{
>> base.OnPaint (e);
>> ControlPaint.DrawBorder(e.Graphics,
>>               this.ClientRectangle ,
>>               Color.Red, ButtonBorderStyle.Solid);
>>}
>>
>>private const int WM_PAINT = 0x000F;
>>
>>protected override void WndProc(ref Message m)
>>{
>> base.WndProc (ref m);
>> if(m.Msg == WM_PAINT)
>> {
>> this.OnPaint(new PaintEventArgs(this.CreateGraphics(),this.Bounds));
>> }
>>}
>>
>>---------------------------
>
> 教えて頂いたサンプルを自分の開発環境であるVB.NETを下記のように
> 書き直しました。
> ---------------------------------------------------------
> Public Class sListView
> Inherits ListView
>
> Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
> MyBase.OnPaint(e)
> ControlPaint.DrawBorder(e.Graphics,Me.ClientRectangle, Color.Red, ButtonBorderStyle.Solid)
> End Sub
>
> Private Const WM_PAINT As Integer = &HF
>
> Protected Overrides Sub WndProc(ByRef m As Message)
> MyBase.WndProc(m)
> If m.Msg = WM_PAINT Then
> Me.OnPaint(New PaintEventArgs(Me.CreateGraphics(), Bounds))
> End If
> End Sub
> End Class
> ---------------------------------------------------------
> フォームにListViewコントロールを配置してデザイナで生成されたコード内の
> ListViewの部分を下記のようにSListViewに変更して実行しましたが
> 「トップレベルのコントロールをコントロールに追加できません。」
> のエラーが発生します。
> 継承したコントロールをフォームに配置する方法が間違っているのでしょうか?
> ---------------------------------------------------------
> Friend WithEvents ListView1 As sListView
> Me.ListView1 = New sListView
> Me.SuspendLayout()
> '
> 'ListView1
> '
> Me.ListView1.Location = New System.Drawing.Point(64, 56)
> Me.ListView1.Name = "ListView1"
> Me.ListView1.Size = New System.Drawing.Size(256, 120)
> Me.ListView1.TabIndex = 0
>
> Me.Controls.Add(Me.ListView1)
> ---------------------------------------------------------
> 引き続きご指導を宜しくお願い致します。
>

「トップレベルのコントロールをコントロールに追加できません。」
のエラーが発生しておりましたがプロジェクトを新たに作って
同様の処理を行いましたら見事?ListViewの境界線が赤になりました。
境界線が隠れたあとも消える事も無く表示されています。
ご指導頂きました皆様には、本当に感謝しております。
解決済み!
■No6217に返信(ことぶきさんの記事)
> ■No6205に返信(ことぶきさんの記事)
>>■No6191に返信(antさんの記事)
>>>>「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
>>>>が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。
> >>
> >>具体的なサンプルとしては次のような方法が考えられます。
> >>(ListViewを継承したクラス内に書き込みます)
> >>
> >>---------------------------
> >>protected override void OnPaint(PaintEventArgs e)
> >>{
> >> base.OnPaint (e);
> >> ControlPaint.DrawBorder(e.Graphics,
> >>               this.ClientRectangle ,
> >>               Color.Red, ButtonBorderStyle.Solid);
> >>}
> >>
> >>private const int WM_PAINT = 0x000F;
> >>
> >>protected override void WndProc(ref Message m)
> >>{
> >> base.WndProc (ref m);
> >> if(m.Msg == WM_PAINT)
> >> {
> >> this.OnPaint(new PaintEventArgs(this.CreateGraphics(),this.Bounds));
> >> }
> >>}
> >>
> >>---------------------------
>>
>>教えて頂いたサンプルを自分の開発環境であるVB.NETを下記のように
>>書き直しました。
>>---------------------------------------------------------
>>Public Class sListView
>> Inherits ListView
>>
>> Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
>> MyBase.OnPaint(e)
>> ControlPaint.DrawBorder(e.Graphics,Me.ClientRectangle, Color.Red, ButtonBorderStyle.Solid)
>> End Sub
>>
>> Private Const WM_PAINT As Integer = &HF
>>
>> Protected Overrides Sub WndProc(ByRef m As Message)
>> MyBase.WndProc(m)
>> If m.Msg = WM_PAINT Then
>> Me.OnPaint(New PaintEventArgs(Me.CreateGraphics(), Bounds))
>> End If
>> End Sub
>>End Class
>>---------------------------------------------------------
>>フォームにListViewコントロールを配置してデザイナで生成されたコード内の
>>ListViewの部分を下記のようにSListViewに変更して実行しましたが
>>「トップレベルのコントロールをコントロールに追加できません。」
>>のエラーが発生します。
>>継承したコントロールをフォームに配置する方法が間違っているのでしょうか?
>>---------------------------------------------------------
>> Friend WithEvents ListView1 As sListView
>> Me.ListView1 = New sListView
>> Me.SuspendLayout()
>> '
>> 'ListView1
>> '
>> Me.ListView1.Location = New System.Drawing.Point(64, 56)
>> Me.ListView1.Name = "ListView1"
>> Me.ListView1.Size = New System.Drawing.Size(256, 120)
>> Me.ListView1.TabIndex = 0
>>
>> Me.Controls.Add(Me.ListView1)
>>---------------------------------------------------------
>>引き続きご指導を宜しくお願い致します。
>>
>
> 「トップレベルのコントロールをコントロールに追加できません。」
> のエラーが発生しておりましたがプロジェクトを新たに作って
> 同様の処理を行いましたら見事?ListViewの境界線が赤になりました。
> 境界線が隠れたあとも消える事も無く表示されています。
> ご指導頂きました皆様には、本当に感謝しております。
>

境界線が表示されるようになりましたが、フォームのサイズを変えると
以前の境界線が表示されたままになっています。
これを回避する方法を教えて頂ければと思っています。
■No6218に返信(ことぶきさんの記事)
> ■No6217に返信(ことぶきさんの記事)
>>■No6205に返信(ことぶきさんの記事)
> >>■No6191に返信(antさんの記事)
> >>>>「WndProcもオーバーライドしてWM_PAINT をきゃっちした時に呼び出しておく」
> >>>>が具体的にどのようにするのか分かりません。引き続いて宜しくお願い致します。
>>>>
>>>>具体的なサンプルとしては次のような方法が考えられます。
>>>>(ListViewを継承したクラス内に書き込みます)
>>>>
>>>>---------------------------
>>>>protected override void OnPaint(PaintEventArgs e)
>>>>{
>>>> base.OnPaint (e);
>>>> ControlPaint.DrawBorder(e.Graphics,
>>>>               this.ClientRectangle ,
>>>>               Color.Red, ButtonBorderStyle.Solid);
>>>>}
>>>>
>>>>private const int WM_PAINT = 0x000F;
>>>>
>>>>protected override void WndProc(ref Message m)
>>>>{
>>>> base.WndProc (ref m);
>>>> if(m.Msg == WM_PAINT)
>>>> {
>>>> this.OnPaint(new PaintEventArgs(this.CreateGraphics(),this.Bounds));
>>>> }
>>>>}
>>>>
>>>>---------------------------
> >>
> >>教えて頂いたサンプルを自分の開発環境であるVB.NETを下記のように
> >>書き直しました。
> >>---------------------------------------------------------
> >>Public Class sListView
> >> Inherits ListView
> >>
> >> Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
> >> MyBase.OnPaint(e)
> >> ControlPaint.DrawBorder(e.Graphics,Me.ClientRectangle, Color.Red, ButtonBorderStyle.Solid)
> >> End Sub
> >>
> >> Private Const WM_PAINT As Integer = &HF
> >>
> >> Protected Overrides Sub WndProc(ByRef m As Message)
> >> MyBase.WndProc(m)
> >> If m.Msg = WM_PAINT Then
> >> Me.OnPaint(New PaintEventArgs(Me.CreateGraphics(), Bounds))
> >> End If
> >> End Sub
> >>End Class
> >>---------------------------------------------------------
> >>フォームにListViewコントロールを配置してデザイナで生成されたコード内の
> >>ListViewの部分を下記のようにSListViewに変更して実行しましたが
> >>「トップレベルのコントロールをコントロールに追加できません。」
> >>のエラーが発生します。
> >>継承したコントロールをフォームに配置する方法が間違っているのでしょうか?
> >>---------------------------------------------------------
> >> Friend WithEvents ListView1 As sListView
> >> Me.ListView1 = New sListView
> >> Me.SuspendLayout()
> >> '
> >> 'ListView1
> >> '
> >> Me.ListView1.Location = New System.Drawing.Point(64, 56)
> >> Me.ListView1.Name = "ListView1"
> >> Me.ListView1.Size = New System.Drawing.Size(256, 120)
> >> Me.ListView1.TabIndex = 0
> >>
> >> Me.Controls.Add(Me.ListView1)
> >>---------------------------------------------------------
> >>引き続きご指導を宜しくお願い致します。
> >>
>>
>>「トップレベルのコントロールをコントロールに追加できません。」
>>のエラーが発生しておりましたがプロジェクトを新たに作って
>>同様の処理を行いましたら見事?ListViewの境界線が赤になりました。
>>境界線が隠れたあとも消える事も無く表示されています。
>>ご指導頂きました皆様には、本当に感謝しております。
>>
>
> 境界線が表示されるようになりましたが、フォームのサイズを変えると
> 以前の境界線が表示されたままになっています。
> これを回避する方法を教えて頂ければと思っています。

フォームのResizeRedrawプロパティをTrueに設定する事で解決しました。
これですべて解決と思ってよく見るとListViewのColumnHeader部分の
境界線が引かれていない事に気が付きました。
Listview.View = View.Detailsに設定したときのみ現象がでます。
ControlPaint.DrawBorderのClientRectangleでは正しく境界線を
取得できないのでしょうか?
> ControlPaint.DrawBorderのClientRectangleでは正しく境界線を
> 取得できないのでしょうか?

返信が遅れまして、本当に申し訳ありませんでした。
もう、自分がサンプルを書いたときに解決されたと勘違いして、
ことぶきさんが悪戦苦闘していることに気付きませんでした。m(_ _)m

本題ですが、まず、フォームのResizeRedrawですが、これでもきちんと描画
されているのなら、いいのですが、本来なら、ListViewのResizeRedrawを
呼ぶべきです。

次に非クライアント領域の描画ですが、これはWindowのタイトルバーを描画
することと同じように、通常.NETを含め推奨されていません。
従って、CreateGraphicsなどで、取得できる領域はクライアント領域に
限られます。なので、いくら非クライアント領域が取得できたとしても(Boundsで
取得可能)描画することはできません。

解決策のひとつとしては、Win32 APIのGetWindowDCを使用してまず
非クライアント領域も含めたデバイスコンテキストを取得します。
あとはGraphics.FromHdcメソッドを使用してGraphicsのインスタンスを
生成します。具体的なサンプルは以下のようになります。

----------------------------------------
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint (e);
Rectangle rect = new Rectangle(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
ControlPaint.DrawBorder(e.Graphics, rect , Color.Red, ButtonBorderStyle.Solid);
}

private const int WM_PAINT = 0x000F;

protected override void WndProc(ref Message m)
{
base.WndProc (ref m);
if(m.Msg == WM_PAINT)
{
IntPtr hdc = IntPtr.Zero;
Graphics g = null;
try
{
hdc = GetWindowDC(this.Handle);
g = Graphics.FromHdc(hdc);
this.OnPaint(new PaintEventArgs(g, this.Bounds));
}
finally
{
g.Dispose();
ReleaseDC(this.Handle ,hdc);
}
}
}

----------------------------------------
■No6228に返信(antさんの記事)
>>ControlPaint.DrawBorderのClientRectangleでは正しく境界線を
>>取得できないのでしょうか?
>
> 返信が遅れまして、本当に申し訳ありませんでした。
> もう、自分がサンプルを書いたときに解決されたと勘違いして、
> ことぶきさんが悪戦苦闘していることに気付きませんでした。m(_ _)m
>
> 本題ですが、まず、フォームのResizeRedrawですが、これでもきちんと描画
> されているのなら、いいのですが、本来なら、ListViewのResizeRedrawを
> 呼ぶべきです。
>
> 次に非クライアント領域の描画ですが、これはWindowのタイトルバーを描画
> することと同じように、通常.NETを含め推奨されていません。
> 従って、CreateGraphicsなどで、取得できる領域はクライアント領域に
> 限られます。なので、いくら非クライアント領域が取得できたとしても(Boundsで
> 取得可能)描画することはできません。
>
> 解決策のひとつとしては、Win32 APIのGetWindowDCを使用してまず
> 非クライアント領域も含めたデバイスコンテキストを取得します。
> あとはGraphics.FromHdcメソッドを使用してGraphicsのインスタンスを
> 生成します。具体的なサンプルは以下のようになります。
>
> ----------------------------------------
> [DllImport("user32.dll")]
> private static extern IntPtr GetWindowDC(IntPtr hWnd);
>
> [DllImport("user32.dll")]
> private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
>
> protected override void OnPaint(PaintEventArgs e)
> {
> base.OnPaint (e);
> Rectangle rect = new Rectangle(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
> ControlPaint.DrawBorder(e.Graphics, rect , Color.Red, ButtonBorderStyle.Solid);
> }
>
> private const int WM_PAINT = 0x000F;
>
> protected override void WndProc(ref Message m)
> {
> base.WndProc (ref m);
> if(m.Msg == WM_PAINT)
> {
> IntPtr hdc = IntPtr.Zero;
> Graphics g = null;
> try
> {
> hdc = GetWindowDC(this.Handle);
> g = Graphics.FromHdc(hdc);
> this.OnPaint(new PaintEventArgs(g, this.Bounds));
> }
> finally
> {
> g.Dispose();
> ReleaseDC(this.Handle ,hdc);
> }
> }
> }
>
> ----------------------------------------

antさん。本当に感謝です。
妥協してしまいそうになっていましたが上記のサンプルを見せて頂きまして
もう一度頑張ってみようと思っています。まだまだ試行錯誤の連続ですが
助けて頂ける多くの方のおかげで少しずつですが前に進んでいます。
3連休は悪戦苦闘して気持ち良く週明けを迎えます。(本当は3日とも出勤)
■No6228に返信(antさんの記事)
>>ControlPaint.DrawBorderのClientRectangleでは正しく境界線を
>>取得できないのでしょうか?
>
> 返信が遅れまして、本当に申し訳ありませんでした。
> もう、自分がサンプルを書いたときに解決されたと勘違いして、
> ことぶきさんが悪戦苦闘していることに気付きませんでした。m(_ _)m
>
> 本題ですが、まず、フォームのResizeRedrawですが、これでもきちんと描画
> されているのなら、いいのですが、本来なら、ListViewのResizeRedrawを
> 呼ぶべきです。
>
> 次に非クライアント領域の描画ですが、これはWindowのタイトルバーを描画
> することと同じように、通常.NETを含め推奨されていません。
> 従って、CreateGraphicsなどで、取得できる領域はクライアント領域に
> 限られます。なので、いくら非クライアント領域が取得できたとしても(Boundsで
> 取得可能)描画することはできません。
>
> 解決策のひとつとしては、Win32 APIのGetWindowDCを使用してまず
> 非クライアント領域も含めたデバイスコンテキストを取得します。
> あとはGraphics.FromHdcメソッドを使用してGraphicsのインスタンスを
> 生成します。具体的なサンプルは以下のようになります。
>
> ----------------------------------------
> [DllImport("user32.dll")]
> private static extern IntPtr GetWindowDC(IntPtr hWnd);
>
> [DllImport("user32.dll")]
> private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
>
> protected override void OnPaint(PaintEventArgs e)
> {
> base.OnPaint (e);
> Rectangle rect = new Rectangle(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
> ControlPaint.DrawBorder(e.Graphics, rect , Color.Red, ButtonBorderStyle.Solid);
> }
>
> private const int WM_PAINT = 0x000F;
>
> protected override void WndProc(ref Message m)
> {
> base.WndProc (ref m);
> if(m.Msg == WM_PAINT)
> {
> IntPtr hdc = IntPtr.Zero;
> Graphics g = null;
> try
> {
> hdc = GetWindowDC(this.Handle);
> g = Graphics.FromHdc(hdc);
> this.OnPaint(new PaintEventArgs(g, this.Bounds));
> }
> finally
> {
> g.Dispose();
> ReleaseDC(this.Handle ,hdc);
> }
> }
> }
>
> ----------------------------------------

おかげさまで境界線が消える事も無く描画できました。
自分ひとりでは何年経っても解決する事が出来なかった事を
短時間で解決できたのはantさんのお陰と感謝しております。
最後に1点だけ質問ですがMe.ResizeRedraw=Trueにしていたのを
ListView1.ResizeRedraw=Trueに変更するとエラーが出たため現在は
元の状態に戻しています。この値を変更できるようにする為には
ListViewを継承したクラス内に記述が必要ですよね。
> 自分ひとりでは何年経っても解決する事が出来なかった事を
> 短時間で解決できたのはantさんのお陰と感謝しております。

いえいえ、恐縮です。m(_ _)m

> 最後に1点だけ質問ですがMe.ResizeRedraw=Trueにしていたのを
> ListView1.ResizeRedraw=Trueに変更するとエラーが出たため現在は
> 元の状態に戻しています。この値を変更できるようにする為には
> ListViewを継承したクラス内に記述が必要ですよね。

はい。VS.NETで開発されておられるのでしたら、継承したクラスの
コンストラクタにInitializeComponent()が自動的に挿入されているはずですから
その後に、Me.ResizeRedraw=Trueとしておけばいいと思います。
■No6238に返信(antさんの記事)
>>自分ひとりでは何年経っても解決する事が出来なかった事を
>>短時間で解決できたのはantさんのお陰と感謝しております。
>
> いえいえ、恐縮です。m(_ _)m
>
>>最後に1点だけ質問ですがMe.ResizeRedraw=Trueにしていたのを
>>ListView1.ResizeRedraw=Trueに変更するとエラーが出たため現在は
>>元の状態に戻しています。この値を変更できるようにする為には
>>ListViewを継承したクラス内に記述が必要ですよね。
>
> はい。VS.NETで開発されておられるのでしたら、継承したクラスの
> コンストラクタにInitializeComponent()が自動的に挿入されているはずですから
> その後に、Me.ResizeRedraw=Trueとしておけばいいと思います。

「本来ならListViewのResizeRedraw…」がやっと理解できました。
間違いなくこちらの方が安定して描画してくれています。
これで全て解決!…実は、
列ヘッダー幅をマウスで変更するとヘッダー部分だけ元の幅が残っています。
ListViewをResizeしたときと同じように何かしなければいけないのですよね?
> 列ヘッダー幅をマウスで変更するとヘッダー部分だけ元の幅が残っています。
> ListViewをResizeしたときと同じように何かしなければいけないのですよね?

ヘッダー部分だけ元の幅が残っているというのがいまいちわからないのですが、
自分が書いた上記のサンプルでテストした限りではそのようなことは発生して
いないと思うのですが…(^^;
■No6240に返信(antさんの記事)
>>列ヘッダー幅をマウスで変更するとヘッダー部分だけ元の幅が残っています。
>>ListViewをResizeしたときと同じように何かしなければいけないのですよね?
>
> ヘッダー部分だけ元の幅が残っているというのがいまいちわからないのですが、
> 自分が書いた上記のサンプルでテストした限りではそのようなことは発生して
> いないと思うのですが…(^^;
本当に何度も申し訳ありません。もう少し詳しく説明しますが
フォームをResizeしたとき境界線の一部(右側の縦線)が列ヘッダーの中に
描画されています。又、列ヘッダー幅をマウスでスライドして広げると
非クライアント領域の境界線が消え、逆に狭めると右端に何本もの線が
描画されます。教えて頂いたコードをVB.NETに変更して使用しているものを
お見せしますので間違い点等をご指摘ください。

Imports System.Runtime.InteropServices
Public Class HIListView
Inherits ListView

Private Const WM_PAINT As Integer = &HF
Private BorderColor As Color = SystemColors.InactiveCaption

<DllImport("user32.dll")> _
Private Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
End Function

<DllImport("user32.dll")> _
Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer
End Function

Public Sub New()
Me.ResizeRedraw = True
End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
Dim rect As Rectangle
rect = New Rectangle(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height)
ControlPaint.DrawBorder(e.Graphics, rect, BorderColor, ButtonBorderStyle.Solid)
End Sub

Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = WM_PAINT Then
Dim hdc As IntPtr = IntPtr.Zero
Dim g As Graphics = Nothing
Try
hdc = GetWindowDC(Me.Handle)
g = Graphics.FromHdc(hdc)
Me.OnPaint(New PaintEventArgs(g, Me.Bounds))
Catch ex As Exception

End Try
g.Dispose()
ReleaseDC(Me.Handle, hdc)
End If
End Sub
End Class
> フォームをResizeしたとき境界線の一部(右側の縦線)が列ヘッダーの中に
> 描画されています。又、列ヘッダー幅をマウスでスライドして広げると
> 非クライアント領域の境界線が消え、逆に狭めると右端に何本もの線が
> 描画されます。教えて頂いたコードをVB.NETに変更して使用しているものを
> お見せしますので間違い点等をご指摘ください。

コード拝見させていただきましたが、今回の問題に関係ありそうな点で
間違いはないと思います。(リソースの解放処理に少々問題がありますが(^^;)
又、自分の環境(VS.NET 2003 .NET Framework 1.1 SP1)では特に問題なく
描画されています。もしかしたら、ここではない別の場所が原因なのかもしれません。
■No6243に返信(antさんの記事)
>>フォームをResizeしたとき境界線の一部(右側の縦線)が列ヘッダーの中に
>>描画されています。又、列ヘッダー幅をマウスでスライドして広げると
>>非クライアント領域の境界線が消え、逆に狭めると右端に何本もの線が
>>描画されます。教えて頂いたコードをVB.NETに変更して使用しているものを
>>お見せしますので間違い点等をご指摘ください。
>
> コード拝見させていただきましたが、今回の問題に関係ありそうな点で
> 間違いはないと思います。(リソースの解放処理に少々問題がありますが(^^;)
> 又、自分の環境(VS.NET 2003 .NET Framework 1.1 SP1)では特に問題なく
> 描画されています。もしかしたら、ここではない別の場所が原因なのかもしれません。

開発環境に関しては私もまったく同じです。(言語はC#でなくVBですが)
この1週間antさんに教わりながらやってきましたがVBすらも理解できない
自分がもどかしくて仕方ありませんでした。
昨晩antさんのHPを訪れたところC#の講座が開かれている事をしりまして
私も1から勉強する事に致しました。ListViewの境界線の描画に関しては
VB環境では完璧とは行きませんでしたが、教えて頂いたことを参考にして
C#で完成させたいと思っております。皆さま本当に有難うございました。
解決済み!
■No6251に返信(ことぶきさんの記事)
> ■No6243に返信(antさんの記事)
> >>フォームをResizeしたとき境界線の一部(右側の縦線)が列ヘッダーの中に
> >>描画されています。又、列ヘッダー幅をマウスでスライドして広げると
> >>非クライアント領域の境界線が消え、逆に狭めると右端に何本もの線が
> >>描画されます。教えて頂いたコードをVB.NETに変更して使用しているものを
> >>お見せしますので間違い点等をご指摘ください。
>>
>>コード拝見させていただきましたが、今回の問題に関係ありそうな点で
>>間違いはないと思います。(リソースの解放処理に少々問題がありますが(^^;)
>>又、自分の環境(VS.NET 2003 .NET Framework 1.1 SP1)では特に問題なく
>>描画されています。もしかしたら、ここではない別の場所が原因なのかもしれません。
>

申し訳ありません。再度お願いします。
今日一日で問題のあったVBでのコードをVC#に書き直してテストしましたが
結果はVBで書いていたものと同じ現象が出ています。
ご指摘のように別の場所に原因があるのでしょうか?
------------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace CTest
{
/// <summary>
/// HIListView の概要の説明です。
/// </summary>
public class HIListView : System.Windows.Forms.ListView
{
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd,IntPtr hDC);

public HIListView()
{
this.ResizeRedraw=true;
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint (e);
Rectangle rect = new Rectangle(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
ControlPaint.DrawBorder(e.Graphics, rect , Color.Red, ButtonBorderStyle.Solid);
}

private const int WM_PAINT = 0x000f;

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(m.Msg == WM_PAINT)
{
IntPtr hdc = IntPtr.Zero;
Graphics g = null;
try
{
hdc = GetWindowDC(this.Handle);
g= Graphics.FromHdc(hdc);
this.OnPaint(new PaintEventArgs(g,this.Bounds));
}
finally
{
g.Dispose();
ReleaseDC(this.Handle,hdc);
}
}
}
}
}
------------------------------------------------
> ご指摘のように別の場所に原因があるのでしょうか?

どうもそのような気がします。
自分の書いたプロジェクトファイルをアップロードしましたので、
一度見てみてください。

http://jp.y42.briefcase.yahoo.co.jp/bc/ant_0x/vwp2?.tok=bcOF9dBBiAHyvp0t&.dir=/%a4%bd%a4%ce%c2%be%b8%f8%b3%ab&.dnm=ExtendListViewTestApp.zip&.src=bc
■No6265に返信(antさんの記事)
>>ご指摘のように別の場所に原因があるのでしょうか?
>
> どうもそのような気がします。
> 自分の書いたプロジェクトファイルをアップロードしましたので、
> 一度見てみてください。
>
> http://jp.y42.briefcase.yahoo.co.jp/bc/ant_0x/vwp2?.tok=bcOF9dBBiAHyvp0t&.dir=/%a4%bd%a4%ce%c2%be%b8%f8%b3%ab&.dnm=ExtendListViewTestApp.zip&.src=bc
>
>

完璧に動作しました。
ソースコードも本当に美しく、これからVC#を学習していく過程で
参考にさせて頂きます。本当に有難うございました。
解決済み!
■No6265に返信(antさんの記事)
>>ご指摘のように別の場所に原因があるのでしょうか?
>
> どうもそのような気がします。
> 自分の書いたプロジェクトファイルをアップロードしましたので、
> 一度見てみてください。
>
> http://jp.y42.briefcase.yahoo.co.jp/bc/ant_0x/vwp2?.tok=bcOF9dBBiAHyvp0t&.dir=/%a4%bd%a4%ce%c2%be%b8%f8%b3%ab&.dnm=ExtendListViewTestApp.zip&.src=bc
>
>

ソースコードをそのまま実行して正常に動作しましたので、自分でもう一度
入力して実行してみました。その結果、依然とまったく同じ現象がでましたので
別の場所を探しましたら自分の場合ListViewのBorderStyleがNoneに設定
されていました。FixedSingleにすると描画のとき後の黒線が見えるので
あえてNoneにしていましたが、Noneの場合に正常に描画しない現象がでます。
FixedSingleに設定して正常に動作しています。有難うございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板