Using await with a TableAdapter - c#

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);
});
}
}
}

Related

My datasource isn't updating when changing the binding list using a task

I want to bind my combobox's data source using a binding list. The binding list contains a collection of Client instances. I managed this and it works well, but because reading from the database takes long I decided to use a task. And now once the binding list is updated via the task the combobox still has no values.
I wanted to use a normal thread at first, but struggled so switched to using a task(pretty much the same thing I guess thing I guess). So a solution using threads would be just as useful.
public partial class frmJobCreation : Form
{
public frmJobCreation()
{
InitializeComponent();
}
BindingList<Client> clients = new BindingList<Client>();
private void frmJobCreation_Load(object sender, EventArgs e)
{
cbxRtojClient.DataSource = clients;
Task.Run(() =>
{
clients = new BindingList<Client>(Client.GetClients());
});
}
}
Where Client.GetClients() is a static method that returns List<Client>
In the form load event you have cbxRtojClient.DataSource = clients; and then you are updating the clients object in the Task. But this is never going to update the ComboBox.
A Task in C# (wrt winforms) should ideally perform a task and return its results so that it can be updated in the UI. The UI update should ideally be done in a ContinueWith continuation task which is run in the UI context. We should always update any control in the context of the UI thread. Check this for reference.
Task.Run<BindingList<Client>>(() =>
{
// return all the clients to 'ContinueWith' task
return new BindingList<Client>(Client.GetClients());
})
.ContinueWith(t =>
{
// Result is a dynamic property and holds the output of its previous Task. BindingList<Client> in this case.
clients = t.Result;
// Update UI
cbxRtojClient.DataSource = clients;
}, TaskScheduler.FromCurrentSynchronizationContext()); // ensures calling the ContinueWith task to be run in the UI thread.
To know more about Task Parallel Library (TPL) follow this.

WPF Progress bar working but blocked in UI thread even using async

I am trying to implement an indeterminate progress bar into my program. I'm new to threading, but as far as I know one of the best options here is to add an async method, and await the "heavy" function to perform its results. So I wrote this:
public void Window_Loaded(object sender, RoutedEventArgs e)
{
firstLoad();
}
private async void firstLoad()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
await Task.Run(() => InitializeFilter());
}
private void InitializeFilter()
{
//Asynchronous???
Dispatcher.BeginInvoke(new Action(() => {
//... some lines of code that takes some time to run.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(closeLoadingWindow);
}));
private void closeLoadingWindow(object sender, EventArgs e)
{
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
firstLoad runs when the window is loaded, showing an indeterminate LW loadingWindow, and running the InitializeFilter() method (the heavy one). Finally, when the grid is populated and loaded, an event fires, allowing the LW window to be closed and closing it (if I didn't make it unclosable, a funny user could just close it clicking or using F4, which is not nice).
The system is working properly and everything works as expected regarding time frames, but the loading bar is frozen, not showing progress. The same LW bar works in the MainWindow with a similar set up What am I missing? Thanks in advance!
as far as I know one of the best options here is to add an async method, and await the "heavy" function to perform its results
The best option is to use Task.Run to move the heavy processing to the thread pool, and use await to retrieve its results.
The code as it currently stands uses Task.Run to move to the thread pool and then immediately turns around and uses Dispatcher to move back to the UI thread before doing the heavy processing. Thus, it's blocking the UI thread.
what this particular DataGrid displays is a CollectionView, which is not thread-safe.
Right, you can't update data-bound objects from a thread pool thread.
The best solution is to separate the heavy processing from the UI updates, something like this:
public async void Window_Loaded(object sender, RoutedEventArgs e)
{
await firstLoadAsync();
}
private List<FilterType> InitializeFilter()
{
//... some lines of code that takes some time to run.
}
private async Task firstLoadAsync()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
var filterData = await Task.Run(() => InitializeFilter()); // Get the plain data on a background thread
myCollectionView = new CollectionView(filterData); // Update the UI
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
do not use your dispatcher. Microsoft had the foresight to use it's magic (SynchronizationContext) to be able to update the UI thread in a method that is being executed in an async context. This is demonstrated in their async/await example found here
while under previous/other circumstances, you would have to either marshal back to the main (UI) thread to update the UI thread, or wait until completed and retrieve the results from objects who share state. Since you are using async/await then you should be fine to not use the dispatcher, and update the UI directly.

Solving The calling thread cannot access this object because a different thread owns it Error Without Using Dispatcher [duplicate]

This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
Closed 2 years ago.
Is there a way to solve this error " The calling thread cannot access this object because a different thread owns it" without using dispatcher because dispatcher causes freezing on UI when the codes has a longer time to process is there another way to do it? without causing the freeze on the UI
No, you have to update the UIElement on the UI thread as the error says.
Yes, there other ways to run something on the UI thread other than using the Dispatcher, but they like the Dispatcher still run whatever it is you want to run on the UI thread - so will still freeze the UI.
If you are using C# 5 and .NET 4.5 or above you can easily run your long running process without blocking the UI Thread then when it completes continue on the UI thread (without worrying about how it works) using the async and await keywords:
private async Task<string> SimLongRunningProcessAsync()
{
await Task.Delay(2000);
return "Success";
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
button.Content = "Running...";
var result = await SimLongRunningProcessAsync();
button.Content = result;
}
If you do not have those however you will want to use the Dispatcher. The Dispatcher actually assists you running processes without freezing the UI
What you want to do is run the long running processes off the UI thread then when it is finished update the UI - which the Dispatcher helps you to:
Start long process on another thread and return immediately.
(long process still running, UI continues to update)
Long process finishes, update the UI on the UI thread.
e.g.:
private void UpdateButtonContent(string text)
{
button.Content = text;
}
private void SimLongRunningProcess()
{
Thread.Sleep(2000);
}
private void OnProcessFinished(Task task)
{
string content;
if(task.Exception != null)
{
content = task.Exception.Message;
}
else
{
content = "Success";
}
Dispatcher.BeginInvoke(new Action<string>(UpdateButtonContent), DispatcherPriority.Normal, content);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Start long running process and return immediatly
var task = Task.Factory.StartNew(SimLongRunningProcess);
task.ContinueWith(OnProcessFinished);
}
If you are using .NET 4.0 or newer, you can utilize the async and await keywords for clean, asynchronous code. This feature is built into 4.5 directly, and for 4.0 there is a NuGet package available from Microsoft (Microsoft.Bcl.Async) to enable this functionality.
For example, a user clicks a button and you wish to do something that may take a bit of time, then report back to the user.
// Notice how this method is marked 'async', this allows the 'await' keyword
async void OnButtonClicked(object sender, EventArgs e)
{
var button = sender as Button;
button.IsEnabled = false;
button.Text = "Calculating...";
int result = await DoSomeWork();
button.IsEnabled = true;
button.Text = "Calculate";
}
// This is an asynchronous method that returns an integer result
Task<int> DoSomeWork()
{
// Do some lengthy computation here, will be run on a background thread
return 42;
}
Alternatively, you could use other mechanisms like the BackgroundWorker class, or the Asynchronous Programming Model (APM) with callbacks. These are fine, however the async/await pattern is preferable.
If you have a choice, target .NET 4.5 (Win7+). If you must also support Windows XP, target .NET 4.0 and use the NuGet packages for Microsoft.Bcl.Async.

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!");
}
}

Loading data from DB asynchronously in win forms

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
}
}
}
}

Categories

Resources