views:

1131

answers:

6

I'm trying to change the cursor that appears on a standard ListView when the cursor appears over an item. However I am getting a flickering effect as the mouse is changed to a finger cursor, and then back to what I asked it to be.

I'm trying to isolate this flicker/changing to the hand cursor but can't figure out where it's occuring or how to stop it. To replicate this...

1) Create a form with a ListView on it. 2) Add an image list and some images. Set the view to the large icon mode. 3) Add some items to the ListView.

Add a MouseMove event to the ListView:

  private void listView1_MouseMove(object sender, MouseEventArgs e)
    {
        ListViewItem selected = this.listView1.GetItemAt(e.X, e.Y);
        if (selected == null)
        {
            base.Cursor = Cursors.Default;
        }
        else
        {
            base.Cursor = Cursors.No;
        }
    }

Execute the app, moving the mouse over an item. You should see the cursor flickering between the No (no entry cursor) and the finger pointer when you're over an item. The question is how to ensure it just displays the No cursor and to not flicker. (C# .NET).

I've tried override both OnMouseMove and OnMouseHover to returning to ensure these don't set anything. I've also tried overriding the Cursor property and saying 'only set to default or no cursors' and that didn't work either.

Any help's appreciated.

Ian

A: 

I've built the test you outline and my cursor changes from a default arrow to the No cursor without any flickering to the hand cursor at all.

Iain M Norman
That's interesting. I'm using lots of owner draw stuff with hottracking turned on which seems to make it worse. If you run the app, ensuring you can see the form. Break on (base.Cursor = Cursors.No;). You'll see the hand cursor. This is causing the problem, but I don't know where it's being set.
Ian
A: 

Does it happen elsewhere? For example, when navigating over hyperlinks or in other applications? Or does it only happen in your application?

If so, it is probably more an OS issue...

Razzie
It's cross platform, cross application. If you read my comment to teknohippy... The problem is exaggerated with manual drawing of items and hottracking. I've tried overriding WndProc to return if the (m.Msg == 0x020) to change cursor. Something switches it to a hand, but I'm not sure what.
Ian
A: 

Just realised people don't use comments all that often so moved it into here instead:

tekohippy:

I'm using lots of owner draw stuff with hottracking turned on which seems to make it worse. If you run the app, ensuring you can see the form. Break on (base.Cursor = Cursors.No;). You'll see the hand cursor. This is causing the problem, but I don't know where it's being set.

Razzie:

It's cross platform, cross application. The problem is exaggerated with manual drawing of items and hottracking. I've tried overriding WndProc to return if the (m.Msg == 0x020) to change cursor. Something switches it to a hand, but I'm not sure what.

Ian
A: 

Without having tried it, cursors are normally changed in response to WM_ SETCURSOR, so maybe you are in conflict with the default WM_ SETCURSOR handling of the ListView. I would try to create a new UserControl deriving from ListView and then trap WM_ SETCURSOR in WndProc and see if that helps.

danbystrom
A: 

did you fix the problem? I have a owner-drawn listview in my c# program and I'm getting the same problem. It looks really weired with mouse changing rapidly to hand & back to arrow(what I want) when I move it over the items.

So far, I have tried handling WM_SETCURSOR, overriding MouseMove, deriving a listview class But nothing is fixing the issue. If you fixed it, please let me know asap!

MTG, unfortunately I wasn't able to fix it. In the end I gave up and settled with the default finger pointer when the mouse is over an item. It's frustrating, and I wish I knew what was causing it!
Ian
+2  A: 

Hey, I found the CURE!

The problem is that C# ListView Control is basically a wrapper around windows List View Control. So when we set the cursor to Arrow, the underlying listview control always defaulted to Hand cursor while our setting in the C# ListView class wanted it to be an Arrow. That's why we were getting that flickering, because underlying control was reverting back to Hand.

Here is the code that you need to add:

public const uint LVM_SETHOTCURSOR = 4158; [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

SendMessage(listView1.Handle, LVM_SETHOTCURSOR, IntPtr.Zero, Cursors.Arrow.Handle);

It's very important that you call the SendMessage from your Form's onLoad event because by then the underlying ListView control is completely initialized!

It's pretty simple actually, Have a great day! :)

MTG. Thanks for that, I shall have a look at it and try it out. If it works will mark it as the answer for the future :) I'm guessing another way would be to override WndProc using the same uint...
Ian
Overriding WndProc won't do anything. SendMessage is used as a way to update Windows Common Control properties. LVM_SETHOTCUROSR is a property Not a Windows message, so overriding wndproc won't help at all.
Very good. Can I ask where you found this info from? Never found a nice place to locate all these magic constant values...
Ian
It didn't solve the problem for me, so I'm continuing to find something better.
brady gaster
lan - I first look at the documentation for Windows Common controls in msdn, then I googled LVM_SETHOTCUSOR and found the header file with all the constants.