views:

717

answers:

2

.Net Compact Framework

Scenario: User is on a screen. Device can't finds a printer and asks the user if they want to try again. If they click "No", the current screen is closed and they are returned to the parent menu screen. If they click the "No" button multiple times, the first click will be used by the No button and the next click will take effect once the screen has completed redrawing. (In effect clicking a menu item which then takes the user to another screen.)

I don't see a good place to put a wait cursor...there isn't much happening when the user clicks "No" except a form closing. But the CF framework is slow to redraw the screen.

Any ideas?

+2  A: 

Random thoughts:

  • Disable the some of the controls on the parent dialog while a modal dialog is up. I do not believe that you can disable the entire form since it is the parent of the modal dialog.
  • Alternatively I would suggest using a Transparent control to catch the clicks but transparency is not supported on CF.
  • How many controls are on the parent dialog? I have not found CF.Net that slow in updating. Is there any chance that the dialog is overloaded and could be custom drawn faster that with sub controls?
  • override the DialogResult property and the Dispose method of the class to handle adding/remvoing a wait cursor.
Jack Bolding
Good suggestions, gives me some other things to try. Thank you!
MrJeepster
You can do proper transparency with CF but you have to glue together rectangular regions via P/Invoke. Not very pretty.
Quibblesome
+2  A: 

Hi,

you can skip pending clicks by clearing the windows message queue with Application.DoEvents();

We use the following custom Event class to solve your problem (preventing multiple clicks and showing a wait cursor if necessary):

using System;
using System.Windows.Forms;

public sealed class Event {

    bool forwarding;

    public event EventHandler Action;

    void Forward (object o, EventArgs a) {
        if ((Action != null) && (!forwarding)) {
            forwarding = true;
            Cursor cursor = Cursor.Current;
            try {
                Cursor.Current = Cursors.WaitCursor;
                Action(o, a);
            } finally {
                Cursor.Current = cursor;
                Application.DoEvents();
                forwarding = false;
            }
        }
    }

    public EventHandler Handler {
        get {
            return new EventHandler(Forward);
        }
    }

}

You can verify that it works with the following example (Console outputs click only if HandleClick has terminated):

using System;
using System.Threading;
using System.Windows.Forms;

class Program {

    static void HandleClick (object o, EventArgs a) {
        Console.WriteLine("Click");
        Thread.Sleep(1000);
    }

    static void Main () {
        Form f = new Form();
        Button b = new Button();
        //b.Click += new EventHandler(HandleClick);
        Event e = new Event();
        e.Action += new EventHandler(HandleClick);
        b.Click += e.Handler;
        f.Controls.Add(b);
        Application.Run(f);
    }

}

To reproduce your problem change the above code as follows (Console outputs all clicks, with a delay):

        b.Click += new EventHandler(HandleClick);
        //Event e = new Event();
        //e.Action += new EventHandler(HandleClick);
        //b.Click += e.Handler;

The Event class can be used for every control exposing EventHandler events (Button, MenuItem, ListView, ...).

Regards, tamberg

tamberg
That's weird because I don't think CF plays the same game when it comes to Key events. I tried to do something similar with keys but ended up having to set a gate, jump threads and then Application.DoEvents to flush the keyboard buffer to prevent getting multiple key events.
Quibblesome
Hi, as far as I know, key events are fired from another thread while mouse events come from the GUI thread.
tamberg