0

I would like to control if the user do single click or double click when is clicked with the mouse. So I use this code:

private void MouseSingleClickCommand(RoutedEventArgs e)
{
    _dtMouseClick.Start();
}


private void MouseClick_Tick(object sender, System.EventArgs e)
{
    _dtMouseClick.Stop();

    //my one click code
}



private void MouseDoubleClickCommand(MouseButtonEventArgs e)
{
    _dtMouseClick.Stop();
    //code of the double click
}

_dt is a DispatcherTimer that is created in the constructor of the view model:

_dtMouseClick =
                new System.Windows.Threading.DispatcherTimer(
                new TimeSpan(0, 0, 0, 0, 200),
                System.Windows.Threading.DispatcherPriority.Background,
                MouseClick_Tick,
                System.Windows.Threading.Dispatcher.CurrentDispatcher);

However the code of one click is always executed because the dispatcher is not stopped.

Why?.

Thanks.

EDIT: I include the axml of the button:

<StackPanel Height="Auto" HorizontalAlignment="Left" Margin="548,0,0,0" Name="stpBotnoesBasicos" VerticalAlignment="Top" Width="Auto">
                    <Button Content="Buscar" Height="23" Name="btn01" Width="75">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Click">
                                <cmd:EventToCommand Command="{Binding MouseSingleClickCommand}" PassEventArgsToCommand="True"/>
                            </i:EventTrigger>

                                <i:EventTrigger EventName="MouseDoubleClick">
                                <cmd:EventToCommand Command="{Binding MouseDoubleClickCommand}" PassEventArgsToCommand="True"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                    </Button>
</Stackpannel>
Álvaro García
  • 18,114
  • 30
  • 102
  • 193
  • Probably you forgot to start your timer? – Nikolay Aug 23 '13 at 10:11
  • I star my timer in the click method. – Álvaro García Aug 23 '13 at 11:08
  • Please, could you include a XAML tag/reference? C#/C#-4.0 is understood as winforms by default. – varocarbas Aug 23 '13 at 11:49
  • Ah I see! You misunderstood my previous comment: your original code was enough to know where the problem was (I have explained it to you in my answer and shown a graphical way to understand what is going on: you are stopping the timer after the first tick). When I said XAML tag/reference, I meant adding XAML (or WPF) to the references of this question or to the title to show clearly what this code is about (to future readers). Your problem is answered/fixed by my answer; please, understand it or feel free to ask anything you don't understand. – varocarbas Aug 24 '13 at 09:15
  • Your problem is clear: you are stopping the timer in the first tick and not allowing it to work as expected. Even though, you are free to not accept my answer (thanks for the (deserved) upvote, though), what does not sound too good is posting a clearly-wrong answer yourself by saying that it has solved your problem: you are misleading future readers; please, delete your answer or feel free to discuss about it to understand the situation properly (and re-write if you wish). – varocarbas Aug 24 '13 at 12:52
  • Easier: please, tell the EXACT functionality you want to accomplish with the timer and I will tell you how to do that (and explain why works). You can process all this information and write your own answer afterwards (but a proper one), that is, one which will not contain sentences on the lines of "but for some reason...". That is, getting the help you were requesting when wrote this question; the one I have offered. – varocarbas Aug 24 '13 at 13:00

2 Answers2

1

You are stopping it after the first tick (_dtMouseClick.Stop(); under MouseClick_Tick). Try the following changes to get a clearer picture:

private void MouseClick_Tick(object sender, System.EventArgs e)
{
    MessageBox.Show("One tick more");
}

And change the Interval to 1 second (new TimeSpan(0, 0, 0, 0, 1000)).

Now, the MessageBox pops up once every second, until you double-click (MouseDoubleClickCommand is called). Inside MouseClick_Tick you have to put the code to be triggered regularly, not a code avoiding the Timer to run.

CLARIFICATION

The expected way in which a timer has to be used consists in three parts: START, DO ANYTHING (on the _tick event), STOP once it is not useful anymore. How to register the number of clicks for example?

Int clicksCounter = 0; //Declared globally.

You store the information you want (number of clicks); and start the timer when required.

private void MouseLeftButtonDownCommand(MouseButtonEventArgs e)
{
     clicksCounter = clicksCounter + 1;
     if (clicksCounter == 1)
     {
         _dtMouseClick.Start(); //(set a small enough interval: 50ms or 10ms or even 1ms).
     }
}

Now you have to check the values of the target variable from the _Tick method (which can stop itself when required), that is:

private void MouseClick_Tick(object sender, System.EventArgs e)
{
   //This event should be called as quickly as possible in order to check clicks at any time
    if(clicksCounter >= 2)
    {
        //Condition met. Reset the variables
        clicksCounter = 0;
        _dtMouseClick.Stop(); 
       MessageBox.Show("The user has clicked the mouse button more than once");
    }
}
varocarbas
  • 12,354
  • 4
  • 26
  • 37
0

This solution is based on the solution from this other question:

base solution

If I use the PreviewMouseLeftButtonDown to control when is single click or double click works, instead of using two events (click and doubleclick).

So I solve the problem with this code:

This first method control the click with the mouse.

private void MouseLeftButtonDownCommand(MouseButtonEventArgs e)
        {

            if (e.ClickCount == 1)
            {
                _dtMouseClick.Start();
            }

            else if(e.ClickCount > 1)
            {
                _dtMouseClick.Stop();

                //the code of the double click
            }
        }

This method is the method that is linked to the DispatcherTimer, that is execute if is not stopped with the second click of the mouse.

private void MouseClick_Tick(object sender, System.EventArgs e)
        {
            _dtrMouseClick.Stop();

            //code of the single click                
        }

The dispatcherTimer is create in the constructor of the view model

_dtBotonBuscarMouseClick =
                new System.Windows.Threading.DispatcherTimer(
                new TimeSpan(0, 0, 0, 0, 250),
                System.Windows.Threading.DispatcherPriority.Background,
                MouseClick_Tick,
                System.Windows.Threading.Dispatcher.CurrentDispatcher);
            _dtMouseClick.Stop();

The interval is 250ms that is the interval that is the time that the user has to double click.

In this solution, I use the same way to stop the dispatcherTimer, the stop() method, but for some reason if I use the two events (click and mouseDoubleClick) the dispatcherTimer is not stopped in the double click and if I use the MouseLeftButtonDown event the solution works.

EDIT

This solution for me works as I expect.

In the MouseLeftButtonDown event, I check if the ClickCount is 1 or 2. If the count is 1, then I start the timer. So the timer will execute its code if is not stopped before.

The timer will be stopped if the second click is a double click. This is when the ClickCounter > 1. If the lapse time between clicks is enough big, then clickcounter is always 1, so this event, MouseLeftButtonDown, control when is double click or not.

When the timer is executed, first I stop it because I want exectued its code once, the code that I want when is only one click.

If I double click, then I stop the timer before the interval is reached, so never is executed, and execute the code that I want when is double click.

Community
  • 1
  • 1
Álvaro García
  • 18,114
  • 30
  • 102
  • 193
  • Sorry to say, but your correction is wrong. Try to understand the idea: the timer is expected to be called (its tick method, that is: MouseClick_Tic) regularly as many times as required between start and stop (which might be triggered by the same button than start or by other one). When you are doing is stopping right after the first interval (by writing _dtrMouseClick.Stop() on the MouseClick_Tick), what does not make absolutely no sense: the timer will always be stop after the first tick; what is the point of timer.stop? – varocarbas Aug 24 '13 at 12:39
  • In summary you are basically not doing anything (calling a method from one place or from the other; that is, from different buttons or the same button does not change anything), not even understanding the problem. I am not a downvoter (much less when you upvoted my answer; although well... my answer is right) but this answer does not have a point and thus should be deleted: please, don't say that this has solved your problem because is impossible. Feel free to discuss with me about anything. – varocarbas Aug 24 '13 at 12:46
  • I explain my solution in the solution, because here in the comments there are not space enough. – Álvaro García Aug 26 '13 at 08:58
  • I have read your explanation and has no point. Imagine that you have a chronometer watch on your hand, set up such that an alarm is triggered every 10 minutes. What your code (the original version and the one in this answer) does is starting it and stopping after the first 10 mins no matter what. You cannot complain about the stop button not working 1 hour later because you stopped it after the first 10 minutes!!? Is it so difficult to understand?! What this reply does is exactly the same (stopping it after 10 minutes) but relying on a different stop button and saying that now it works?! – varocarbas Aug 26 '13 at 09:02
  • But the most curious thing is that you come here without understanding what is happening (that's why you have asked); someone (I) explains you clearly what is happening (with lots of extremly descriptive examples of a behaviour which I think that is pretty evident) and you don't want to understand. Prefer to give this person a lesson of non-sense. If you are so sure that you are doing the right thing, could you please explain me what is _dtrMouseClick.Stop(); exactly doing on the tick event and when this part is called? – varocarbas Aug 26 '13 at 09:05
  • _dtrMouseClick.Stop() in the tick event prevent that the code is executed only once, because if I don't stop the ticker, the code corresponding to one click is execute forever. – Álvaro García Aug 26 '13 at 09:21
  • Excellent. So you want to use the stop button only within the given tick (= 250 ms). And you are saying that the original code didn't allow the stop button to work and that the new one does it. Nothing to do with the fact that 250 ms is a pretty short period; too short to allow someone to click a button, perhaps? Might not be this the reason, other than thinking that your current answer is actually fixing something? – varocarbas Aug 26 '13 at 09:27
  • Yes, my problem is that I don't know why if I separate my solution in two events (click and mouseDoubleClick) the timer is not stopped when I try it in the mouseDoubleClick event. However when I use only the event MouseLeftButton down the timer is stopped. And in the first solution, with the two events, I tried to use an interval of 1000ms and the problems persists. So the short interval is not the problem. Also, I test with 250ms and for my is time enough to double click. If in the future I see that the user need more time, I can change this interval. – Álvaro García Aug 26 '13 at 09:35
  • Sorry, in my last comment I think I explain bad. I want to say that in the tick event I use _dtMouseClick.Stop() as first line of code because I only want to execute this code only once, not forever. – Álvaro García Aug 26 '13 at 09:38
  • Sorry to correct you but this is not time enough to click and this is your whole problem (why forcing to stop it after 250 ms). If you want to understand how quick is 250 ms, I recommend you to implement the code I suggested (2 days ago) with your original interval. The only difference between your actual and your original code is a slight time variation (perhaps from the user perspective, perhaps from the code one) which is relevant for a so short time. It is not affecting the behaviour of the time at all. – varocarbas Aug 26 '13 at 09:39
  • Regarding your last comment: what you want is execute the timer until you click on "stop". This is the whole point of a timer, whole point which you are missing when writing the stop on the tick event and making it last just 250 ms; what is not enough for anything (not even for clicking the STOP button). The idea is really simple and still don't understand why you are not getting it: the timer works fine; you have configured it fine; and it will work from the moment when you press START until the moment when you press STOP. If you force it to just last 250 ms, you don't time to press STOP. – varocarbas Aug 26 '13 at 09:42
  • Well, I only have one button, the user dont have to stop the timer. If the user would have to stop the timer with a stop button, 250ms is very short interval, of course, but this is not the case, I only want to execute one code if the user sigle click or another code if the user double click in the same button. I only have one button. – Álvaro García Aug 26 '13 at 09:46
  • With STOP I mean when you trigger the timer.stop it does matter what you want it for (for determining if there is single click or double click or for just counting the milliseconds): you are stopping the timer with the second click (this is the whole point of your answer and the whole point of your code); but, on top of that, you are stopping the timer after 250ms and thus the true stop point (second click) might not be reached. Nothing to do with the timer working wrongly, but with the fact that 250 is a too short period even for click twice on a button (+ processing the click)!!! – varocarbas Aug 26 '13 at 09:50
  • SUMMARY: your question was: why my timer is not working? The answer is: it works perfectly but you are (unnecessarily and pointless) restricting it by stopping it automatically after the first tick and thus making the whole period 250ms long what is too short. Thus, how can you make your code work always? (the second-click part be reached every time and the timer.stop be used there): remove the stop in the tick event!!! In this way, the user can do double click in 250ms or in 100ms or in 300ms. You might even decrease the interval to 10ms (or to 1ms) – varocarbas Aug 26 '13 at 09:53
  • And thus the time would be checking for a double click much quicker than now. But what does not make any sense is stopping the timer after the first tick; it goes against what this control is about. If you prefer to do that, accept the consequences and don't wonder why the timer is not recognising anything beyond 250 ms!!!! Is a bit clearer (the a priori extremely clear IMHO) problem here? Your code does not solve anything because there is nothing to be solved: you are using the timer wrongly, start using it rightly. – varocarbas Aug 26 '13 at 09:55
  • My origianl problem was that the timer is not stopped when double lick, not that the timer is not worked, because its code, in my original question, the first click is alwys detected and then the timer is started always. If I don't stop the timer in the tick event, the timer is always executed each 250ms, and it only would be stopped if a user double click, but this double click perhaps never occurs, so the timer always would be in execution. So this is the needed to use _dtMouseClick.Stop() in the tick event, because I only one execution each time. – Álvaro García Aug 26 '13 at 10:01
  • I though that you had a problem. Try to understand the help (the for-sure-working help) I am giving: the timer checks anything each X-seconds. You want to check whether the user clicks twice on the mouse button. Best way to accomplish it? Check the smallest interval acceptable (the one not affecting performance appreciably; perhaps 50ms) and LET THE TIME DO ITS WORK, that is, register whatever you want (click of the user? OK) in its tick event. Whatever something has been registered (the second click), stop the timer. I will update my answer to show the ideas clearer. – varocarbas Aug 26 '13 at 10:06
  • Please, take a look at the update I have written right now to understand how a Timer has to be used, why yours was working perfectly since the start (you were using it wrongly) and why your "correction" does not have any point. – varocarbas Aug 26 '13 at 10:16
  • In this post (http://stackoverflow.com/questions/18376012/how-to-avoid-click-when-i-want-double-click) the answer of "wolfovercats", is the solution that I would like to use (stop the dispatcherTimer in the tick event). My problem is that the timer is not stopped when I try it in the mouseDoubleClickEvent. So for that reason I tried to mix this solution with the solution of the user "Shane.C". So I merge the two solution. In this case the timer can be stopped in the event. But the philosophy is the same than solution of "wolfovercats" (stop the timer in the tick event). – Álvaro García Aug 26 '13 at 10:34
  • This is why I create this post, because I can't stop the timer in the DoubleClickEvent, but when I use the MouseLeftButtonDown event I can stop the timer in the double click. – Álvaro García Aug 26 '13 at 10:37
  • I think that control the single click or double click in the tick event is not the best solution because it is needed to create a global variable and also I think that the control of what to do when is single click or double click is better in the mouse event, not in the timer that is code that depends of the number of clicks. – Álvaro García Aug 26 '13 at 10:38
  • Let's go step by step. Firstly: you are the one bringing the timer into consideration (and the one doing it wrongly; not knowing how to use it and coming up with a nonsense to say that the problem is fixed). Now try to understand what my code does and what your code does (doing things veerrry slowly and step by step is the best way to avoid confusions): my code uses the timer as expected, that is, relies on what makes the timer useful at all: its tick event (the alarm of the choronometer I referred above). In its tick event it performs what is required (in my example counting the clicks). – varocarbas Aug 26 '13 at 10:42
  • Now let's analyse your code: you start a timer on the first click and stop it twice (on the second click and the tick event). So you basically are: starting a chronometer to know when you have to eat and setting an alarm every 10 minutes; the logical proceeding seems to eat every time the alarm sounds (and stop the chronometer the last time); this is what my code does and how the timer is expected to be used. What your code does: you eat whenever you are hungry and once 10 minutes have passed you stop the chronometer no matter what -> it does not make too much sense, doesn't it? – varocarbas Aug 26 '13 at 10:46
  • See, I will be clear with you: you are not only aiming something ridiculous (as accurately described in my last comment); but you look for help; find someone wasting his time explaining you (EXTREMELY CLEARLY) how things should be done and the only thing you do is keep claiming more and more senseless statements (I don't know... perhaps by thinking that just the fact of replying you means that what you say has the slightest sense; I do reply every time to everyone until reaching an extremely ridiculous stage... already there, continue reading). Unfortunately, I know quite a few – varocarbas Aug 26 '13 at 10:49
  • people like you: you don't seem to be more worried to prove an unprovable point that to get a solution/do things rightly/learn. From my experience with this people, I am pretty sure that you will not change: you will continue things wrongly; no matter how many people explains you how to them rightly; no matter how many wrong results come to you over and over. You seem to be in the same reality that I do and the fact of seeing errors do not seem to trigger in you the idea "wait! perhaps I did something wrong, would try differently"... – varocarbas Aug 26 '13 at 10:51
  • ... even despite of knowing people like you and knowing that all my explanations will be useless (because you will not learn; prefer to be wrong and suffer the consequences than change/learn/evolve); I cannot avoid being an extremly logical person who cannot believe that someone is so blindly that cannot see the reality in from of his eyes. But it is enough. You have already made me waste to much time today. As said in one of my previous comments: don't expect any more help from me in the future (and, with this attitude, most likely from noone). Bye. – varocarbas Aug 26 '13 at 10:54
  • Yes, the idea is "to eat when I am hungry" because the user is who decides when to eat. The question is what to meat. If the user single click, then the code in the tick event ensure that is executed the code for single click. If the user double click, then the timer is canceled to excute the code of the double click, and if I execute the code of the double click, I don't want to execute the code for the single click so I need to stop the timer. – Álvaro García Aug 26 '13 at 10:54
  • So you are saying that the solution in the other post, given for the user wolfovercats is wrong? – Álvaro García Aug 26 '13 at 10:55
  • (sorry but I cannot avoid this... seriously what is wrong with you and the understand of what happens around you?): if you want to eat when you are hungry, WHY ON THE HELL ARE SETTING A CHRONOMETER (and why on the hell are you blaming the chronometer when you don't the food on time)???!!! You are even understanding what I am writing? – varocarbas Aug 26 '13 at 10:56
  • Because the chronometer ensure that if the user does not double click, the code for one click must be exectued, and this is only possible with the use of a chronometer. – Álvaro García Aug 26 '13 at 10:58
  • (this will last forever?) haven't read the post but a priori if the anwer is yours (which is wrong) yes it is pointless. On the other hand, wolfovercats does not seem to have a really impressive ranking/experience in this site to assume that what he writes is right, isn't it? A ranking of 79! wow (not misunderstand: the ranking does not say anything; but if you want to assume if something is wrong/right without knowing what is going on I guess that my ranking over 3800 says a bit more than 79). BTW you accept your answer instead of his?! LOL. Really honest behaviour. – varocarbas Aug 26 '13 at 11:00
  • Because the chronometer ensure that if the user does not double click, -> where on the hell are you written this code? in the timer.STOP that is the only code written in the _tick event, that is, what is triggered when the alarm is triggered?!! But seriously? Why don't you try to think what you say before talking/writing?... In general in life? You know that knowing what you talking about tends to be the right thing to do, don't you? See enough... this conversation is a true joke and thus I will better stop talking to you before you think that is serious at all. – varocarbas Aug 26 '13 at 11:03
  • I understand the solution of wolfovercats. The only problem was that the timer was not stopped in the doble click event. But the solution is clar. And is not the only solution that has the same philosophy, in the MSDN has a similar soulition but with more code. – Álvaro García Aug 26 '13 at 11:04
  • I hope that you understand that what you are saying does not make any sense. I have stopped replying you because what you say is ridiculous -> Other mark question for you, eh? Good work! I will better flag this one, because what you say is ridiculous and should be considered by any future reader. – varocarbas Aug 26 '13 at 11:55
  • Flagged. BTW, do you know that if you accept other's answer, this other person gets points and that you also get them (because of acting rightly)? But if you accept your own answer nobody gets anything?. Also I am starting to think that you are not from Spain. Did you understand what I told you in our first conversation? I said that we have the same name: Álvaro; and your first family name (the one from the father in Spain) is like my second family name (the one from the mother): García. I didn't understood why you didn't reply to that; now I get it; sorry for the misunderstanding. – varocarbas Aug 26 '13 at 12:04
  • Well, if you have a better solution with only one button execute one code if the user single click or other different code if the user double click the same button, then I can study it. With your solution, how you don't stop the timer in the tick event, if the user does not double click never, then the code of the timer is execute each interval. This is what I don't know. – Álvaro García Aug 26 '13 at 12:09
  • I have corrected your (inexistent) "problem": if you want to use a timer, use it rightly; otherwise, don't use it. Your question was: what is wrong here? The answer is: nothing; it works as it should. The problem is that you are not doing what is required to get what you want. Thus, this answer is not a solution and thus shouldn't be marked as the right answer (that's why I have flagged it). I am not able to communicate with you (and have tried it really hard). Don't misunderstand my silence as implicit agreement; I don't agree with anything on this question/answer. – varocarbas Aug 26 '13 at 12:14