Wpf DispatcherTimer.Tick interupted by mouse hook event in same thread - wpf

I have a created a thread that has a dispatcher run for processing low level mouse hook events, and created a DispatcherTimer based on this dispatcher.
When DispatcherTimer.Tick() was fired, I simulated another mouse down message. Then something strange happend:
The Dispatcher.Tick() was interupted and mouse hook event fired in the same thread. After the mouse hook event processed, the DispatcherTimer.Tick() continues to end.
From what I understand, the dispatcher will process tasks one by one, so it should execute the DispatcherTimer.Tick() method completely, then other hook events.
Is this behaivor normal?
Is there anyway that I can ensure DispatcherTimer.Tick() was executed completely before hook event fired?
Creating dispatcher thread:
public static class DispatcherBuilder
{
public static Dispatcher Build()
{
Dispatcher dispatcher = null;
var manualResetEvent = new ManualResetEvent(false);
var thread = new Thread(() =>
{
dispatcher = Dispatcher.CurrentDispatcher;
var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
SynchronizationContext.SetSynchronizationContext(synchronizationContext);
manualResetEvent.Set();
try
{
Dispatcher.Run();
}
catch
{
// ignore
}
}, maxStackSize:1);
thread.Priority = ThreadPriority.Normal;
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
manualResetEvent.WaitOne();
manualResetEvent.Dispose();
return dispatcher;
}
}
Code for creating timer and hook setup:
// creating disapatcher:
_hookDispatcher = DispatcherBuilder.Build();
// creating timer on the dispatcher
_mouseDownTimer = new DispatcherTimer(DispatcherPriority.Normal, _hookDispatcher);
_mouseDownTimer.Tick += new EventHandler(mouseDownTimer_Tick);
_mouseDownTimer.Interval = TimeSpan.FromMilliseconds(_dataService.Settings.RightBtnPopupDelayMs);
// create hook
_hookDispatcher.Invoke(() =>
{
_mouseHook = new MouseHook();
_mouseHook.MouseUp += MouseHookOnMouseUp;
_mouseHook.MouseDown += MouseHookOnMouseDown;
_mouseHook.MouseWheel += MouseHookOnMouseWheel;
_mouseHook.MouseMove += MouseHookOnMouseMove;
_mouseHook.MouseHWheel += MouseHookOnMouseHWheel;
_mouseHook.Start();
});
The following is some Debug.WriteLine() output:
177,250 MouseDown Right Thread:14
177,250 MouseDown Right Captured Thread:14
// DeispatcherTimer.Tick() Started
177,360 Timer Tick Begin Thread:14 -- in DeispatcherTimer.Tick()
177,360 Sending RightButtonDown -- in DeispatcherTimer.Tick()
// MouseHookOnMouseUp() called in same thread
177,485 MouseUp Right Thread:14 -- in MouseHookOnMouseUp()
177,500 MouseUp Right Captured Thread:14 -- in MouseHookOnMouseUp()
// MouseHookOnMouseDown() called in same thread
177,500 MouseDown Right Thread:14 -- in MouseHookOnMouseDown()
// Returned to DeispatcherTimer.Tick() in same thread
177,500 Timer Tick End -- in DeispatcherTimer.Tick()
177,500 MouseDown Right Thread:14

Everything seems to be alright.
"When DispatcherTimer.Tick() was fired, I simulated another mouse down
message. Then something strange happend: The Dispatcher.Tick() was
interupted and mouse hook event fired in the same thread. [...]"
In general event handlers are executed on the same thread the event was raised on, except execution is marshalled to a different thread by the event source or the handler itself.
Since you had explicitly setup the DispatcherTimer to run on the _hookDispatcher, the Tick handler, which raises the event, runs on the _hookDispatcher thread. Therefore the Tick handler and all events raised by this handler and their corresponding event handlers execute on the same thread - the thread the DispatcherTimer is associated with.
This answers your first question, why the event handlers are executed on the same thread the DispatcherTimer executes on.
"[...] After the mouse hook event processed, the
DispatcherTimer.Tick() continues to end.
From what I understand, the dispatcher will process tasks one by one,
so it should execute the DispatcherTimer.Tick() method completely,
then other hook events."
Events are always raised synchronously (WPF doesn't implement asynchronous events).
1) The Tick handler will execute.
2) This handler raises a mouse event.
3) The event delegate is invoked synchronously, which means the continuation of the Tick handler is "suspended".
4) Invocation of the mouse event delegate means all registered callbacks are invoked too.
5) After the last callback was invoked the Tick handler can continue execution.
So your observations are correct, but this behavior is absolutely normal in this context.
If you want the Tick handler continue to execute while the mouse event will be handled, you should raise the mouse event on a background thread. But since input events are handled to do UI related work, it is very likely that those handlers will invoke the Dispatcher to access UI resources (or any DispatcherObject). Executing such handlers on a background thread, forcing the handlers to synchronize with the UI thread again is too expensive and usually doesn't make any sense.
The recommended solution is to raise the events using Dispatcher.InvokeAsync:
private void OnTick(object sender, EventArgs e)
{
Dispatcher.InvokeAsync(RaiseMouseEvent, DispatcherPriority.Background);
}
Dispatcher.InvokeAsync executes asynchronous. Therefore, control returns immediately to the calling object (the Tick handler) after it is called.

Related

Is there a way to force the immediate completion of a Storyboard?

The gist of the code is
Storyboard story = new Storyboard();
DoubleAnimation anim = new DoubleAnimation();
anim.Completed += anim_Completed(object sender, EventArgs e);
...
story.Children.Add(anim);
story.Completed += story_Completed(object sender, EventArgs e);
story.Begin(control, true);
return;
In another method I have:
// Finish the Storyboard now
story.SkipToFill(control);
// I want it to get back to me here after the Completed events have run.
The problem is that the Completed events don't run until the next pass of the WPF dispatcher message loop which is no good to me because they update some state. I also tried
story.Stop(control);
but then the Completed handlers don't get run at all it seems. Is there a way to get the Completed handlers to fire immediately?
To avoid running your storyboard on another ui thread and handling locks or signals you can try the following:
Action emptyDelegate = delegate() { };
control.Dispatcher.Invoke(DispatcherPriority.Render, emptyDelegate);
...to force a render pass and hence pick up the completed events that don't seem to fire when you need them to during processing in the UI's code-behind.
You may see some artefacts come into and out of existence though as any updated dependency property values will, of course, be rendered.

WPF: What is the correct way to wait for a storyboard animation to complete before performing an operation

I have a storyboard which I reuse to animate some pictures, I wanna perform some operation after each animation, which includes some calculations, and then running another animation, so I believe I should be using the StoryBoard's Completed Event MyStoryboard.Completed += storyboard_Com​pleted;
What I'm curious about is, should I start the next animation in the current StoryBoard's Storyboard_Completed Event? And, are there any implications if I started the first animation in a separate thread using the Application.Current.Dispatcher Object?
If I called a StoryBoard.Begin() in a separate thread using the Application.Current.Dispatcher, does the Storyboard_Completed Event also get invoked in the UI thread? In this case, do I still need to wrap the Next Animation within another Dispatcher Invoke?
private void Story_Completed(object sender, EventArgs e)
{
Application.Current.Dispatcher.Invoke((Action)delegate()
{
SomeNewStoryBoardAnimation.Begin();
}
}
Is this correct? Or is there a better way to check if a storyboard has ended and start the next set of calculations & storyboard animation right after that?
I've thought of using a single background worker to handler all animations and calculations in sequence, but I'm also wondering how to "wait" for the animation to complete before starting on the next set of calculations and animations. Is it normal for a BackGroundWorker to have Thread.sleep while waiting for animation to complete?
You could wrap the Storyboard in a Task object and await its completion.
Here is an excellent bit of sample code illustrating how to do just that, taken from a blog post by Morten Nielsen:
public static class StoryboardExtensions
{
public static Task BeginAsync(this Storyboard storyboard)
{
System.Threading.Tasks.TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
if (storyboard == null)
tcs.SetException(new ArgumentNullException());
else
{
EventHandler<object> onComplete = null;
onComplete = (s, e) => {
storyboard.Completed -= onComplete;
tcs.SetResult(true);
};
storyboard.Completed += onComplete;
storyboard.Begin();
}
return tcs.Task;
}
}
Essentially you're creating an extension method, which returns a Task object signalling the completion of the Storyboard. In this way, you get some nice fluid syntax like this:
//Start the storyboard and asynchronously await completion...
await myStoryboard.BeginAsync();
//Do my other stuff here, after the storyboard completes...
Using the Storyboard.Completed event should work for your purposes. The Storyboard.Completed event handler should fire on the UI thread, so you should not need to call Application.Current.Dispatcher.Invoke to fire off the second Storyboard.
There should be no implications if you call the original Storyboard.Begin using Application.Current.Dispatcher.Invoke. This won't launch the storyboard animation on a new thread. It will asynchronously invoke the animation on the main UI thread. Whether you call Begin on the UI thread yourself or whether you use Application.Current.Dispatcher.Invoke to do it, the final result should be the same. Your completed event handler will fire when the storyboard finishes, and you can perform your calculations and fire off the next storyboard.
See the following question for some discussion of storyboard having being used in the past as a timer because of the fact that it runs on the UI thread:
What is the point of using Storyboard as timer?
Also, this is probably overkill for the specific case you are describing, but if you need to orchestrate a bunch of sequential, asynchronous operations, you could use Reactive Extensions:
http://msdn.microsoft.com/en-us/data/gg577609.aspx
The following article includes a sequential storyboard example (though the article is old enough that the syntax has probably changed):
http://www.wintellect.com/cs/blogs/jlikness/archive/2010/08/22/coroutines-for-asynchronous-sequential-workflows-using-reactive-extensions-rx.aspx

WPF Best point to update a progress bar from BackgroundWorker

I have a task that takes a long time to execute. In order to inform the user of the progress, I have a progress bar that I update inside DoWork.
Can anybody tell me if this is the best way to update the progress bar? I have heard that there is a ReportProgress event handler but I am confused because I'm unsure of the purpose of ReportProgress.
Since the Background worker works in a separate thread, you'll run into problems if you try to access UI objects. Calling the ReportProgress method on the worker from inside the DoWork handler raises the ProgressChanged event. That event should be handled in the UI thread so as to easily access the control.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWorkHandler;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (s, e) =>
{ myProgressBar.Value = e.ProgressPercentage; };
worker.RunWorkerAsync();
...
public void DoWorkHandler(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (working)
{
// Do Stuff
worker.ReportProgress(progressPercentage);
}
}
The ProgressChanged event is what you are looking for. However, make sure you create the BackgroundWorker like below so it actually raises this event when ReportProgress is called.
BackgroundWorker bw = new BackgroundWorker() { WorkerReportsProgress = true };
bw.ProgressChanged += ... ;
ReportProgress is what you would use to update the progress of your task, including things like the UI--in your case, a proggress bar.
You should check out the MSDN docs, located here.
basically, you create a handler for the ReportProgress event, then in your DoWorkEventHandler, you call the ReportProgress like so:
worker.ReportProgress((i * 10));

WPF How to stop animation from a thread in background worker

I have a task that takes a long time. I do it with a background worker thread and before start it, since Do_Work I begin an animation over a label and when task finishes, I stop it in RunWorkerCompleted but I received an error because I try to begin/stop animation in the background thread that is not the owner. How can I do this, I mean to begin/stop animation in the background worker?
thanks!
You should start the animation before starting the BackgroundWorker, not in the DoWork event. That way, you will be able to stop it from the RunWorkerCompleted event.
You need to use the Dispatcher.BeginInvoke method, on the control which is doing the animation.
You can also call the stop animation on the UI thread using something like the following:
private void OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
/* If not operating on the main UI thread, call this method again on the App dispatcher's thread */
if (App.Current != null && App.Current.Dispatcher.Thread != Thread.CurrentThread)
{
App.Current.Dispatcher.Invoke(new RunWorkerCompletedEventHandler(OnRunWorkerCompleted), new object[] { sender, e});
return;
}
// Do stuff to the UI here
}

How to remove all the associated in built events of a control in WPF?

How to remove all the associated in built events of a control in WPF?
There is no easy way to remove all events queued on the Dispatcher. Even if there were, you wouldn't want to do so because it would break many WPF controls that rely on background events to update their data structures and UI.
However, there is an easy way to discard selected input events from the queue, such as keyboard, mouse and stylus events:
Create a "FlushInputQueue" method that registers an event handler with InputManager.PreprocessInput, invokes a DispatcherOperation at Input priority, then removes the event handler.
When the PreprocessInput event fires, check the input message and set the Handled flag to true if you want to discard it.
Here is some code to get you started:
public void FlushInputQueue()
{
PreProcessInputEvent handler = (obj, e) =>
{
if(ShouldFlushEvent(e.StagingItem.Input))
e.StagingItem.Input.Handled = true;
};
InputManager.PreProcessInput += handler;
Dispatcher.Invoke(DispatcherPriority.Input, new Action(() => {}));
InputManager.PreProcessInput -= handler;
}
private bool ShouldFlushEvent(InputEventArgs e)
{
// Example only:
return e is MouseEventArgs || e is KeyboardEventArgs || e is StylusEventArgs;
}
The ShouldFlushEvent method should probably be customized for your particular scenario to avoid throwing out events that should be kept.
One last thought: Have you considered doing your long-running operation on a background thread so the UI remains responsive? Many times this is a better solution than locking the UI when an item is clicked on, and removes any reason for wanting to flush the queue.

Resources