This question has been asked a lot, and I've read all the posts on Stackoverflow on it.
I wanted to confirm my conclusion though.
Where the source of information being populated is quite fast (ie it doesn't take much processing time to get the information itself), it seems to me that the processing that takes the time is actually feeding it into the DataGridView. However that has to be done on the UI thread as that's where the control is.
If that's the case there seems to be limited benefit to trying to do anything in the background, and that the corollary is that there's no effective way to populate a DataGridView without bunging up the UI thread. Is that right?
Surely there must somehow be a way to populate a DataGridView entirely asynchronously while the user can still interact with the UI?
Surely there must somehow be a way to populate a DataGridView entirely asynchronously while the user can still interact with the UI?
There are many ways it can be done.
Paging via Async/await Inlined with Regular Code
If whatever it is you are fetching the data from (whether it be a direct database connection; REST or WCF call) supports paging, then you could fetch pages of data via inline async/await and add rows for each item returned in the page.
e.g.
// somewhere in your UI code
async Task LoadAsync(List<Page> pages)
{
foreach (var page in pages)
{
var stuff = await service.GetMovieSalesPagedAsync (page);
foreach (var item in stuff)
{
_dataGrid.Rows.Add (/* convert item then add it here */);
}
}
}
This is faster than say requesting all the data in one go and then trying to add rows for each item. The latter would just block the UI.
The benefit of the above approach is that the code is inline and easier to read.
Dedicated Task with Progressive Filling During Application Idle
This technique is better for when there is a large amount of data to display and you want the best performance UI-wise. It's also useful if the source does not support paging.
Here you can spawn a Task whose job is to retrieve the data a page (or all at once) at a time, then add each page results to say a ConcurrentQueue<> for the benefit of the UI thread. If you have to retrieve all of it, then break the results into pages manually.
Meanwhile, in your Application.Idle handler try to pop an item off the queue and if one is found, add the new items as rows to the datagrid. Now depending on your app, you may choose to process all available pages or wait for the next application idle event. It might take a bit of fine tuning. Waiting for the next application idle allows your app to play nice with UI responsiveness.
This will cause the datagrid to be filled progressively rather than all at once.
A con of this approach is that the code is no longer inline. You have one block of code responsible for fetching and storing data; another for pumping it into the UI.
Related
I'm new to C# / VisualStudio and I'm trying to get a grip on async programming.
Specifically I'm writing an image viewer that should be able to show images from N multiple sets (folders) at the same time, thus using N pictureboxes. I want the image sets / folders to load in the background, thus async, and up to some maximum buffer size. Each picturebox shows a slideshow of sorts, thus while background loading the loaded images should be iterated through to be shown.
The loading should be balanced out over the sets, such that after set[i] image[j] is loaded, set[i+1] image[j] is loaded. However, since sets can change during viewing, it could be the case that for set[i] first images [1, 2 .. j] should be loaded before set[i+1][image[j+1] is loaded, as to be 'balanced' again.
(Also, I'm trying to write a bit cleaner code now, so ideally the loader can be implemented in a seperate (static) class as to not write all serious logic in my Form.)
The balancing part should be easy enough ; the async loading -- not so much. I' ve looked at several examples here at StackOverflow, but I'm doing something wrong. My GUI hangs when loading images, slideshows do not continue .. Thus clearly indicating the async isn't implemented as it should. Also, most examples I seem to find deal with async loading from websites or such - I just want to load from a local disk.
As for what I tried:
(I managed to reinstall my laptop WITHOUT backing up my code.. But it was garbagey anyway.)
In words then, I created several List as members of the form. Some button showed a folder browser, saving the filenames to another list. Then the latter list was iterated through, using the filenames as to start async loading the image, thereby incrementally populating the first list(s). When a timer fired a click, and when the list(s) were not empty, picbox1 showed a pic from list1, etc. I specifically did not use async load of the pictureboxes - I need to process the images before showing them. (For instance, resizing manually, not by means of the textbox. I need this as I want to 'scroll' through images when they are shown, as to maxime the use of screen estate.)
At the lowest level, it was something like async Image.loadfromfile() Followed by await. I did not use Task.As I read that you need to 'propagate' the async stuff to all above functions, I (believe I) used the async keyword in all above functions. So, the functions actually loading as well as for instance the function button_click had the async keyword. I can't remember if I used async in my top Application file, where the form is actually ran in the Main () loop - nor do I really understand if Main SHOULD be async too. -- Same for the await / Task keyword ; I might have used / avoided to use this incorrectly.
What I was expecting to happen was that the loading of images continued on the background, while the already loaded images could be started to be iterated through as to show them in the picboxes as slideshow. However, the GUI clearly hanged.
(-- I hope this is specific enough for the standards here. (Also new to StackOverflow.) If not, I will try to implement it again using a static class and then call for help again with specific code.)
How do I setup an event loop (main loop) in a UWP app?
My goal is to have an app that has a main page with a continuously updating calculation, that then continuously updates an image on the page. While that is constantly happening, the user can click a button to change the calculation behavior, or to go to a second page and edit related data.
The user can then click back to the main page and see the image and calculation restart and continuously update. (The calculation is complex, so it should go as fast as possible and use up as much app time as possible).
If there is a way to accomplish this without an event loop I would like to know that also, but so far I have not found a way.
With an event loop, I can simply update the calculation and UI every time through the loop. But I have not found any way to do so. This question asked nearly the same thing, but was never directly answered and had a different use case anyway.
The closest I have found to a solution is to grab the CoreDispatcher from the CoreWindow and use the RunIdleAsync() method to create a loop:
public MainPage()
{
this.InitializeComponent();
Windows.UI.Core.CoreWindow appwindow = Windows.UI.Core.CoreWindow.GetForCurrentThread();
Windows.UI.Core.CoreDispatcher appdispatcher = appwindow.Dispatcher;
//create a continuously running idle task (the app loop)
appdispatcher.RunIdleAsync( (dummyt) =>
{
//do the event loop here
.
.
.
if (appdispatcher.ShouldYield()) //necessary to prevent blocking UI
{
appdispatcher.ProcessEvents(Windows.UI.Core.CoreProcessEventsOption.ProcessAllIfPresent);
}
});
}
The main problem with this is that you can't switch between pages (you get a system exception from dispatching events within an already dispatched event).
Second, this is very messy and requires maintaining extra state in the event loop. Besides, why should I have to go through these contortions just to have some calculations happening while the app is waiting for user input?
Is there a way to do this (besides switching to a C++ DirectX app)?
I don't know about setting up your own event loop, but there is no reason to do so.
What you are talking about sounds like a great case for Tasks. You would start a calculation Task whenever your user did something, having it report its progress via standard C# events if you need mid-operation updates. Those updates would modify properties in your view model which the binding system would then pick up.
You could also make your calculation code cancellable so changes can abort a previous calculation.
All of this involves pretty standard UWP concepts; no need for a special event loop. That you are even considering that makes me think you need to study MVVM and multi-threading/tasks; you are still thinking in a very "Win-Forms" kind of way.
If we're talking about some event loop, or stream, .Net has a great library named Rx, or Reactive Extensions, which may be helpful for you. You can set up a simple flow, something like this:
var source = Observable
// fire event every second
.Interval(TimeSpan.FromSeconds(1), Scheduler.DispatcherScheduler)
// add timestamp for event
.Timestamp()
// gather system information to calculate
.Select(GetSystemInfo);
Note that the events right now are on UI thread, as you need to access the controls. Now you have two options: use Rx for background processing too or use TPL Dataflow' TransformBlock for processing your system information into new image (it can be Observer and Observable at a time). After that you need to get back to UI thread.
First option:
var source = Observable
// fire event every second
.Interval(TimeSpan.FromSeconds(1), DispatcherScheduler.Current)
// add timestamp for event
.Timestamp()
// gather system information to calculate
.Select(GetSystemInfo)
// expensive calculations are done in background
.Select(x => x.ObserveOn(DefaultScheduler.Instance))
.Select(x => Expensive(x))
.Select(x => x.ObserveOn(DispatcherScheduler.Current))
.Select(x => UpdateUI(x));
You probably should split this chain into several observers and observables, still the idea is the same, more information here: Rx Design Guidelines.
Second option:
var action = new TransformBlock<SystemInfo, ImageDelta>(CalculateDelta,
new ExecutionDataflowBlockOptions
{
// we can start as many item processing as processor count
MaxDegreeOfParallelism = Environment.ProcessorCount,
});
IDisposable subscription = source.Subscribe(action.AsObserver());
var uiObserver = action.AsObservable()
.Select(x => x.ObserveOn(DispatcherScheduler.Current))
.Select(x => UpdateUI(x));
I want to note that UWP and MVVM pattern do provide a possibility to work with binding between UI and ObservableCollection, which will help you to notify user in most natural way.
I'm currently in the process of designing and writing an application in C# using the .NET Framework that imports some data from a file. After importing the data it can be bound to a DataGridView in one or more Windows Form's to allow the user to manipulate the data before it's exported back to a file.
I want my Form(s) to remain responsive during the exportation process with the possibility of cancelling the exportation operation. I was going to create a BackgroundWorker and setup the DoWork handler to perform the export operation, so the exportation operation is carried out in a background thread. I was doing this to allow progress of the operation to be updated in the Form(s), among other reasons. I was going to pass the data into the worker to allow it to do the export.
I'm concerned however that once I start the worker and my worker is performing the exportation operation, which may be still bound to one or more DataGridViews, that my data becomes accessible to multiple threads, and that the user could update the data using the form whilst it's being exported.
Does anyone know how I can prevent the Forms referencing and messing with the data whilst it's being exported?
I do not have any code written as yet, but I've written some code below that I hope conveys what i was thinking of doing, which i'm sure is a horrible way to do it.
class Data : List<string>, MyInterface
{
}
class Form
{
Data data;
void SetData(Data data)
{
this.data = data;
dataGridView.DataSource = data;
}
void ButtonClickHandler()
{
//Create a BackgroundWorker with the DoWork handler set up to
//save/exports each item in data to a file.
}
}
If you don't want the user to modify the data you are trying to export, you have two viable options:
Disable the part of the UI that allows modification of the data while the export is in progress (e.g. make the DataGridView cells read-only) , or
Make a copy of the data before exporting, and export the copy, not the live data that the user is able to edit.
Other synchronization techniques would block the UI thread, which is of course a huge "no-no".
I have a scenario that I've tried to solve with TPL. The result is decent but I'm wondering if my design is flawed and if there is room for any improvement or radical changes.
Scenario:
An user can "subscribe" to X number of items and can set a given interval for updates of that item. The user will then get notifications if the item has changed its data. Since time is
a vital factor I want to show an item as updated straight away instead of waiting for all items to be updated and then notify the user about all updated items in a batch, or is this a bad idea?
My approach:
A user subscribes to an event called ItemUpdated.
A method, called Process is called each time with the given interval. The method is called in a fire and forget way by creating running it on a BackgroundWorker. The Process
method works in the following way:
2.1 Retrieve JSON strings and post them to a BufferBlock which is linked to a TransformBlock.
2.2 The TransformBlock parses each JSON string into a domain object called
Item. The TransformBlock is linked to an ActionBlock.
2.3 The ActionBlock invokes the event ItemUpdated for each Item it receives.
My question is basically: Is this an optimal solution or should i re-think my strategy? My biggest concern is that I notify the user about updated items with an event. Should I use an async callback method that will be given a list of all updated items instead or is there an alternative solution?
Recently i came to know about Rx framework and seems very promising. I have a doubt in it. Suppose from my UI [may it be winforms or web pages], i make a call to webservice and sending a List. So my calls is like --> myWCFServiceMethod(List empLists). Inside this service methods, for each employee object, i need to make again another service calls and get the result of it and do some kind of DB operations [saving and updation] and finally sends back the status of each employee to the client side. For each employee in the lists, i have to do the same operation parallel. There is no sequential order.
Is that possible with Rx framework ? For doing this, should I need to implement callback contracts for each employees status updation back to client UI ?
I made the UI with a datagrid and the datagrid has 2 columns. firts is the employee name and second is the status column.
when UI loads, i loaded with 100 employee in the grid. Then clicks on the start button. So I packed up all the employee object into a list and sends that lists to the webservice method.
Now, i am looking for the things to do which is the status updation of each process when an employee goes through different process. Something like parallel process. There is no sequential process. If some employee object can finish its work early and some others will take some time. SO there is no order of process. Any employee can call its own associated external web service call and gets the result from it. One it got such a result, it then tries to save or update the DB. For all these process, I want to get notified the status of each process of an employee is going through and finally it finishes its work.
I dont understand without having callback contract how Rx can do this ?
I didnt see any similiar type of tutorials or guidance for how we can do it.
Please guide me through proper way.
Thanks very much.
Here's a quick answer to your question.
To make multiple service calls in parallel and then get the results as they return you need a query like this:
var query =
from index in indexes.ToObservable()
from result in webServiceCall(index)
select new { index, result };
The webServiceCall signature would look like IObservable<R> webServiceCall(I index).
You then execute the query with:
query.Subscribe(ir =>
{
// Do stuff with ir.index and ir.result
});
Focus on implementing webServiceCall to fit this code. I hope this gives you a starting point.