in WPF application I load a list of business objects by WCF to a listbox.
I want to load it in another thread and display a progressbar window.
But how? I need to call WCF service in the second thread and return its return value to the first (UI) thread. And this is the point I don't know. How to return?
Or what should be the correct workflow of calling for data at background and displaying of progress?
Now I:
- show the progress window
- create a new thread and call the WCF service
- return values <-- I don't know
- close window
But - is this workflow right?
I don't want to use a backgroundworker because I can call many different WCF services, not only one I could write into the DoWork method.
I have a WCFClient class in which I call all services I need. Here is a one of the methods (all methods are same only calls different services):
public class Client
{
public List<BusinessDto> GetBusinesses(int userID)
{
OnConnecting();
ServiceClient client = null;
BusinessDto[] dtos = null;
try
{
client = new ServiceClient();
dtos = client.GetBusinesses(userID);
}
catch
{
MessageBox.Show(Properties.Resources.ConnectionNotSucessful, Properties.Resources.ApplicationName, MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
if (client != null) client.Close();
OnClosing();
}
return dtos.ToList();
}
}
I'm catching an Onconnecting and OnClosing events of WCFClient and opening and closing a new window with progressbar.
But I do not call WCF services in a new thread, because I don't know how.
Thanks, I'm trying do that unsuccessfuly for a two days.
I don't want to use a backgroundworker because I can call many different WCF services, not only one I could write into the DoWork method.
Well, first, you can decide which of many DoWork methods you want to call at the time you prepare the BackgroundWorker. But you can also (and this is probably more maintainable) write a DoWork method of arbitrary complexity. You can write a DoWork method that takes an argument of type Client, and have it call a member method on that object, for instance. There's absolutely nothing limiting about this method.
The way I'd implement a progress bar window:
Implement a Task class that exposes three methods: SetUp, Execute, and TearDown, as well as a Status property, which is a struct containing int PercentComplete and string Message. Implement INotifyPropertyChanged.
Implement a protected UpdateStatus method that updates Status and raises PropertyChanged.
Build a modal window that implements a ShowDialog(Task t) method. In that method, call t.SetUp(), then create a BackgroundWorker.
Handle t.PropertyChanged and have the handler raise the BackgroundWorker's ProgressChanged event.
Have the BackgroundWorker's ProgressChanged event handler use t.Status to update the UI,
Have the BackgroundWorker's DoWork event handler call t.Execute().
Have its its RunWorkerCompleted event handler both handle exceptions (do not neglect this!) and call t.TearDown().
Build and test Task subclasses as needed.
Whenever you need to display a progress bar window, instantiate the appropriate Task, set whatever properties it needs, and then call ProgressBarWindow.ShowDialog(t). This will display the window and block and wait while the background process runs, updating the UI as it goes; it will return after t.TearDown() gets called.
BackgroundWorker is your friend. It does the thread marshalling for you, leaving you to worry about only doing the actual work.
Related
I need help understanding why following Test deadlocks? I suspect it has something to do with WindowsFormsSynchronizationContext that is set as Current SyncronizationContext during WinForm control creation.
[TestMethod]
public async Task myTest()
{
//During this winForms control creation, WindowsFormsSynchronizationContext is set as Current SyncronizationContext
new SomeWinformControl();
//This statement deadlocks
await Task.Run(() => { });
}
(MSTest using .NET 4.5.2)
Here is more context to #HansPassant's answer:
It has everything to do with Application.Run(), invariably missing in
a unit test. It is the dispatcher loop that is implemented by Run()
that keeps async code going.
From https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
Your user interface also has a scheduler: the message pump. A
dedicated thread sits in a loop, monitoring a queue of messages and
processing each; that loop typically processes messages like mouse
events or keyboard events or paint events, but in many frameworks you
can also explicitly hand it work to do, e.g. the Control.BeginInvoke
method in Windows Forms, or the Dispatcher.BeginInvoke method in WPF.
I want to render a chart with the DevExpress ChartControl via the WiForm DrawToBitmap() function on a separate thread.
I try something like:
Form yourForm;
Thread thread = new Thread( () =>
{
yourForm = new HiddenForm();
Application.Run(yourForm);
});
thread.ApartmentState = ApartmentState.STA;
thread.Start();
yourForm.Invoke(chartRenderingFunction)
And simple make sure the Hidden never actually gets displayed. However, I don't need that hidden form, and there is a parameterless form of Application.Run(). However, if I run that, it doesn't return. So my question is once I call Application.Run() inside a thread, how do I inject code in it?
Well, you actually really do need that hidden window. The only way to get code to run on that thread. Somebody must call PostMessage() and that requires a window handle. Your Invoke() call makes that call. You really should use BeginInvoke() instead, there's no point in starting a thread if you are going to wait for the call to complete.
Using Application.Run(yourForm) is going to make the window visible. You can stop it from becoming visible by overriding the SetVisibleCore() method in your HiddenForm class:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
CreateHandle();
value = false;
ThreadReady.Set();
}
base.SetVisibleCore(value);
}
The CreateHandle() call is necessary to make sure that the window is created so it can process the PostMessage() notifications. Also note the added AutoResetEvent (ThreadReady), you are going to have to call ThreadReady.WaitOne() after calling the thread's Start() method to ensure that your BeginInvoke() call is going to work. Dispose the form to get the thread to exit or call Application.Exit().
Last but not least, be very careful with using non-trivial controls on that thread. A chart control certainly is not indicated. You'll have long-lasting problems if that control uses the SystemEvents class for example. Your worker thread will get it to raise events on that worker thread. But it won't be around anymore after the chart is printed. You'll now get the events fired on an arbitrary threadpool thread, very nasty. A deadlock is a common mishap, particularly apt to trigger when locking the workstation.
I am looking into adding cancellation support to awaitable extension methods in the AsyncUI and WinRT XAML Toolkit libraries. It seems like the base Task class does not have a built-in Cancel() method or event and relies on cancellation tokens that my tasks would need to check for periodically. I think does not make sense in my UI scenarios, since my tasks are generated using the TaskCompletionSource and I would like to cancel the tasks on the UI thread in response to events instead of running a loop on a thread pool thread and checking for a token.
My tasks currently complete when a UI event happens - like a Storyboard completing or a button being clicked, so if I want to support cancellation - I need to respond to a cancellation request by unsubscribing from events and doing other cleanup like stopping an animation .
I am thinking of creating some sort of CancellableUITask base class instead of using the TaskCompletionSource, so I could expose a Cancel() method that the consumer of my task could call (e.g. to stop an awaited animation in response to a button click) and something like a virtual OnCancellationRequested() method that my storyboard awaiter task could override to perform cleanup.
Does it make sense? What would be the best way to accomplish what I am describing here?
Your tasks would not need to check periodically for cancellation - that is just the most common way of doing things. If your tasks are event-driven, then you can register a handler against the CancellationToken that will be called when it is cancelled. See CancellationToken.Register.
So your code might look something like this:
public Task DoSomethingAsync(CancellationToken cancellationToken = default(CancellationToken))
{
var tcs = new TaskCompletionSource();
if (cancellationToken.CanBeCanceled)
{
// register for notification of cancellation
cancellationToken.Register(...);
}
// set up other handlers and what-not
return tcs.Task;
}
Hi,
I have a winform application that is hosting a WCF Service(NamedPipes). When reciving a call a event will be triggered and then a form will be created and opened. The problem is that I get the followin exception
ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
When creating a System.Windows.Forms.WebBrowser in the winforms InitializeComponent method?
I Supose that another thread is running the even(working thread), how can I get the main thread to run the event?
I do not have any winform open at the time so I canĀ“t use InvokeRequired.
BestRegards
Edit1 : Pleas not that I am using
[STAThread]
public static void Main(string[] args)
{
Application.Run(_instance);
}
These kind of calls are made on thread pool threads. They are not suitable to display any UI. You'll need to create your own thread of the right flavor:
var t = new Thread(() => {
Application.Run(new Form1());
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
There are other practical problems you'll be battling with this, you can't just pop up a window without the user participating. Typical mishaps are the user accidentally closing it without even seeing it or the window disappearing behind the window that the user is working with. If you already have a user interface then be sure to use Control.BeginInvoke() to let the main thread display the window. Consider the soft touch with a NotifyIcon, displaying a balloon in the tray notification area to alert the user.
That WCF call is most likely coming in on a thread other than the main UI thread. All UI controls including ActiveX ones must be created and accessed from the UI thread and only the UI thread. The error you are getting is indicating that the creating thread is not even in a Single Thread Apartment (STA) which is also a requirement.
To get the code executing on the main UI thread use the Control.Invoke method. It will marshal the execution of a delegate onto the thread hosting the target Control or Form.
If you do not have a reference to a Control or Form immediately available then you will need to create one. You may have to create a thread that runs a message loop as well. This can be done with Application.Run. It is simple enough to create a hidden Form that could be used to call Invoke.
Here is what it might look like.
void SomeMethodExecutingOnThreadPool()
{
var form = null;
var mre = new ManualResetEvent(false);
// Create the UI thread.
new Thread(
() =>
{
form = new Form();
form.Load +=
(sender, args) =>
{
mre.Set();
}
Application.Run(form);
}).Start();
// Wait for the UI thread to initialize.
mre.WaitOne();
// You can now call Invoke.
form.Invoke(/* ... */);
}
My solution is to create a dummy winform on startup and when I need the main UI thread I will use invoke on this dummyform.
It will use some more resourse but I dont see a simpler way of doing it.
What solutions do I have if I want to prevent the UI from freezing while I deserialize a large number of UI elements in WPF? I'm getting errors complainig that the objects belong on the UI Thread when I'm trying to load them in another thread. So, what options do I have to prevent the Vista "Program not responding" error while I'm loading my UI data? Can I rely on a single-threaded solution, or am I missing something regarding perhaps multiple UI Threads?
If you only use a single thread then the UI will freeze while you do any amount of processing.
If you use a BackgroundWorker thread you'll have more control over what happens & when.
To update the UI you need to use Dispatcher.Invoke from your background thread to marshal the call across the thread boundary.
Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => this.TextBlock.Text = "Processing");
You can turn the flow of control on its head using DispatcherFrames, allowing a deserialization to proceed on the UI thread in the background.
First you need a way to get control periodically during deserialization. No matter what deserializer you are using, it will have to call property sets on your objects, so you can usually add code to the property setters. Alternatively you could modify the deserializer. In any case, make sure your code is called frequently enough
Each time you receive control, all you need to do is:
Create a DispatcherFrame
Queue an event to the dispatcher using BeginInvoke that sets Continue=false on the frame
Use PushFrame to start the frame running on the Dispatcher
In addition, when calling the deserializer itself make sure you do it from Dispatcher.BeginInvoke, or that your calling code doesn't hold any locks etc.
Here's how it would look:
public partial class MyWindow
{
SomeDeserializer _deserializer = new SomeDeserializer();
byte[] _sourceData;
object _deserializedObject;
...
void LoadButton_Click(...)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
_deserializedObject = _deserializer.DeserializeObject(_sourceData);
}));
}
}
public class OneOfTheObjectsBeingDeserializedFrequently
{
...
public string SomePropertyThatIsFrequentlySet
{
get { ... }
set { ...; BackgroundThreadingSolution.DoEvents(); }
}
}
public class BackgroundThreadingSolution
{
[ThreadLocal]
static DateTime _nextDispatchTime;
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
frame.Continue = false;
}));
Dispatcher.PushFrame(frame);
}
}
Checking DateTime.Now in DoEvents() isn't actually required for this technique to work, but will improve performance if SomeProperty is set very frequently during deserialization.
Edit: Right after I wrote this I realized there is an easier way to implement the DoEvents method. Instead of using DispatcherFrame, simply use Dispatcher.Invoke with an empty action:
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
}
Here is a wonderful blog posting from Dwane Need that discusses all the available options for working with UI elements amongst multiple threads.
You really haven't given enough detail to give a good prescription. For example, why are you creating UI elements yourself at all instead of using databinding? You might have a good reason, but without more details it's hard to give good advice. As another example of detail that would be useful, are you looking to build complex deeply nested control hierarchies for each piece of data or do you just need to draw a simple shape?
I had a similar problem with my panel which was moving its items. The UI was freezing because I was using a DispatcherTimer at priority Loaded. The problem is gone as soon as I changed it to DispatcherPriority.Input.
You can still make your long processing in a separate thread, but when finished you have to synchronize with the UI thread by calling Dispatcher.BeginInvoke(your_UI_action_here)
Recommendations from the OldNewThing blog.
It is best if you do go the threaded route, to have one GUI thread and spawn your work load off to another thread that when finishes reports back to the main GUI thread that its done. The reason for this is because you will not get into thread issues with your GUI interface.
So One GUI Thread
Many worker threads that do the work.
If any of your threads do hang the user is in direct control over your application can can close down the thread without effecting his experience with the application interface. This will make him happy because your user will feel in control other than him constantly click THAT STOP BUTTON AND IT WONT STOP SEARCHING.
Try freezing your UIElements. Frozen objects can be passed between threads without encountering an InvalidOperationException, so you deserialize them & freeze them on a background thread before using them on your UI thread.
Alternatively, consider dispatching the individual deserializations back to the UI thread at background priority. This isn't optimal, since the UI thread still has to do all of the work to deserialize these objects and there's some overhead added by dispatching them as individual tasks, but at least you won't block the UI - higher priority events like input will be able to be interspersed with your lower priority deserialization work.