I have a list box which is not filled with items all the way down, and has some empty area after last item. When I click that empty area the last item is automatically get's selected. And that selection happens before MouseDown
event. And I want to prevet it from happening.
I can keep current selected index (only one item can be selected) in a variable in SelectedIndexChanged
, and reset it in MouseDown
, but between MouseDown
and MouseUp
last item is selected - and it doesn't look good.
How can I prevent last item from being selected when empty area is clicked?
P.S. This is owner-drawn ListBox, but I'm not sure it has anything to do with this issue.
private void listBox_DrawItem(object sender, DrawItemEventArgs e)
{
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds);
}
else
{
e.Graphics.FillRectangle(Brushes.White, e.Bounds);
}
if (_commands.Count > 0)
{
KeyValuePair<string, string> cmd = (KeyValuePair<string, string>)_commands[e.Index];
// FIRST ROW
e.Graphics.DrawString(cmd.Key, _cmdNameFont, Brushes.Black, e.Bounds.X, e.Bounds.Y + _cellPadding);
开发者_开发百科 // SECOND ROW
e.Graphics.DrawString(cmd.Value,
_cmdCommandFont, Brushes.Black, e.Bounds.X + 5, e.Bounds.Y + _cmdNameFont.Height + _cellPadding);
}
e.DrawFocusRectangle();
}
private void listBox_MeasureItem(object sender, MeasureItemEventArgs e)
{
e.ItemHeight = _cmdNameFont.Height + _cmdCommandFont.Height + _cellPadding * 2 ;
}
I have a work around. You can place a panel and dynamically change its height based on the screen height,listbox height. In that case when you click the empty area, the new panel takes the click.
You can do this by inspecting the mouse down message and not letting it process the message if the user isn't clicking on an item:
public class ListBoxEx : ListBox {
private const int WM_LBUTTONDOWN = 0x201;
protected override void WndProc(ref Message m) {
int lParam = m.LParam.ToInt32();
int wParam = m.WParam.ToInt32();
if (m.Msg == WM_LBUTTONDOWN) {
Point clickedPt = new Point();
clickedPt.X = lParam & 0x0000FFFF;
clickedPt.Y = lParam >> 16;
bool lineOK = false;
for (int i = 0; i < Items.Count; i++) {
if (GetItemRectangle(i).Contains(clickedPt)) {
lineOK = true;
}
}
if (!lineOK) {
return;
}
}
base.WndProc(ref m);
}
}
Posted this from my answer at OwnerDrawVariable ListBox selects last item when clicking on control below items
Make sure you are returning the right value from OnMeasureItem.
EDIT: Appears to be a difference in how OwnerDrawVariable works.
Normally, IndexFromPoint (the hit test) returns -1 if empty space is clicked.
With OwnerDrawVariable, it returns the bottom item.
You have two choices.
1) Your items are all the same height so you can use OwnerDrawFixed and your problem goes away.
base.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.ItemHeight = this.Font.Height + this.Font.Height + _cellPadding * 2;
2) Handle the mouse click at a lower level and throw out the empty-space one.
精彩评论