How to make background threads work

Topics: CAB & Smart Client Software Factory
May 24, 2006 at 2:33 AM
originally posted by: dopoto

I am trying to implement some background threads in a view. I have followed the examples in the AppraisalWorkbench module and in the UI Threading section of the help file, but I can't get my code to work the same way.

I have listed below the code of a simple view. It has only one label - "_statusLabel", that has some default text - eg "Loading...". My goal is to have the view and the label displayed initially, then connect to the database in the background, and then update the text of the label according to the connection status ("Connected" / "Failed to connect"). The problem is that in my case the view will not display anything until the db connection operations are finished. InvokeRequired seems to be false everytime.

using System;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Windows.Forms;
using Microsoft.Practices.CompositeUI.SmartParts;
using Microsoft.Practices.ObjectBuilder;


namespace MyApp.SandBoxModule
{
SmartPart
public partial class ThreadView : UserControl, IThreadView
{
public ThreadView()
{
InitializeComponent();
}

private delegate void UpdateStatusDelegate(string status);

public void UpdateStatus(String status)
{
if (InvokeRequired)
BeginInvoke(new UpdateStatusDelegate(InnerUpdateStatus), new object[] { status });
else
InnerUpdateStatus(status);
}

private void InnerUpdateStatus(string status)
{

string connectionString =
ConfigurationManager.ConnectionStrings"ConnectionString".ConnectionString;

using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand("GetSomething", connection);
command.CommandType = CommandType.StoredProcedure;
try
{
command.Connection.Open();
_statusLabel.Text = status;
}
catch (SqlException)
{
_statusLabel.Text = "Failed to connect.";
}
finally
{
if (connection != null){
if (connection.State == ConnectionState.Open)
connection.Close();
}
}

}
}


/// <summary>
/// Sets the presenter. The dependency injection system will automatically
/// create a new presenter for you.
/// </summary>
CreateNew
public ThreadViewPresenter Presenter
{
set
{
_presenter = value;
_presenter.View = this;
}
}

private void ThreadView_Load(object sender, EventArgs e)
{
UpdateStatus("Connected");
}
}
}
May 25, 2006 at 8:17 AM
originally posted by: mmbaker65

Here is an approach that works for us:

1. I suggest you move the threading logic to the Presenter from the View. The View should concentrate on showing the labels and their new text, not managing the threading or interacting with the database.

2. Implement the View's Load event. In that event call a new method in the Presenter named "FormLoaded".

3. In Presenter.FormLoaded, create an instance of a BackgroundWorker object.

4. Add a method named Presenter.DoWork which handles the BackgroundWorker DoWork event. Create a class to wrap any additional data you might need to pass into the DoWork method and pass along when you add Presenter.DoWork to the BackgroundWorker.DoWork event.

5. Add a method named Presenter.RunWorkerCompleted that handles the BackgroundWorker.RunWorkerCompleted event. This method will have code that asks the View to close itself.

6. Add necessary code to Presenter.DoWork to interact with your database, retrieve data, etc. Call methods on the View to update items as needed.

This design ensures that the ModuleController and View don't handle threading. Of course, you do need to ensure that updates to View items within the View are handled by BeginInvoke to ensure that these updates occur on the UI thread, not the background worker thread.

Regards,
Mark

Mark Baker
Host, CMP DevNet .NET Cast
http://www.ddj.com/podcast/dotnetcast
Jun 1, 2006 at 4:20 AM
originally posted by: ksunair

Have a look at chapter 6 in design architecture of Smart client. It has a very simple example. It worked fine for me.

http://msdn.microsoft.com/practices/apptype/smartclient/default.aspx?pull=/library/en-us/dnpag/html/scag-ch06.asp