3

I'm working on an Export-Tool from a Database which I had written in Visual Basic.net before a long time.

I switched to C# and like to reprogram it in C# since I've gathered quite a little bit more experience than I had before :-)

My C# application's UI is hanging because there is a big database query to do. So I've informed myself about asynchronous programming. Tried threads and tasks as well but I'm having problems to find the right method for my concerns.

This is what I have: it's a Windows Forms application and there's a start button which creates a new thread.

The Method called Export is a non static method which I've created in a second class file named actions.cs. It's non static because the method should be reused often in the code but with different parameters.

So I instantiated the method in the Button_Clicked Event on Form1 with the corresponding parameters:

actions KuliMon = new actions()
        {
            ExportPath = settings.ReadActSetting("baexport", "ExportPfad", ""),
            Trennzeichen = settings.ReadGlobSetting("Trennzeichen", ";"),
            ConnectionString = settings.ReadGlobSetting("Mand1_odbc", ""),
            SQLFile = "kuli.sql",
            ExportAktion = "kuli"
        };

Then I've started the thread from the Button_click event like this:

Thread ExportThread = new Thread(KuliMon.Export);
        ExportThread.Start();

This works. No sticking GUI. But now there is the problem. My method Export in actions.cs is exporting the DB-Query into a csv-File but should also return the result in a string variable which then I can display in a TextBox on Form1.

By reading a little bit around I've found the Invoke-Method this helped quite a little bit. Under Thread.Start() I've added the following:

this.Invoke((MethodInvoker)delegate
        {
             tx_main_t1.Text = "Hello";
        });

When I've clicked the button the TextBox says "hello". But instead of hello I need the Return string from my method Export running in the thread. And here's the problem how can I get the string with the queried results.

In my understanding the thread method has to call a void-method and must not return a value.

I had an idea of creating a public property string and fill the string in Export with the return value like this:

public string results { get; set; }

Instead of using return ReturnValue in Method Export I've tried

results = ReturnValue;

In Form1 I then tried to fill the TextBox with KuliMon.results but it's empty because I've made an instance of Export as I think.

halfer
  • 19,824
  • 17
  • 99
  • 186
Sum1Unknown
  • 1,032
  • 1
  • 9
  • 14
  • Are you limited to using .Net 3.5 or 4.0? Or is it possible you use .Net4.5? in .Net4.5 there are ne keyweords named Async and Await which help alot in creating reactive UIs. Well you could use the same feature in 3.5 or 4.0 by using the AsyncBridge library – BoeseB Jan 29 '15 at 12:06
  • Which .NET framework version are you on? Also, what database is this? SQL Server? – Yuval Itzchakov Jan 29 '15 at 12:08
  • Create a Object with a string property, this object is known by your window. Now give these object to your thread. Do your work. Write the Result into your string variable and let your thread throw an event (which is handled by your UI). Inside this handler you just read your variable and show it's contents. – user743414 Jan 29 '15 at 12:35

3 Answers3

2

You should look in to the BackGroundWorker class
https://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx

You can assign a function to call when the worker completes the job, and have that function update your UI.

Jakob Olsen
  • 793
  • 8
  • 13
2

Both database queries and writing to files are I/O-bound operations, so they are a natural fit for async and await.

First, you would define an asynchronous version of KuliMon.Export:

async Task<string> ExportAsync()
{
  var data = await myQuery.ToListAsync();

  await myStream.WriteAsync(...);

  return results;
}

You can, for example, use Entity Framework 6 for asynchronous query support.

Then you can call it from your UI as such:

async void button1_Clicked(...)
{
  TextBox1.Text = await myInstance.ExportAsync();
}

If you can't use asynchronous database queries for whatever reason (e.g., I think Oracle doesn't support them at this time), then you can use a background thread that calls the synchronous APIs. Note that Task.Run is a modern replacement for both Thread and BackgroundWorker:

string Export();
...
async void button1_Clicked(...)
{
  TextBox1.Text = await Task.Run(() => myInstance.Export());
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Ah, ok, so I will concentrate myself on creating a Task. Though I have to say that this is really hard stuff for me. But I'll try until it works. Allright for the moment I'd like to thank all repliers for your help and kindness. – Sum1Unknown Jan 29 '15 at 13:21
1

using async await supported in .Net 4.5 and c#5 (you can get support for this in erarlier .Net versions with AsyncBridge package for 3.5 or for 4.0)

private async void button1_Click(object sender, EventArgs e)
{
     button1.Enabled = false;
     try
     {
          //Code will wait here for your method to return without blocking UI Exceptions or Result will be automatically Scheduled to UI thread
          string result = await DoStuffAsync("myParameter");
     }
     catch
     {
          MessageBox.Show("Ups an error");
     }
     finally
     {
         button1.Enabled = true;
     }

}

/// <summary>
/// Wraps the synchron implementation off DoStuff
/// </summary>    
public Task<string> DoStuffAsync(string s)
{
   return Task.Factory.StartNew(DoStuff, s); //here parameter s is forwarded to your synchronus implementation
}

/// <summary>
/// Your orginal synchron implementation with the dbQuerry
/// or long running calculations
/// </summary>   
public string DoStuff(string s)
{
      //do your normal code;
      return result
}
BoeseB
  • 695
  • 4
  • 17
  • Hello BoeseB, When I would use a Task I have to use a static method - right? I think that's not the best way because I'd like to supply some arguments to my method Export. – Sum1Unknown Jan 29 '15 at 12:55
  • Nah there is nothig that forces you to use a static Method. – BoeseB Jan 29 '15 at 13:00
  • Ok, as I'm programming in c# 5.0 and I'm quite virgin in asynchronous programming which is the better way for future orientation? Using Tasks or the backgroundworker? – Sum1Unknown Jan 29 '15 at 13:08
  • 1
    Backgroundworker is the old concept to use Threading with windows forms. async await is the new guy and in my opinon much easier to work with than backgroundworker. – BoeseB Jan 29 '15 at 13:18