Help drawing a custom selection border in a ListView

T

Terry

What I would like to do is override the default ListViewItem selection
(solid rect) drawing and draw my own. It seems like it should be a
relatively simple thing to do, but I'm running into problems.

I set the appropriate Control styles:

this.SetStyle(ControlStyles.DoubleBuffer |

ControlStyles.UserPaint |

ControlStyles.AllPaintingInWmPaint, true);



Then, I over ride OnPaint and do what seems like appropriate drawing
behavior. But, what results is basically a mess. Only partial rectangles
are drawn and the very first item in the list refuses to paint when being
clicked on. If the entire form loses focus or the first item is covered and
uncovered it will paint properly. So, obviously, the default behavior of
the control is interfering with my painting somewhere.

Can anyone see what I'm missing?

Here's my OnPaint:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

{

if (this.View == View.Details)

{

Console.WriteLine(e.ToString());

Graphics g = e.Graphics;

g.Clear(this.BackColor);


// Draw the text for all items

foreach (ListViewItem lvi in Items)

{

if (lvi.Selected || lvi.Focused)

{

g.DrawRectangle(new Pen(Color.Orange), lvi.Bounds);

}

g.DrawString(lvi.Text, lvi.Font, new SolidBrush(lvi.ForeColor), lvi.Bounds,
StringFormat.GenericDefault);

}

}

}



Thanks,

Terry
 
T

Terry

If anyone is interested, I figured out what is happening, but I don't know
the correct way to handle it.
Basically, when I receive the OnPaint, it's passed a clipping region and I'm
trying to paint outside of that region.

In the following, the number in the square brackets is the index of the item
that is selected. The "ClipRect" is what Windows provides in the
PaintEventArgs and the "border rect" is where I'm trying to paint the
border. They don't always overlap, so some of the time my painting is
getting clipped. I don't know what I'm doing with this stuff.

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=28}
Drawing border rect:[1] {X=0,Y=33,Width=120,Height=14}

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=14}
Drawing border rect:[0] {X=0,Y=19,Width=120,Height=14}

So, obviously my approach isn't valid here. Can anyone offer a suggestion
on how to do this correctly?



Thanks,

Terry
 
S

Saurabh

Check if the border is part of the non client area (which i think is!!) If
that is so, you need to handle WM_NCPAINT and paint the border in the
WM_NCPAINT handler.

--Saurabh

Terry said:
If anyone is interested, I figured out what is happening, but I don't know
the correct way to handle it.
Basically, when I receive the OnPaint, it's passed a clipping region and I'm
trying to paint outside of that region.

In the following, the number in the square brackets is the index of the item
that is selected. The "ClipRect" is what Windows provides in the
PaintEventArgs and the "border rect" is where I'm trying to paint the
border. They don't always overlap, so some of the time my painting is
getting clipped. I don't know what I'm doing with this stuff.

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=28}
Drawing border rect:[1] {X=0,Y=33,Width=120,Height=14}

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=14}
Drawing border rect:[0] {X=0,Y=19,Width=120,Height=14}

So, obviously my approach isn't valid here. Can anyone offer a suggestion
on how to do this correctly?



Thanks,

Terry

Terry said:
What I would like to do is override the default ListViewItem selection
(solid rect) drawing and draw my own. It seems like it should be a
relatively simple thing to do, but I'm running into problems.

I set the appropriate Control styles:

this.SetStyle(ControlStyles.DoubleBuffer |

ControlStyles.UserPaint |

ControlStyles.AllPaintingInWmPaint, true);



Then, I over ride OnPaint and do what seems like appropriate drawing
behavior. But, what results is basically a mess. Only partial rectangles
are drawn and the very first item in the list refuses to paint when being
clicked on. If the entire form loses focus or the first item is covered and
uncovered it will paint properly. So, obviously, the default behavior of
the control is interfering with my painting somewhere.

Can anyone see what I'm missing?

Here's my OnPaint:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

{

if (this.View == View.Details)

{

Console.WriteLine(e.ToString());

Graphics g = e.Graphics;

g.Clear(this.BackColor);


// Draw the text for all items

foreach (ListViewItem lvi in Items)

{

if (lvi.Selected || lvi.Focused)

{

g.DrawRectangle(new Pen(Color.Orange), lvi.Bounds);

}

g.DrawString(lvi.Text, lvi.Font, new SolidBrush(lvi.ForeColor), lvi.Bounds,
StringFormat.GenericDefault);

}

}

}



Thanks,

Terry
 
T

Terry

I think you're misunderstanding what I'm trying to do. When a user selects
an item in a ListView control in Details view, I don't want the default
selection behavior, so I'm only trying to paint on the client area of the
ListView. I want to have my own item selection behavior but apparently I'm
not understanding the correct way to override the default selected item
painting.

Saurabh said:
Check if the border is part of the non client area (which i think is!!) If
that is so, you need to handle WM_NCPAINT and paint the border in the
WM_NCPAINT handler.

--Saurabh

Terry said:
If anyone is interested, I figured out what is happening, but I don't know
the correct way to handle it.
Basically, when I receive the OnPaint, it's passed a clipping region and I'm
trying to paint outside of that region.

In the following, the number in the square brackets is the index of the item
that is selected. The "ClipRect" is what Windows provides in the
PaintEventArgs and the "border rect" is where I'm trying to paint the
border. They don't always overlap, so some of the time my painting is
getting clipped. I don't know what I'm doing with this stuff.

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=28}
Drawing border rect:[1] {X=0,Y=33,Width=120,Height=14}

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=14}
Drawing border rect:[0] {X=0,Y=19,Width=120,Height=14}

So, obviously my approach isn't valid here. Can anyone offer a suggestion
on how to do this correctly?



Thanks,

Terry

Terry said:
What I would like to do is override the default ListViewItem selection
(solid rect) drawing and draw my own. It seems like it should be a
relatively simple thing to do, but I'm running into problems.

I set the appropriate Control styles:

this.SetStyle(ControlStyles.DoubleBuffer |

ControlStyles.UserPaint |

ControlStyles.AllPaintingInWmPaint, true);



Then, I over ride OnPaint and do what seems like appropriate drawing
behavior. But, what results is basically a mess. Only partial rectangles
are drawn and the very first item in the list refuses to paint when being
clicked on. If the entire form loses focus or the first item is
covered
and
uncovered it will paint properly. So, obviously, the default behavior of
the control is interfering with my painting somewhere.

Can anyone see what I'm missing?

Here's my OnPaint:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

{

if (this.View == View.Details)

{

Console.WriteLine(e.ToString());

Graphics g = e.Graphics;

g.Clear(this.BackColor);


// Draw the text for all items

foreach (ListViewItem lvi in Items)

{

if (lvi.Selected || lvi.Focused)

{

g.DrawRectangle(new Pen(Color.Orange), lvi.Bounds);

}

g.DrawString(lvi.Text, lvi.Font, new SolidBrush(lvi.ForeColor), lvi.Bounds,
StringFormat.GenericDefault);

}

}

}



Thanks,

Terry
 
S

Saurabh

Actually you are right!! I did not understand the exact problem. If you can
submit a short but complete code (taking out your bus. logic... maybe i can
give it a try.

--Saurabh
Terry said:
I think you're misunderstanding what I'm trying to do. When a user selects
an item in a ListView control in Details view, I don't want the default
selection behavior, so I'm only trying to paint on the client area of the
ListView. I want to have my own item selection behavior but apparently I'm
not understanding the correct way to override the default selected item
painting.

Saurabh said:
Check if the border is part of the non client area (which i think is!!) If
that is so, you need to handle WM_NCPAINT and paint the border in the
WM_NCPAINT handler.

--Saurabh

Terry said:
If anyone is interested, I figured out what is happening, but I don't know
the correct way to handle it.
Basically, when I receive the OnPaint, it's passed a clipping region
and
I'm
trying to paint outside of that region.

In the following, the number in the square brackets is the index of
the
item
that is selected. The "ClipRect" is what Windows provides in the
PaintEventArgs and the "border rect" is where I'm trying to paint the
border. They don't always overlap, so some of the time my painting is
getting clipped. I don't know what I'm doing with this stuff.

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=28}
Drawing border rect:[1] {X=0,Y=33,Width=120,Height=14}

OnPaint received. ClipRect = {X=0,Y=33,Width=120,Height=14}
Drawing border rect:[0] {X=0,Y=19,Width=120,Height=14}

So, obviously my approach isn't valid here. Can anyone offer a suggestion
on how to do this correctly?



Thanks,

Terry

What I would like to do is override the default ListViewItem selection
(solid rect) drawing and draw my own. It seems like it should be a
relatively simple thing to do, but I'm running into problems.

I set the appropriate Control styles:

this.SetStyle(ControlStyles.DoubleBuffer |

ControlStyles.UserPaint |

ControlStyles.AllPaintingInWmPaint, true);



Then, I over ride OnPaint and do what seems like appropriate drawing
behavior. But, what results is basically a mess. Only partial rectangles
are drawn and the very first item in the list refuses to paint when being
clicked on. If the entire form loses focus or the first item is covered
and
uncovered it will paint properly. So, obviously, the default
behavior
of
the control is interfering with my painting somewhere.

Can anyone see what I'm missing?

Here's my OnPaint:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

{

if (this.View == View.Details)

{

Console.WriteLine(e.ToString());

Graphics g = e.Graphics;

g.Clear(this.BackColor);


// Draw the text for all items

foreach (ListViewItem lvi in Items)

{

if (lvi.Selected || lvi.Focused)

{

g.DrawRectangle(new Pen(Color.Orange), lvi.Bounds);

}

g.DrawString(lvi.Text, lvi.Font, new SolidBrush(lvi.ForeColor),
lvi.Bounds,
StringFormat.GenericDefault);

}

}

}



Thanks,

Terry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top