views:

288

answers:

2

I have an application written in C# targeting .NET Compact Framework 3.5, running on Windows CE. From time to time, operations lasting for a second or so are being performed on the UI thread. I currently set the Cursor.Current property to indicate that the application is busy, but this does not prevent mouse events from eager users to queue up. This sometimes leads to unintended clicks.

What is the best way to ignore queued mouse messages on the .NET Compact Framework platform? Sadly, the code has to run on the UI thread.

A: 

I believe that the best solution is to prevent the events from happening. You can do that by disabling all the controls and re-enabling them, when the lengthy operation finishes.

kgiannakakis
+5  A: 

Disabling the controls won't help you, as I've found from my POS application that the users can sneak in another click in about 50ms, especially when using a touch screen that is not calibrated.

One of the problems this creates is when producing an invoice, you can't have a duplicate click produce another invoice, just because there's a 50ms delay before clearing the current invoice.

In cases like this, I use a pattern similar to this:

    public static void ClearMouseClickQueue()
    {
        Message message;
        while (PeekMessage(out message,IntPtr.Zero, (uint) MessageCodes.WM_MOUSEFIRST,(uint) MessageCodes.WM_MOUSELAST,1) != 0)
        {    
        }
    }

    private object approvalLockObject = new object();

    private void btnApproveTransaction_Click(object sender, EventArgs e)
    {
        ApproveTransactionAndLockForm();
    }

    private void ApproveTransactionAndLockForm()
    {
        lock (approvalLockObject)
        {
            if (ApprovalLockCount == 0)
            {
                ApprovalLockCount++;
                ApproveTransaction();
            }
            else
            {
                CloseAndRetry();
            }
        }
    }

    private void ApproveTransaction()
    {
        ClearMouseClickQueue();

        this.Enabled = false;

        Logger.LogInfo("Before approve transaction");

        MouseHelper.SetCursorToWaitCursor();

        ... validate invoice and print
    }

In case you need to reenable the screen, do this:

            this.Enabled = true;

            ApprovalLockCount = 0;

            DialogResult = DialogResult.None;
Miki Watts
For completeness, I've listed the necessary definitions for the p/invoke at http://pastebin.ca/1369082
Tormod Fjeldskår