C4d
C4d

Reputation: 3292

Check if event (doubleClick) is running

I am writing a tool which switchs between a lot of states. For some events I need to be sure they wont get executed a second time while the called function (inside the event) is running. This is how I managed it before:

// Global variables //
public bool func1IsRunning = false;
public bool func2IsRunning = false;
...

public void listView_DoubleClick(object sender, EventArgs e) 
{
    if(!func1IsRunning)
    {
        func1();
        func1IsRunning = false;
    }
}

public void func1()
{
    func1IsRunning = true;
    // some code in here //
}

But with every extension of my tool the list of the global variables grows up. Also the events and functions getting less clear to read.

Isnt there a way like this(?):

public void listView_DoubleClick(object sender, EventArgs e) 
{
    if(DoubleClick.IsHandled)
    {
        func1();
    }
}

public void func1()
{
    // some code in here //
    // ................. //

    DoubleClick.IsHandled = true; // at the end of the function //
}

So what I am looking for is a way to determine if an event is still running or not. My code is working, im just unhappy with how it looks like.

Any ideas?


UPDATE 1

I decided to use Steve's answer as it solves my problem by the clearest way. Anyway it is NOT running correctly for now.

Here is how my code looks like:

public void listView_DoubleClick(object sender, EventArgs e)
        {
            try
            {
                listView.DoubleClick -= new EventHandler(listView_DoubleClick);
                itemEdit();
            }
            finally
            {
                listView.DoubleClick += new EventHandler(listView_DoubleClick);
            }
        }

The code above is NOT disabling the handler.

public void listView_DoubleClick(object sender, EventArgs e)
        {
            try
            {
                listView.DoubleClick -= listView_DoubleClick;
                itemEdit();
            }
            finally
            {
                listView.DoubleClick += listView_DoubleClick;
            }
        }

This code is also not disabling the handler.

This is the line where the handler gets enabled (MainForm.Designer.cs):

this.listView.DoubleClick += new System.EventHandler(this.listView_DoubleClick);

There are no errors raised. The event just gets fired again and again. Where is the problem?

UPDATE 2:
As Sinatr asked in the comments below if my function is really waiting or just enabling user input he discovered where the mistake was made.

Steve's answer is correct according to my wrong written question. Thanks a lot to all of you guys.

Upvotes: 0

Views: 895

Answers (3)

Steve
Steve

Reputation: 216343

Just disable the event handler

public void listView_DoubleClick(object sender, EventArgs e) 
{
    try
    {
         listView.DoubleClick -= listView_DoubleClick;

         // Now, even if func1 causes a DoubleClick event,
         // or user manages to trigger a DobuleClick
         // there is no event registered and this code could
         // reentered until you exit from func1.
         func1();
    }
    finally
    {
         // Important part. the finally block is required 
         // because you should readd the event handler 
         // ALSO in case an exception occurs in func1 
         // and it is not handled there
         listView.DoubleClick += listView_DoubleClick;
    }
}

EDIT

Looking at your comment I suspect that this DoubleClick event is assigned to more than one control. If this is the case, using the global listView global instance of a listview doesn't disable the double click on other controls that are linked to the same code.
If this is the case then you need a more generic approach

public void listView_DoubleClick(object sender, EventArgs e) 
{
    Control c = sender as Control;
    try
    {
         if(c != null)
         {
              c.DoubleClick -= listView_DoubleClick;

              // Now, even if func1 causes a DoubleClick event,
              // or user manages to trigger a DobuleClick
              // there is no event registered and this code could
              // reentered until you exit from func1.
              func1();
         }
    }
    finally
    {
         // Important part. the finally block is required 
         // because you should readd the event handler 
         // ALSO in case an exception occurs in func1 
         // and it is not handled there
         if(c != null) c.DoubleClick += listView_DoubleClick;
    }
}

Of course, this is just to enable/disable DoubleClicks events, it cannot works if you assign this event handler to other standard events like Click that have the same signature (object sender, EventArgs e)

Upvotes: 3

dotNET
dotNET

Reputation: 35440

A simple state-machine should solve your problem without requiring too many variables. Create an Enum named AppState like this:

enum AppState
{
     Ready = 1,
     InsideListView1Click = 2,
     InsideListView1DoubleClick = 3
     InsideListView2Click = 4,
     InsideListView2DoubleClick = 5
}

This enum could grow as you add new controls and/or event-handlers to your application. Now use a single global variable that keeps track of the application state and modify it inside event-handlers appropriately:

private AppState m_State = AppState.Ready;

And in the event-handlers you would do:

private void ListView1_DoubleClick(object sender, EventArgs e)
{
    lock
    {
        if(m_State != AppState.Ready)
            return;
        else
            m_State = AppState.InsideListView1DoubleClick;
    }

    //Do your stuff

    m_State = AppState.Ready;
 }

This way newer calls will be ignored instead of being queued. If you expect to be in multiple states at the same time, you could apply [Flags] attribute on this enum as well. Also note that enums are thread-safe and evaluating them is atomic, so multi-threading shouldn't be a problem either.

Upvotes: 0

Christoph Fink
Christoph Fink

Reputation: 23113

How about something like the following using locks:

private object globalLock = new object();
private Dictionary<int, object> lockObjects = new Dictionary<int, object>();

public void listView_DoubleClick(object sender, EventArgs e) 
{
    object lockObject;
    lock (globalLock) // to avoid two threads creating the object
    {
        if (!lockObjects.ContainsKey(1))
            lockObjects.Add(1, new object());
        lockObject = lockObjects[1];
    }

    if (Monitor.TryEnter(lockObject) // enter only if no thread has already entered
    {
        try { func1(); }
        finally { Monitor.Exit(lockObject); }
    }
}

This is different to Steve's logic in the matter that it is thread-safe.

Upvotes: 1

Related Questions