views:

98

answers:

2

I have a windows form, on which I display data from a local database.

I'd like to also connect to a remote database, and display some other data from there.. however, this remote database could be down, or slow.

I don't want the UI to freeze while I try to connect to this remote database.

So knowing nothing about threading or thread-safety, here's my hamfisted example:

RemoteDataContext rdt;

private void GetRemoteDataContext() {
    rdt = new RemoteDataContext(RemoteServerConnectionString);
}

private void FillFromRemoteDataContext() {
   lblTest.text = rdt.TestTable.First().TestField;
}

private void Form1_Shown(object sender, EventArgs e) {
    Thread t = new Thread(new ThreadStart(new delegate {
        try {
            GetRemoteDataContext();
            FillFromRemoteDataContext();
        } catch { }  // ignore connection errors, just don't display data
    );
    t.Start;
}

So you should be able to tell from that what it is that I want to acheive.

My question is, what is the correct way to go about it?


Update: Thanks guys, now I have (in Form1Shown):

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler((sender, e) => {
    e.Result = null;
    try {
        e.Result = new RemoteDataContext(RemoteServerConnectionString);
    } catch { } // ignore connection errors, just don't display data
});
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((sender, e) => {
    if (e.Result != null) {
        rdt = (RemoteDataContext)e.Result;
        FillFromRemoteDataContext();            
    }
});
bw.RunWorkerAsync();

And it works, and as far as I understand it, there should be no threading related errors.

+2  A: 

You might want to check the BackgroundWorker class, it will make things a lot easier.

You only have to specify delegates for the actual work, for the progress reporting and the thread completion.

CMS
Hah, when I asked this question, I was in the middle of abstracting the above code into a class, which I called, 'BackgroundWorker'.
Blorgbeard
I should have guessed it would already exist.
Blorgbeard
+1  A: 

Thats along the lines of how I'd do it but the issue you will have is cross thread access when your database connection does succeed and you need to update your UI. As CMS suggests you could use the BackgroundWorker class and have it take care of the cross-thread marshalling for you. I tend to go for more fine grained control and I would implement you example as:

RemoteDataContext rdt;
private void GetRemoteDataContext() {    
   rdt = new RemoteDataContext(RemoteServerConnectionString);
}
private void FillFromRemoteDataContext() { 
    if (lblTest.Dispatcher.Thread != Thread.CurrentThread) {
        lblTest.Dispatcher.Invoke(delegate { lblTest.text = rdt.TestTable.First().TestField}); 
    } 
    else {
        lblTest.text = rdt.TestTable.First().TestField;
    }
}
private void Form1_Shown(object sender, EventArgs e) {    
    ThreadPool.QueueUserWorkItem(delegate {        
        try {            
            GetRemoteDataContext();            
            FillFromRemoteDataContext();        
        } catch { }  // ignore connection errors, just don't display data   
    });    
}
sipwiz
Did I miss something, or is that the same as the code I posted?
Blorgbeard
Sorry, I hit accidentally enter when formatting the code. Example is done now.
sipwiz
Interesting, but I think I'd better leave as much of the thread handling to the framework as possible :P
Blorgbeard
Definitely but I'd bet that sooner or later you'll find a situation where you need the extra control. That's when the example will be useful.
sipwiz