Loading data from DB asynchronously in win forms - c#

many time we populate UI with data from DB in the form load and that is why form gets freeze for few second. so i just want to know how can i load data asynchronously and populate UI in form load as a result my form will not freeze and also will be responsive but i don't want to use background worker class. please help me with sample code which can solve my problem.
thanks

Here is a well commented example code:
Example:
// This method can be called on Form_Load, Button_Click, etc.
private void LoadData()
{
// Start a thread to load data asynchronously.
Thread loadDataThread = new Thread(LoadDataAsync);
loadDataThread.Start();
}
// This method is called asynchronously
private void LoadDataAsync()
{
DataSet ds = new DataSet();
// ... get data from connection
// Since this method is executed from another thread than the main thread (AKA UI thread),
// Any logic that tried to manipulate UI from this thread, must go into BeginInvoke() call.
// By using BeginInvoke() we state that this code needs to be executed on UI thread.
// Check if this code is executed on some other thread than UI thread
if (InvokeRequired) // In this example, this will return `true`.
{
BeginInvoke(new Action(() =>
{
PopulateUI(ds);
}));
}
}
private void PopulateUI(DataSet ds)
{
// Populate UI Controls with data from DataSet ds.
}

Command.BeginExecuteReader()
may serves your need for reading purposes.
Here is Sample Code for this method.
You can call Application.DoEvents() while waiting for response to keep your window responsive.

Have a look at this article. http://aspadvice.com/blogs/azamsharp/archive/2007/04/05/Executing-a-Query-Asynchronously-in-.NET-2.0.aspx
It still uses Background worker. Honestly, I can't think of an alternative solution to this this other than threading your application to execute queries and bind returned results. If you do decide to use threads, than i suggest you take a look at this article about thread-pooling for asynchronous execution: http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml

Your best course of action is to use another thread. You can use one straight from the thread pool by calling ThreadPool.QueueUserWorkItem.
private void OnFormLoad()
{
ThreadPool.QueueUserWorkItem(() => GetSqlData());
}
private object GetSqlData()
{
using (var connection = new SqlCeConnection("ConnectionString"))
{
using(var command = new SqlCeCommand())
{
command.Connection = connection;
command.CommandText = "SELECT * FROM tbl_hello";
command.ExecuteReader();
while (command.ExecuteReader().Read())
{
//Put data somewhere
}
}
}
}

Related

How to invoke multiple controls in a single thread?

I am fetching data from a database and binding it to 3 different combo boxes simultaneously based on the parent comboBox value. Following is the example, I have three combo boxes named
i. comboBoxBranch
ii. comboBoxClass
iii. comboBoxSection
Value of comboBoxClass is fetched from database on the basis of selected branch, Similarly the value of comboBoxSection is fetched on the basis of selected branch and selected class. So the order of binding is (ComboBoxBranch) then comboBoxClass and then comboBoxSection.
Now in order to acheive this I am using seperate thread to call GetBranches() method to bind data with comboboxBranch in following way.
private void GetBranches() (This is working perfectly fine)
{
if (comboBoxBranches.InvokeRequired)
{
comboBoxBranches.BeginInvoke(((MethodInvoker) delegate
{
comboBoxBranches.DataSource = _schoolManagementSystemServiceClient.GetBranches();
comboBoxBranches.ValueMember = "BranchId";
comboBoxBranches.DisplayMember = "BranchName";
}));
}
Now the problem occurs how should I bind data with other two comboBoxes that are comboxClass and comboBoxSection, Should I use another thread to as I am using for Getbranch Method or there is any other clean method to achieve this. Following is my GetClasses method that I am calling in comboBoxBranches_SelectedValueChanged() event method of comboBoxBranches.
private void comboBoxBranches_SelectedValueChanged(object sender, EventArgs e)
{
Thread thread=new Thread(GetClasses());
thread.start();
}
private void GetClasses()// in this method how should I achieve invoking for multiple controls? What should I do here?
{
if (InvokeRequired)
{
comboBoxBranches.BeginInvoke(((MethodInvoker) delegate
{
Branch branch = comboBoxBranches.SelectedItem as Branch;
}));
comboBoxClasses.BeginInvoke((MethodInvoker) delegate
{
comboBoxClasses.DataSource = _schoolManagementSystemServiceClient.GetClasses(branch.BranchId);
comboBoxClasses.ValueMember = "ClassId";
comboBoxClasses.DisplayMember = "ClassName";
});
}
}
Same method is for comboxBoxSections whose value is based on both ComboBoxBranches and comboBoxClasses? I am new to multi-threading.
Invoking means waiting until the UI thread is idle, then switch to the UI thread and perform some actions. Therefore, the long running task (e.g. querying data from a database) must be performed before invoking takes place.
Today the preferred way to achieve this is to use async/await.
private async void comboBoxBranches_SelectedValueChanged(object sender, EventArgs e)
{
// We are in the UI thread and can access the controls directly.
Branch branch = comboBoxBranches.SelectedItem as Branch;
var classes = await Task.Run(
// This runs in a new thread. At this point the UI is not blocked.
() => _schoolManagementSystemServiceClient.GetClasses(branch.BranchId)
);
// Here the thread joins the UI thread and returns the classes.
// We are in the UI thread again. No need for Invoke.
comboBoxClasses.DataSource = classes;
comboBoxClasses.ValueMember = "ClassId";
comboBoxClasses.DisplayMember = "ClassName";
}
Note the keyword async in the method header. It tells C# to handle this method in a special way. Behind the scenes C# rewrites this method completely to make the magic happen and hides the complexity involved.
To understand how this works, you can imagine that C# puts the lines after the awaited task (the 3 lines with comboBoxClasses) into a callback method.
As explained in Async in depth (Microsoft) you also should rewrite GetClasses to work asynchronously and to return a Task<T> object, instead of starting a new thread here.
var classes = await _schoolManagementSystemServiceClient.GetClassesAsync(branch.BranchId);
See: Asynchronous programming (Microsoft).

Parallel.ForEach freezing on last loop [duplicate]

More newbie questions:
This code grabs a number of proxies from the list in the main window (I couldn't figure out how to make variables be available between different functions) and does a check on each one (simple httpwebrequest) and then adds them to a list called finishedProxies.
For some reason when I press the start button, the whole program hangs up. I was under the impression that Parallel creates separate threads for each action leaving the UI thread alone so that it's responsive?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
I've tried using the code that's commented out to make changes to the UI inside the Parallel.Foreach and it makes the program freeze after the start button is pressed. It's worked for me before but I used Thread class.
How can I update the UI from inside the Parallel.Foreach and how do I make Parallel.Foreach work so that it doesn't make the UI freeze up while it's working?
Here's the whole code.
You must not start the parallel processing in your UI thread. See the example under the "Avoid Executing Parallel Loops on the UI Thread" header in this page.
Update: Or, you can simply create a new thread manuall and start the processing inside that as I see you have done. There's nothing wrong with that too.
Also, as Jim Mischel points out, you are accessing the lists from multiple threads at the same time, so there are race conditions there. Either substitute ConcurrentBag for List, or wrap the lists inside a lock statement each time you access them.
A good way to circumvent the problems of not being able to write to the UI thread when using Parallel statements is to use the Task Factory and delegates, see the following code, I used this to iterate over a series of files in a directory, and process them in a Parallel.ForEach loop, after each file is processed the UI thread is signaled and updated:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
And the methods that do the actual UI changes:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Hope this helps!
If anyone's curious, I kinda figured it out but I'm not sure if that's good programming or any way to deal with the issue.
I created a new thread like so:
Thread t = new Thread(do_checks);
t.Start();
and put away all of the parallel stuff inside of do_checks().
Seems to be doing okay.
One problem with your code is that you're calling FinishedProxies.Add from multiple threads concurrently. That's going to cause a problem because List<T> isn't thread-safe. You'll need to protect it with a lock or some other synchronization primitive, or use a concurrent collection.
Whether that causes the UI lockup, I don't know. Without more information, it's hard to say. If the proxies list is very long and checkProxy doesn't take long to execute, then your tasks will all queue up behind that Invoke call. That's going to cause a whole bunch of pending UI updates. That will lock up the UI because the UI thread is busy servicing those queued requests.
This is what I think might be happening in your code-base.
Normal Scenario: You click on button. Do not use Parallel.Foreach loop. Use Dispatcher class and push the code to run on separate thread in background. Once the background thread is done processing, it will invoke the main UI thread for updating the UI. In this scenario, the background thread(invoked via Dispatcher) knows about the main UI thread, which it needs to callback. Or simply said the main UI thread has its own identity.
Using Parallel.Foreach loop: Once you invoke Paralle.Foreach loop, the framework uses the threadpool thread. ThreadPool threads are chosen randomly and the executing code should never make any assumption on the identity of the chosen thread. In the original code its very much possible that dispatcher thread invoked via Parallel.Foreach loop is not able to figure out the thread which it is associated with. When you use explicit thread, then it works fine because the explicit thread has its own identity which can be relied upon by the executing code.
Ideally if your main concern is all about keeping UI responsive, then you should first use the Dispatcher class to push the code in background thread and then in there use what ever logic you want to speedup the overall execution.
if you want to use parallel foreach in GUI control like button click etc
then put parallel foreach in Task.Factory.StartNew
like
private void start_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(() =>
Parallel.ForEach(YourArrayList, (ArraySingleValue) =>
{
Console.WriteLine("your background process code goes here for:"+ArraySingleValue);
})
);
}//func end
it will resolve freeze/stuck or hang issue

Best way to display a progress form while a method is executing code?

I have a WinForm load method that takes a long time to gather some data to display to the user.
I display a form with a large font with the word "Loading" while this method is executing.
However sometimes this error comes up and the "Loading" progress form does not close and then eventually my whole application will just exit:
Error creating window handle. at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
Is there a better way to display my progress/loading form while I am executing code in the load method?
This is my code:
//I launch a thread here so that way the Progress_form will display to the user
//while the Load method is still executing code. I can not use .ShowDialog here
//or it will block.
//Progress_form displays the "Loading" form
Thread t = new Thread(new ThreadStart(Progress_form));
t.SetApartmentState(System.Threading.ApartmentState.STA);
t.IsBackground = true;
t.Start();
//This is where all the code is that gets the data from the database. This could
//take upwards of 20+ seconds.
//Now I want to close the form because I am at the end of the Load Method
try
{
//abort the Progress_form thread (close the form)
t.Abort();
//t.Interrupt();
}
catch (Exception)
{
}
A BackgroundWorker is a great way to perform a long running operation without locking the UI thread.
Use the following code to start a BackgroundWorker and display a loading form.
// Configure a BackgroundWorker to perform your long running operation.
BackgroundWorker bg = new BackgroundWorker()
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
// Start the worker.
bg.RunWorkerAsync();
// Display the loading form.
loadingForm = new loadingForm();
loadingForm.ShowDialog();
This will cause the following method to be executed on a background thread. Note that you cannot manipulate the UI from this thread. Attempting to do so will result in an exception.
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
// Perform your long running operation here.
// If you need to pass results on to the next
// stage you can do so by assigning a value
// to e.Result.
}
When the long running operation completes, this method will be called on the UI thread. You can now safely update any UI controls. In your example, you would want to close the loading form.
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Retrieve the result pass from bg_DoWork() if any.
// Note, you may need to cast it to the desired data type.
object result = e.Result;
// Close the loading form.
loadingForm.Close();
// Update any other UI controls that may need to be updated.
}
Ive successfully tested this on .NET 4.0. (WinForms) I'm reasonably certain that this will work on .NET 4.0+ and should be a useful code snippet to reuse in most of your projects that require closing forms at the end of a process.
private void SomeFormObject_Click(object sender, EventArgs e)
{
myWait = new YourProgressForm();//YourProgressForm is a WinForm Object
myProcess = new Thread(doStuffOnThread);
myProcess.Start();
myWait.ShowDialog(this);
}
private void doStuffOnThread()
{
try
{
//....
//What ever process you want to do here ....
//....
if (myWait.InvokeRequired) {
myWait.BeginInvoke( (MethodInvoker) delegate() { closeWaitForm(); } );
}
else
{
myWait.Close();//Fault tolerance this code should never be executed
}
}
catch(Exception ex) {
string exc = ex.Message;//Fault tolerance this code should never be executed
}
}
private void closeWaitForm() {
myWait.Close();
MessageBox.Show("Your Process Is Complete");
}
I would take the code that you have in your load method and place that into a thread. Setup a progress bar somewhere on your form and increment it at key stages in the code that's gathering the data - be careful not to do this in the thread itself though, i.e. don't tamper with ui elements in a separate thread, you'll need to invoke them using a delegate.

Best way to run Database access tasks, that return objects, in separate thread keeping UI responsive?

[Windows forms application & .NET 4.0]
I need to execute database access methods that return objects (either list of classes or simple classes).
Also i need to open forms that are responsive while main thread does initialization.
I need to run these on separate threads keeping the User Interface responsive and of course to be able to pass the results back to main thread for UI updates.
I have been reading books regarding the various ways for this.
I understand that my job can be done by:
BackGroundWorker
Thread Class
Task Class
Which one i should dive into ?
Update: using the suggested Task class i am getting errot for cross thread safety using this:
private void BtnCheckClick(object sender, EventArgs e)
{
var itm = Task<JDEItemLotAvailability>.Factory.StartNew(() =>
Dal.GetLotAvailabilityF41021(
txtLot.Text,
cmbMcu.SelectedItem.ToString(),
cmbLocn.SelectedItem.ToString())
);
lblDescriptionValue.Text = itm.Result.Description;
lblItemCodeValue.Text = itm.Result.Code;
lblQuantityValue.Text = itm.Result.AvailableQuantity.ToString();
LotFocus(true);
}
On the above exmaple i am getting the exception in cmbMcu control not the txtLot.
I would use the Task class, it's really easy to synchronize it and it already provides a support for returning objects.
var task = Task.Factory.StartNew(
() => GetDatabaseData(someArguments),
TaskCreationOptions.LongRunning);
// Example method
public DataSet GetDatabaseData(object args) { ... }
this this tells a scheduler to create and begin a new task and gives it a hint that it might be a good idea not to use a thread-pool thread, if the scheduler uses a thread-pool. Anyway you can now decide how do you want to synchronize.
For example to achieve similar behaviour as in Gregor Primar's answer, you can set up a continuation using ContinueWith method as follows,
task.ContinueWith(oldTask => ProcessReturnedData(oldTask.Result));
// Example method
public IEnumerable<SomeEntity> ProcessReturnedData(DataSet data) { ... }
which will schedule calling the ProcessReturnedData method after the task object has done executing. Note that this will be called even if task fails for some reason, so it may not be always a good solution - or you would have to do some checks in the provided delegate.
If you want to do a non-blocking wait on the main thread and use the returned object there, you can simply use the Wait method.
task.Wait(); // Makes current thread wait until the task is comnpleted.
DataSet result = task.Result; // Accessing the result object.
I hade done a lot of projects using Thread, however Task should be more easy to use.
Here is demo how make async operations using Threads.
This is the class that will return data to ui:
public class MyAsyncClass
{
public delegate void NotifyComplete(DataSet data);
public event NotifyComplete NotifyCompleteEvent;
//Starts async thread...
public void Start()
{
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(DoSomeJob));
t.Start();
}
void DoSomeJob()
{
//just wait 5 sec for nothing special...
System.Threading.Thread.Sleep(5000);
if (NotifyCompleteEvent != null)
{
//TODO: fill your data...
DataSet ds = new System.Data.DataSet();
NotifyCompleteEvent(ds);
}
}
}
And here is ui implementation:
MyAsyncClass myClass = null;
private void button2_Click(object sender, EventArgs e)
{
myClass = new MyAsyncClass();
myClass.NotifyCompleteEvent += new MyAsyncClass.NotifyComplete(myClass_NotifyCompleteEvent);
//here I start the job inside working class...
myClass.Start();
}
//here my class is notified from working class when job is completed...
delegate void myClassDelegate(DataSet data);
void myClass_NotifyCompleteEvent(DataSet data)
{
if (this.InvokeRequired)
{
Delegate d = new myClassDelegate(myClass_NotifyCompleteEvent);
this.Invoke(d, new object[] { data });
}
else
{
//TODO: show your data
MessageBox.Show("Data retrieved!");
}
}

Using await with a TableAdapter

I recently began using the Async CTP and while I have found it quite useful with Self Coded classes and the like, I have run into a bit of a snag when trying to implement it with Generated Code, specifically the TableAdapters that are generated when you work with a Dataset.
I have an application that uses .Fill calls quite a bit to populate DataGrids and Databindings. Since .Fill blocks and my users need to be able to interact with the application while this is going on, I see the Async CTP to be an Ideal solution.
Unfortunately, I cannot seem to use it with the generated TableAdpters without having to code them myself. What are my options?
The problem is that TableAdapters don't have asynchronous Fill methods. This means to get your Fill to run without blocking the UI thread you will have to run on it a worker thread. The async CTP doesn't help you with this - it makes it easier to consume async APIs but it won't help if the async version of the API doesn't exist.
But running the fill on a worker thread should be as easy as spinning up a Task:
public Task FillAsync()
{
return Task.Factory.StartNew( () =>
{
adapter1.Fill(ds1);
adapter2.Fill(ds2);
// etc
});
}
Now where the async CTP will come in handy is if you need to do some additional work after the fills and you need that additional work to happen on the UI thread:
public async Task RebindUI()
{
// Do stuff on UI thread
// Fill datasets on background thread
await FillAsync();
// When fill is complete do some more work on the UI thread
refreshControls();
}
By default when running in a WinForms/WPF/Silverlight app, when you await it will resume on the UI thread, so refreshControls will be called on your UI thread after the Fill work is done on a background thread.
There's a sample that covers this here:
(UI Responsiveness -> Responsive UI during CPU bound tasks)
namespace AsyncGrid
{
public partial class Form1 : Form
{
SolarDataLogTableAdapter ta = new SolarDataLogTableAdapter();
SolarDataLogDataTable dt = new SolarDataLogDataTable();
BindingSource bs = new BindingSource();
public Form1()
{
InitializeComponent();
bs.DataSource = dt;
dataGridView1.DataSource = bs;
}
private async void button1_Click(object sender, EventArgs e)
{
dataGridView1.Enabled = false;
await FillAsync();
bs.ResetBindings(true);
dataGridView1.Enabled = true;
}
public Task FillAsync()
{
return Task.Run(() =>
{
ta.Fill(dt);
});
}
}
}

Categories

Resources