ReactiveCommand in WPF/ReactiveUI app blocks UI thread - wpf

I am quite a beginner with ReactiveUI and have a strange behavior with a ReactiveCommand.
I want to query data from a database that currently does not support
asynchronous operations. Since we want to exchange the database in the
future with an asynchronous interface I want to write everything as
if the database already would allow async operations. As far as I understand
that would mean that I wrap my database calls at the lowest level in
a Task.
I have a button which is bound to a ReactiveCommand and the command
starts the database query. While the query lasts I want to show some
sort of animation.
The problem is that whatever I tried, the query blocks my UI thread.
Here is part of my code:
public ReactiveCommand<Unit, Unit> StartExportCommand { get; }
//The constructor of my view model
public ExportDataViewModel(IDataRepository dr)
{
this.dr = dr;
//...
StartExportCommand = ReactiveCommand.CreateFromTask(() => StartExport());
//...
}
private async Task StartExport()
{
try
{
Status = "Querying data from database...";
//Interestingly without this call the Status message would not even be shown!
//The delay seems to give the system the opportunity to at least update the
//label in the UI that is bound to "Status".
await Task.Delay(100);
//### This is the call that blocks the UI thread for several seconds ###
var result = await dr.GetValues();
//do something with result...
Status = "Successfully completed";
}
catch(Exception ex)
{
Status = "Failed!";
//do whatever else is necessary
}
}
//This is the GetValues method of the implementation of the IDataRepository.
//The dictionary maps measured values to measuring points but that should not matter here.
//ValuesDto is just some container for the values.
public Task<IDictionary<int, ValuesDto>> GetValues()
{
//...
return Task<IDictionary<int, ValuesDto>>.Factory.StartNew(() =>
{
//### here is where the blocking calls to the database
//### specific APIs take place
return result;
}, TaskCreationOptions.LongRunning);
}
I don't understand why this code is blocking the UI thread although I am wrapping
the long running query in a Task.
Is there something wrong with this pattern or should I go another way with Observables?
Edit 1
I am aware of the fact that async != threads. I thought, however, that Task with the TaskCreationOptions.LongRunning would make the blocking code run on a thread pool thread.
Edit 2
As recommended by Andy I set a breakpoint inside my task and had a look into the Debug Threads window. It tells me that Task is running on a worker thread. Still my UI is blocking.

Related

Freeze WPF UI - multi-threading in view model class

Hi I use WPF with Caliburn Micro and in view model class I need test connection to SQL database.
Here is method which I use for testing connection.
public bool CheckSqlServer(string sqlHost, int sqlPort)
{
try
{
IPHostEntry ipHost = Dns.Resolve(sqlHost);
IPAddress ipAddr = ipHost.AddressList[0];
var tcpCli = new TcpClient();
tcpCli.Connect(ipAddr, sqlPort);
tcpCli.Close();
return true;
}
catch
{
return false;
}
}
And I call this method in another thread
//IP is worng
if (Task<bool>.Factory.StartNew(()=>CheckSqlServer("10.10.10.20",1521)).Result)
{
Insert();
}
Problem is that UI of WPF still freeze I dont know why because I call this method in new thread not in UI thread.
In your if you call Result straight away. That makes the calling thread wait on the task in a blocking way.
You should work e.g. with ContinueWith on the Task. That will be called once the execution of the first task finished. Careful with SynchronizationContext, though!
Also, you shouldn't call TaskFactory etc. in another thread. The whole point of Task is to abstract parallelism away from using the 'low-level' threads.
Try to set the proxy to null, so that the default auto-discovery will be disabled.
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.proxy.aspx

Silverlight web service callback performance

I have a silverlight client that communicates with a web service on a server. It has a DoSomething method that does nothing and returns void.
On the client, I call the service and listen to when the response comes back:
proxy.OnDoSomethingCompleted+=OnDoSomethingCompleted;
t0 = Environment.TickCount;
proxy.DoSomethingAsync();
void DoSomething(..)
{
t1 = Environment.TickCount;
}
Network capture indicates the response is sent back within 2ms. However, OnDoSomethingCompleted is not called until 80ms later. Is there a way to change when the callback is executed?
Normally, OnDoSomethingCompleted() would be executed on the UI thread, i.e., behind the scenes, something is calling some code that (conceptually) looks a little like this:
Dispatcher.BeginInvoke(() => OnDoSomethingCompleted());
This means that OnDoSomethingCompleted() won't get executed until the UI thread decides to cooperate and run it. Most of the time that's fine, but there can be times when you want it to run faster. The basic approach is to use a thread pool to make the original call, which means that the response will get handled from the same thread pool (not necessarily ont he same thread). If you can do some real processing in this return method, and don't just automatically marshal it back onto the UI thread, this can speed up your processing somewhat.
Tomek (from the MS WCF team) gives a good example of how do this here:
http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html
It's also my understanding that the synchronization context for the WCF connection gets set when you first open it. This means that whatever thread the WCF connection is first opened on is the one that will handle all later calls. So in my own code, I do something like this:
// Spin up the connection on a new worker thread.
// According to Tomek, this will cause all WCF calls to be made from this thread.
ManualResetEvent resetEvent = new ManualResetEvent(false);
wcfWorkerThread = new Thread(new ThreadStart(() => InitializeNotificationClient(resetEvent)));
wcfWorkerThread.Name = "WcfWorkerThread";
wcfWorkerThread.Start();
resetEvent.WaitOne();
And then InitializeNotificationClient() looks something like this:
private void InitializeNotificationClient(ManualResetEvent resetEvent = null)
{
try
{
notificationClient = GetRoomServiceClient();
notificationClient.OpenAsync(callback);
notificationClient.InnerChannel.Faulted += new EventHandler(Channel_Faulted);
notificationClient.InnerChannel.Closed += new EventHandler(Channel_Closed);
}
finally
{
// Tell the waiting thread that we're ready.
if (resetEvent != null)
{
resetEvent.Set();
}
}
}

Calling a webservice synchronously from a Silverlight 3 application?

I am trying to reuse some .NET code that performs some calls to a data-access-layer type service. I have managed to package up both the input to the method and the output from the method, but unfortunately the service is called from inside code that I really don't want to rewrite in order to be asynchronous.
Unfortunately, the webservice code generated in Silverlight only produces asynchronous methods, so I was wondering if anyone had working code that managed to work around this?
Note: I don't need to execute the main code path here on the UI thread, but the code in question will expect that calls it makes to the data access layers are synchronous in nature, but the entire job can be mainly executing on a background thread.
I tried the recipe found here: The Easy Way To Synchronously Call WCF Services In Silverlight, but unfortunately it times out and never completes the call.
Or rather, what seems to happen is that the completed event handler is called, but only after the method returns. I am suspecting that the event handler is called from a dispatcher or similar, and since I'm blocking the main thread here, it never completes until the code is actually back into the GUI loop.
Or something like that.
Here's my own version that I wrote before I found the above recipe, but it suffers from the same problem:
public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
string securityToken = "DUMMYTOKEN";
string input = "DUMMYINPUT";
object result = null;
Exception resultException = null;
object evtLock = new object();
var evt = new System.Threading.ManualResetEvent(false);
try
{
var client = new MinGatServices.DataAccessLayerServiceSoapClient();
client.ExecuteRequestCompleted += (s, e) =>
{
resultException = e.Error;
result = e.Result;
lock (evtLock)
{
if (evt != null)
evt.Set();
}
};
client.ExecuteRequestAsync(securityToken, input);
try
{
var didComplete = evt.WaitOne(10000);
if (!didComplete)
throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
}
finally
{
client.CloseAsync();
}
}
finally
{
lock (evtLock)
{
evt.Close();
evt = null;
}
}
if (resultException != null)
throw resultException;
else
return result;
}
Basically, both recipes does this:
Set up a ManualResetEvent
Hook into the Completed event
The event handler grabs the result from the service call, and signals the event
The main thread now starts the web service call asynchronously
It then waits for the event to become signalled
However, the event handler is not called until the method above has returned, hence my code that checks for evt != null and such, to avoid TargetInvocationException from killing my program after the method has timed out.
Does anyone know:
... if it is possible at all in Silverlight 3
... what I have done wrong above?
I suspect that the MinGatServices thingy is trying to be helpful by ensuring the ExecuteRequestCompleted is dispatched on the main UI thread.
I also suspect that your code is already executing on the main UI thread which you have blocked. Never block the UI thread in Silverlight, if you need to block the UI use something like the BusyIndicator control.
The knee-jerk answer is "code asynchronously" but that doesn't satisfy your question's requirement.
One possible solution that may be less troublesome is to start the whole chunk of code from whatever user action invokes it on a different thread, using say the BackgroundWorker.
Of course the MinGatServices might be ensuring the callback occurs on the same thread that executed ExecuteRequestAsync in which case you'll need to get that to run on a different thread (jumping back to the UI thread would be acceptable):-
Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));

Updating a Progress Bar from Another Thread

I have a windows form on the main thread and another thread that does some calculations. I'd like to update the status bar on my form from the work being done in the other thread. What's the best way to do this?
So far everything I've tried just makes things run really slowly. I'm using Visual Studio 2005.
You can use the marshaling techniques like Control.Invoke to execute a delegate on the UI thread where UI elements can be safely manipulated, but that approach is not very good. Actually, it is a terrible approach if all you want to do is update simple progress information.
By far the best method for doing this is:
Have your worker thread publish progress information to a shared variable.
Have your UI thread poll for it via a System.Windows.Forms.Timers on an interval that works well for you.
Here is what it might look like.
public class Example : Form
{
private volatile int percentComplete = 0;
private void StartThreadButton_Click(object sender, EventArgs args)
{
StatusBarUpdateTimer.Enabled = true;
new Thread(
() =>
{
for (int i = 1; i <= 100; i++)
{
DoSomeWork();
percentComplete = i;
}
}).Start();
}
private void StatusBarUpdateTimer_Tick(object sender, EventArgs args)
{
yourStatusBarPanel.Text = percentComplete.ToString() + "%";
StatusBarUpdateTimer.Enabled = percentComplete < 100;
}
}
This works well because:
The percentComplete field is declared 'volatile' ensuring its value can be reliably read from multiple threads.
The UI thread gets to dictate when and how often the UI gets updated...the way it should be!
The worker thread does not have to wait for a response from the UI thread before it can proceed as would be the case with Invoke.
It breaks the tight coupling between the UI and worker threads that Invoke would impose.
It is more efficient...considerably.
You get more throughput on both the UI and worker threads.
There is no chance of saturating the UI message queue as could be the case with BeginInvoke.
You do not have to litter you code with Invoke calls everytime you need to update the UI from the worker thread.
Make sure that you only update the user interface from the main thread or else you will have problems. You can switch your thread context by calling Invoke. There's a good post here on that.
You can send messages to the main thread and get it to update the progress bar, although you then need to check for the messages. You could also do the same sort of thing as a polling function.

Update Label while processing in Windows Forms

What is the best way to update a label on a Windows Forms application while processing?
I have a loop that does some processing to files on the user's system when the user clicks a button.
foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
// Do processing
// Show progress bar
// Update Label on Form, "f.Name is done processing, now processing..."
}
What would be some sample code?
What exactly is this called? Is it threading or delegates?
A quick fix for you would be:
Label1.Text = f.Name + " is done processing, now processing...";
Label1.Refresh();
You really want to avoid DoEvents, otherwise you'll have problems if your user repeatedly presses buttons on your form.
You should be doing this on another thread, and then updating your UI thread from that thread. You are blocking further processing by performing this work on the UI thread.
If you can't move this code to the UI thread, then you could always call Application.DoEvents, but I strongly suggest you explore these options first:
System.ComponentModel.BackgroundWorker
System.Threading.ThreadPool
System.Threading.Thread
System.Threading.Tasks namespace
You'll need to get your data from one thread to the other. This can be done in a couple of ways...
First, your "background" thread could update some kind of "CurrentStatus" string variable that it changes as it goes along. You could then put a timer on your form that would then grab the CurrentStatus variable and update the label with it.
Second, you could simply invoke the operation from the background thread to the UI thread with a delegate using the InvokeRequired property of the label control. So for example...
private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
if (this.label1.InvokeRequired)
{
this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
return;
}
this.label1.Text = status;
}
You can call that UpdateStatus() method from any thread (UI or background), and it will detect whether or not it needs to invoke the operation on the main UI thread (and if so, does it).
To actually set up the thread, you can do so like this:
private void StartProcessing()
{
System.Threading.Thread procThread = new System.Threading.Thread(this.Process);
procThread.Start();
}
private void Process() // This is the actual method of the thread
{
foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
// Do processing
// Show progress bar
// Update Label on Form, "f.Name is done processing, now processing..."
UpdateStatus("Processing " + f.Name + "...");
}
}
Then when the user clicks the "GO" button you'll simply call StartProcessing().
If your processing is lengthy do it in a backgroundworker thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
I also recommend to use :
Application.DoEvents();
Processes all Windows messages currently in the message queue.

Resources