How to raise a UI event from a background Thread - wpf

I've a WebCamCapture class that inherits from UserControl class and I start it in a separate thread like this
ThreadStart webCamThreadStart = () =>
{
webcam = new WebCamCapture();
webcam.FrameNumber = ((ulong)(0ul));
webcam.TimeToCapture_milliseconds = FrameNumber;
webcam.ImageCaptured += new WebCamCapture.WebCamEventHandler(webcam_ImageCaptured);
Start();
};
Thread threadnameThread = new Thread(webCamThreadStart) { IsBackground = true };
threadnameThread.Start();
The web cam starts but it never raises ImageCaptured event.
When I run the code under a Dispatcher BeginInvoke, the event gets fired,
System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
//above code
}));
But thats not my purpose, because this way the UI slows down. I want to run the webcam in a separate thread, this was my original question
[Text Input very slow in WPF Application
My question is how we can raise a UI event from a background thread.
Thanks.

Related

Creating a new UI thread while calling methods on the original thread

I am in a similar situation as this poster (What's the best way to create a new UI thread and call back methods on the original thread?)
I have an API object which I would like to perform lengthy calculations on, however any properties or methods of this object must be accessed on the current thread (which is the UI thread) or else I get "Accessing disposed TPS.NET DataObject" exceptions
Is there an elegant way of accomplishing this using F# async workflows or will I be stuck managing thread dispatchers as in his solution.
For reference, here is his solution to the issue:
public class Plugin
{
public void Run(Context context)
{
// Get the application's UI thread dispatcher
var dispatcher = Dispatcher.CurrentDispatcher;
// Create a dispatcher frame to push later
var frame = new DispatcherFrame();
// Create a new UI thread (using an StaTaskScheduler)
Task.Factory.StartNew(async () =>
{
var window = new MyWindow();
// The Click event handler now uses the original
// thread's dispatcher to run the slow method
window.MyButton.Click += async (o, e) =>
await dispatcher.InvokeAsync(() => context.SlowMethod());
window.ShowDialog();
// When the window is closed, end the dispatcher frame
frame.Continue = false;
}, CancellationToken.None, TaskCreationOptions.None, new StaTaskScheduler(1));
// Prevent exiting this Run method until the frame is done
Dispatcher.PushFrame(frame);
}
}
Without know the exact details I would suggest having the Click handler on the main thread and do the following:
Copy any data needed off the UI into an F# record and passes this into an async workflow
Return immediately after putting the UI into a 'loading' state
The following code is untested but should put you on the right track:
//Get the context of the UI
let context = System.Threading.SynchronizationContext.Current
//Gather any needed data from the UI into immutable F# records
//Put the UI into a 'loading' state
async {
// Do work on a different thread
do! Async.Sleep 1000
let x = 1
// Switching back to the UI
do! Async.SwitchToContext context
//Update UI
return ()
}
|> Async.Start
This link should also provide some useful information http://tomasp.net/blog/async-non-blocking-gui.aspx/
EDIT:
If you need to go back and forth between the UI thread and a background thread to gather additional information in the async workflow you can make alternating calls between do! Async.SwitchToThreadPool() and do! Async.SwitchToContext context

Multiwindow behaviour and dispatcher in WPF

I have app with 2 windows.
1st LoginWindow used to authentificate user and launch main app. I use thread and run dispatcher for that:
private bool EndTrigger = false;
/.../
Thread thread = new Thread(() =>
{
MainWindow T_window = new MainWindow(t_data);
T_window.WindowState = WindowState.Maximized;
T_window.Show();
EndTrigger = true;
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
After that LoginWindow is closed. I used function that checks if MainWindow is ready and Timer like this:
Timer LoginWinClose = new Timer(new TimerCallback(IfLoginWinCanBeClosed), null, 2000, 1000);
and
public void IfLoginWinCanBeClosed(Object stateInfo)
{
if (EndTrigger)
{
this.Dispatcher.Invoke(new Action(delegate
{
this.Close();
}));
}
}
It works as it should: LoginWindow disapper, MainWidow appear and everything works.
But when I tryed to create one more window in MainWindow I get Exception that tells me: Application is shutting down.
It looks like closing LoginWindow leads to attemp of closing application, but if I close any other window (for example MainWindow), I still can create one more from LoginWondow without any error.
Currently I solve this by by changing
this.Close();
to
this.Visibility = Visibility.Collapsed;
It means that LoginWindow will continue to run all the time. If there any another solution?
Thanks to #Sham I understand where is the mistake!
Code, where new window is created located in separate thread (this is because login check operations run in the separated thread to avoid hanging LoginWindow), so I Create and run new window with separate dispatcher in that Thread, instead of main UI thread.
So, the solution is quite easy. Just need to make a little modification:
Thread thread = new Thread(() =>
{
this.Dispatcher.Invoke(new Action(delegate
{
AdminWindow T_window = new AdminWindow(t_data);
T_window.WindowState = WindowState.Maximized;
T_window.Show();
t_data.Link_auth_win.EndTrigger = true;
System.Windows.Threading.Dispatcher.Run();
}));
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

WPF - Task.Run(() => window.ShowDialog) fails

I have to implement busy indication and progress reporting. The constraint is, that I have to use the provided Control Library, which offers a Window for progress reporting.
The following code works fine, but does not block the UI, which in some times is required.
private async void StartLongRunningTask2Sync() {
var wndHandle = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
if (wndHandle == null)
{
return;
}
IntPtr windowHandle = new WindowInteropHelper(wndHandle).Handle;
var progressWindow = new ProgressBarCustomized(windowHandle)
{
Value = 0, CanCancel = true, CanRetry = false, Thumbnail = null, IsIndeterminate = true
};
progressWindow.Show();
await Task.Run(() => this.longRunningTaskComponent.DoLongRunningTask(this.taskIterations, this.iterationSleepTime));
progressWindow.Close();
}
The following code, which blocks the UI would work so far that the dialog is opened, but the long running task never gets executed until the dialog is closed again:
private async void StartLongRunningTask2Sync() {
var wndHandle = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
if (wndHandle == null)
{
return;
}
IntPtr windowHandle = new WindowInteropHelper(wndHandle).Handle;
var progressWindow = new ProgressBarCustomized(windowHandle)
{
Value = 0, CanCancel = true, CanRetry = false, Thumbnail = null, IsIndeterminate = true
};
progressWindow.ShowDialog();
await Task.Run(() => this.longRunningTaskComponent.DoLongRunningTask(this.taskIterations, this.iterationSleepTime));
progressWindow.Close();
}
So I tried with this approach:
private async void StartLongRunningTask2Sync() {
var wndHandle = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
if (wndHandle == null)
{
return;
}
IntPtr windowHandle = new WindowInteropHelper(wndHandle).Handle;
var progressWindow = new ProgressBarCustomized(windowHandle)
{
Value = 0, CanCancel = true, CanRetry = false, Thumbnail = null, IsIndeterminate = true
};
Task.Run(() => progressWindow.ShowDialog());
await Task.Run(() => this.longRunningTaskComponent.DoLongRunningTask(this.taskIterations, this.iterationSleepTime));
progressWindow.Close();
}
When doing this, I get the following error:
The calling thread cannot access this object because a different thread owns it.
After investigation of the custom progress window I found out, that the call "base.ShowDialog()" throws this error.
Is there a way to do what I like or do I have to do this with a totally different approach?
Best regards
UPDATE:
Yes, I have searched for this error and yes, I have tried several approaches with Dispatcher.Invoke() etc...
So the "real" question:
How can I show a blocking Window when a long running task is running and closing it after the long running task has finished and, eventually, inform the window about the progress of the action. The solution should (preferably) work with the MVVM pattern and not rely on (too much) code behind.
So the "real" question: How can I show a blocking Window when a long running task is running and closing it after the long running task has finished and, eventually, inform the window about the progress of the action.
You've already got most of the pieces; you just need to put them together.
How can I show a blocking Window
All UI should go on a single GUI thread. This isn't strictly necessary, but it's a great simplifier and works for the vast, vast majority of applications. A "blocking Window" is known in the UI world as a "modal dialog", and you show one by calling ShowDialog.
// Start the long-running operation
var task = LongRunningOperationAsync();
// Show the dialog
progressWindow.ShowDialog();
// Retrieve results / propagate exceptions
var results = await task;
closing it after the long running task has finished
For this, you need to wire up the completion of the task to close the window. This is pretty straightforward to do using async/await:
async Task DoOperationAsync(ProgressWindow progressWindow)
{
try
{
await LongRunningOperationAsync();
}
finally
{
progressWindow.Close();
}
}
// Start the long-running operation
var task = DoOperationAsync(progressWindow);
// Show the dialog
progressWindow.ShowDialog();
// Retrieve results / propagate exceptions
var results = await task;
inform the window about the progress of the action
Assuming your operation is using the standard IProgress<T> interface for reporting progress:
async Task DoOperationAsync(Window progressWindow, IProgress<int> progress)
{
try
{
await LongRunningOperationAsync(progress);
}
finally
{
progressWindow.Close();
}
}
var progressWindowVM = ...;
var progress = new Progress<int>(value =>
{
progressWindowVM.Progress = value;
});
var task = DoOperationAsync(progressWindow, progress);
progressWindow.ShowDialog();
var results = await task;
Another common use case to consider is the cancelling of the operation if the user closes the progress dialog themselves. Again, this is straightfoward if your operation is already using the standard CancellationToken:
async Task DoOperationAsync(Window progressWindow, CancellationToken token, IProgress<int> progress)
{
try
{
await LongRunningOperationAsync(token, progress);
}
catch (OperationCanceledException) { }
finally
{
progressWindow.Close();
}
}
var progressWindowVM = ...;
var progress = new Progress<int>(value =>
{
progressWindowVM.Progress = value;
});
var cts = new CancellationTokenSource();
progressWindow.Closed += (_, __) => cts.Cancel();
var task = DoOperationAsync(progressWindow, cts.Token, progress);
progressWindow.ShowDialog();
var results = await task;
The solution should (preferably) work with the MVVM pattern and not rely on (too much) code behind.
MVVM works great within a single window. As soon as you start trying to data-bind window-level actions and attributes, a lot of it falls apart. This is not due to MVVM being a poor pattern, but rather just that a lot of MVVM frameworks do not handle this well.
The example code above only uses data binding to report progress to the progress dialog. If your MVVM framework can data-bind the showing/hiding of a modal window, then you could use my NotifyTaskCompletion type to drive that. Also, some frameworks have a more elegant (MVVM) way to handle Window.Closed, but the details depend on your framework.
The calling thread cannot access this object because a different thread owns it.
This is a very common error and if you had searched online, you would have found a very simple explanation.
You cannot manipulate UI objects on a non UI thread.
The solution is simple. Don't attempt to open a dialog Window on a non UI thread.
Perhaps if you can clarify what your actual question is (by editing your question, not by commenting), then I can help further?
I think I have found a nearly working solution here:
Create MVVM Background Tasks with Progress Reporting
The only thing I have to get around with is the deactivation of the main window when showing the dialog.

System.Windows.Controls.WebBrowser, System.Windows.Threading.Dispatcher, and a windows service

I'm trying to render some html content to a bitmap in a Windows Service.
I'm using System.Windows.Controls.WebBrowser to perform the render. The basic rendering setup works as a standalone process with a WPF window hosting the control, but as a service, at least I'm not getting the LoadCompleted events to fire.
I know that I at least need a Dispatcher or other message pump looping for this WPF control. Perhaps I'm doing it right and there are just additional tricks/incompatibilities necessary for the WebBrowser control. Here's what I've got:
I believe only one Dispatcher needs to be running and that it can run for the life of the service. I believe the Dispatcher.Run() is the actual loop itself and thus needs it's own thread which it can otherwise block. And that thread needs to be [STAThread] in this scenario. Therefore, in a relevant static constructor, I have the following:
var thread = new Thread(() =>
{
dispatcher = Dispatcher.CurrentDispatcher;
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
where dispatcher is a static field. Again, I think there can only be one but I'm not sure if I'm supposed to be able use Dispatcher.CurrentDispatcher() from anywhere instead and get the right reference.
The rendering operation is as follows. I create, navigate, and dispose of the WebBrowser on dispatcher's thread, but event handler assignments and mres.Wait I think may all happen on the render request-handling operation. I had gotten The calling thread cannot access this object because a different thread owns it but now with this setup I don't.
WebBrowser wb = null;
var mres = new ManualResetEventSlim();
try
{
dispatcher.Invoke(() => { wb = new WebBrowser(); });
wb.LoadCompleted += (s, e) =>
{
// Not firing
};
try
{
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms, Encoding.Unicode))
{
sw.Write(html);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
// GO!
dispatcher.Invoke(() =>
{
try
{
wb.NavigateToStream(ms);
Debug.Assert(Dispatcher.FromThread(Thread.CurrentThread) != null);
}
catch (Exception ex)
{
// log
}
});
if (!mres.Wait(15 * 1000)) throw new TimeoutException();
}
}
catch (Exception ex)
{
// log
}
}
finally
{
dispatcher.Invoke(() => { if (wb != null) wb.Dispose(); });
}
When I run this, I get my timeout exception every time since the LoadCompleted never fires. I've tried to verify that the dispatcher is running and pumping properly. Not sure how to do that, but I hooked a few of the dispatcher's events from the static constructor and I get some printouts from that, so I think it's working.
The code does get to a wb.NavigateToStream(ms); breakpoint.
Is this bad application of Dispatcher? Is the non-firing of wb.LoadCompleted due to something else?
Thanks!
Here's a modified version of your code which works as a console app. A few points:
You need a parent window for WPF WebBrowser. It may be a hidden window like below, but it has to be physically created (i.e. have a live HWND handle). Otherwise, WB never finishes loading the document (wb.Document.readyState == "interactive"), and LoadCompleted never gets fired. I was not aware of such behavior and it is different from the WinForms version of WebBrowser control. May I ask why you picked WPF for this kind of project?
You do need to add the wb.LoadCompleted event handler on the same thread the WB control was created (the dispatcher's thread here). Internally, WPF WebBrowser is just a wrapper around apartment-threaded WebBrowser ActiveX control, which exposes its events via IConnectionPointContainer interface. The rule is, all calls to an apartment-threaded COM object must be made on (or proxied to) the thread the object was originally created on, because that's what such kind of objects expect. In that sense, IConnectionPointContainer methods are no different to other methods of WB.
A minor one, StreamWriter automatically closes the stream it's initialized with (unless explicitly told to not do so in the constructor), so there is no need to for wrapping the stream with using.
The code is ready to compile and run (it requires some extra assembly references: PresentationFramework, WindowsBase, System.Windows, System.Windows.Forms, Microsoft.mshtml).
using System;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Controls;
using System.IO;
using System.Runtime.InteropServices;
using mshtml;
namespace ConsoleWpfApp
{
class Program
{
static Dispatcher dispatcher = null;
static ManualResetEventSlim dispatcherReady = new ManualResetEventSlim();
static void StartUIThread()
{
var thread = new Thread(() =>
{
Debug.Print("UI Thread: {0}", Thread.CurrentThread.ManagedThreadId);
try
{
dispatcher = Dispatcher.CurrentDispatcher;
dispatcherReady.Set();
Dispatcher.Run();
}
catch (Exception ex)
{
Debug.Print("UI Thread exception: {0}", ex.ToString());
}
Debug.Print("UI Thread exits");
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
static void DoWork()
{
Debug.Print("Worker Thread: {0}", Thread.CurrentThread.ManagedThreadId);
dispatcherReady.Wait(); // wait for the UI tread to initialize
var mres = new ManualResetEventSlim();
WebBrowser wb = null;
Window window = null;
try
{
var ms = new MemoryStream();
using (var sw = new StreamWriter(ms, Encoding.Unicode)) // StreamWriter automatically closes the steam
{
sw.Write("<b>Hello, World!</b>");
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
// GO!
dispatcher.Invoke(() => // could do InvokeAsync here as then we wait anyway
{
Debug.Print("Invoke Thread: {0}", Thread.CurrentThread.ManagedThreadId);
// create a hidden window with WB
window = new Window()
{
Width = 0,
Height = 0,
Visibility = System.Windows.Visibility.Hidden,
WindowStyle = WindowStyle.None,
ShowInTaskbar = false,
ShowActivated = false
};
window.Content = wb = new WebBrowser();
window.Show();
// navigate
wb.LoadCompleted += (s, e) =>
{
Debug.Print("wb.LoadCompleted fired;");
mres.Set(); // singal to the Worker thread
};
wb.NavigateToStream(ms);
});
// wait for LoadCompleted
if (!mres.Wait(5 * 1000))
throw new TimeoutException();
dispatcher.Invoke(() =>
{
// Show the HTML
Console.WriteLine(((HTMLDocument)wb.Document).documentElement.outerHTML);
});
}
}
catch (Exception ex)
{
Debug.Print(ex.ToString());
}
finally
{
dispatcher.Invoke(() =>
{
if (window != null)
window.Close();
if (wb != null)
wb.Dispose();
});
}
}
static void Main(string[] args)
{
StartUIThread();
DoWork();
dispatcher.InvokeShutdown(); // shutdown UI thread
Console.WriteLine("Work done, hit enter to exit");
Console.ReadLine();
}
}
}
Maybe the Webbrowser Control needs Desktop Interaction for rendering the content:
My feeling say that using WPF controls and in particular particulary the Webbrowser-Control (=Wrapper around the IE ActiveX control) isn't the best idea.. There are other rendering engines that might be better suited for this task: Use chrome as browser in C#?

The calling thread cannot access this object because a different thread owns it

i have a problem whenever i Refresh the prograss bar i get the error The calling thread cannot access this object because a different thread owns it
how can i remove it
shashank
backgroundWorker12 = new BackgroundWorker();
timer1.Enabled = true;
//cancel any async processes running for the background worker
//backgroundWorker1.CancelAsync();
backgroundWorker12.DoWork += (s, args) =>
{
BackgroundWorker worker2 = s as BackgroundWorker;
worker2.WorkerReportsProgress = true;
float percentageDone = 20f;
//check if the user status and update the password in xml
CheckUseridPwd();
//call the function to sync the wall chart data
//call the function to sync event relate data
percentageDone = 100f;
ValidateLogin2(txtUserID.Text.Trim(), txtPassword.Password.Trim(), -1);
worker2.ReportProgress((int)percentageDone);
};`
This bit looks like it's using UI controls from the wrong thread:
ValidateLogin2(txtUserID.Text.Trim(), txtPassword.Password.Trim(), -1);
I suggest you capture the user and password in local string variables above the code which adds the event handler - you can use those captured variables within your delegate. That way everything should be on the right thread:
backgroundWorker12 = new BackgroundWorker();
timer1.Enabled = true;
string user = txtUserID.Text.Trim();
string password = txtPassword.Password.Trim();
backgroundWorker12.DoWork += (s, args) =>
{
// ... same code as before up to here
ValidateLogin2(user, password, -1);
worker2.ReportProgress((int)percentageDone);
};
See if you can use the RunWorkerCompleted event of the BackgroundWorker, since you're accessing the UI only after progress is 100% i.e. done..
Then you wouldn't have to worry about thread-affinity of WPF UI controls - since the event handler is invoked again on the right/ UI Thread.
The other option (if you need to access the UI controls before the work is complete) is to cache the object
returned by Dispatcher.CurrentDispatcher on the UI Thread before the work starts and then use object.Invoke to marshal to the right thread from the thread pool thread that is executing your DoWork handler. See some code here.
Have you tried invoking ValidateLogin2
you can either do it directly from your code shown, or in ValidateLogin2 check if the method itself requires invoking. If not, go ahead and validate, but if it does, then have it invoke itself
void ValidateLogin2(...)
{
if (this.InvokeRequired)
{
//Invokes itself if required
BeginInvoke(new MethodInvoker(delegate(){ValidateLogin2(...);}));
}
else
{
//validate login here
}
}

Resources