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.)
Related
First of all, here's the C# code (even though the question is language-independent):
public static void PollClick(IWebElement element, int timeout = defaultTimeout, int pollingInterval = defaultPollingInterval)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.Elapsed < TimeSpan.FromSeconds(timeout))
{
try
{
element.Click();
break;
}
catch (Exception)
{
System.Threading.Thread.Sleep(pollingInterval);
}
}
}
This one is for clicking an element, but I could easily replace the click command with something else (visibility check, send text, etc). I'm setting up automation for IE, Edge, Firefox, and Chrome. I've come across a few situations where a certain web driver has a bug or the web page misbehaves for a browser (an element remains obscured, a crash with no stack trace, and other strange issues). This method has been used sparingly (once or twice) as I already have made use of the existing waits available for Selenium and have even created wrapper functions around those waits (including one that waits until an exception is no longer being thrown). Is it a bad idea to have this method handy? It did pass code review but I'm just curious as to what else I could do for anomalous situations.
There’s nothing wrong with executing such a strategy. In point of fact, the language bindings themselves do exactly that in the WebDriverWait construct. In C# (and other language bindings too, I believe) there is a generic version that is not specific to waiting on elements called DefaultWait which gives the user more control over things like what exceptions are caught and ignored, what timing interval to use, and so on. The caveat to repeating actions on the page like clicking elements is that there is a chance for the action to happen more than once, which may have unexpected side effects.
Apparently there is no issue at all in implementing a custom polling method as per your code.
But the question is Why?
The Selenium Language Bindings Java, Python, C#, Ruby internally implements the same and provides us the APIs to achieve the same. So adding one more layer to the existing layers will definitely will have an impact on the performance of your Script Execution.
Nevertheless, in general as per this discussion when you creating a new function the usual costs of making the function call are :
Push the variables onto the stack memory.
Push the return address onto the stack memory.
Branch-out to the destination function.
Creating a new stack frame in the destination function.
Now, at the end of the function the undoing of all the above :
Destroy the local objects created.
Pop the return address.
Destroy the pass-by-value parameters.
Reset the stack pointer to where it was before the parameters were pushed to stack memory.
So, creating and calling an extra function stands pretty costly in terms of System Resources. To avoid that we can easily avail the services exposed by the APIs particularly the ExpectedConditions Class as follows :
Presence of elements : An expectation for checking that all elements present on the web page that match the locator.
Visibility of elements : An expectation for checking that all elements present on the web page that match the locator are visible. Visibility means that the elements are not only displayed but also have a height and width that is greater than 0.
Click/Interactibility of element : An expectation for checking an element is visible and enabled such that you can click it.
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.
I have some mysterious ArgumentException I have been beating the whole day - still have no idea why does it happen.
I have the next simple method in my MainPage:
public void FavsRefresh()
{
favsCanvas.Children.Clear();
for (short i = 0; i < (App.Current as App).favUnits.Count; i++)
{
FavsItems tmpUnit;
(App.Current as App).favUnits.TryGetValue((App.Current as App).ids[i], out tmpUnit);
Canvas.SetTop(tmpUnit.subCanvas, i * 120);
favsCanvas.Children.Add(tmpUnit.subCanvas);
}
}
Here tmpUnit is an instance of my class FavsCanvas. Its code doesn't matter - it merges some elements into Canvas, which is called here subCanvas and a series of them must be added into parent Canvas, called favsCanvas.
The sense in all this, that we have several items initially and the user may delete existing and add new. Every time an item is deleted or added I call this procedure (including initially program loading).
The joke is that it works during loading and when I call it from another pages, but when I call it from class method throws an exception, besides it adds the first element properly and refuses to do that with others.
Every item has unique name, I even tried not to use names at all or use random ones - not a chance. I have no idea why this exception appears?!
I call this method using following:
MainPage.MPInstance.FavsRefresh();
This way works good from another pages, but from class - fails. I even left only one line (simple reload those items in Canvas):
private void FavMenuItem_Click(object sender, RoutedEventArgs e)
{
//Delete favorite
if (((MenuItem)sender).Header.ToString() == AppRes.FavsMenuDeleteFav)
{
MainPage.MPInstance.FavsRefresh();
}
}
The fun is that this code worked when I wrote it first a couple weeks ago, but now somehow stopped.
Another thing I tried is to make this particular call from a method in App.xaml.cs, which in its turn is called from the class, but it didn't help either.
In fact I have studied most of parameters - everything is the same in both cases: when it works and when not, except the place from where the method is called. But I don't see any proper alternative.
--- added 05 Aug.
I am not sure if it is important, but it always point the next line after the line where exception is thrown:
(the forum does not allow me to post images, so here.
I tried to move this method to class both to class itself and to App.xaml.cs - the same problem.
It works properly when is called during loading (my MainPage is Pivot and this page which contains this favCanvas is one of the pivots, but not the first) and when I call it from another page while overriding its OnNavigatingFrom. And when it is called while the the MainPage and this pivot is active. May be something with that?
Well guys, I still can't catch the reason itself, but at last have found a dirty way to walk around.
The page, for some reason, does not like to be modified when it is active (at least this way). So for now I am forced to simply redirect to another page, where I just call my method and then go back.
If you have some ideas, they are still of demand as my current was is like a crutch and I dislike it
I have a WPF app that controls audio hardware. It uses the same PythonEngine on multiple threads. This causes strange errors I see from time to time where the PythonEngines Globals dictionary has missing values. I am looking for some guidance on how to debug/fix this.
The device has multiple components [filter's, gain's, etc.]. Each component has multiple controls [slider's,togglebutton's, etc.].
Everytime a user changes a control value a python script (from the hardware vendor) needs to run. I am using IronPython 1.1.2(PythonEngine.Execute(code)) to do this.
Every component has a script. And each script requires the current values of all controls (of that component) to run.
The sequence is - user makes change > run component script > send results to device > check response for failure. This whole cycle takes too long to keep the UI waiting so everytime something changes I do something like component.begininvoke(startcycle).
Startcycle looks something like this -
PyEngine Engine = PyEngine.GetInstance(); // this is a singleton
lock(component) // this prevents diff controls of the same component from walking over each other
{
Engine.runcode(...)
}
When different component.begininvokes happen close to each other there are chances where engine.runcode is happening on different threads at the same time. It looks like I need to get rid of the component.begininvoke but that would make things crawl. Any ideas?
You probably want to create a EngineModule for each execution and execute the code against that. Then all of the code will run against a different set of variables. You also probably want to get a CompiledCode object and actually execute that against the new EngineModule each time because engine.Execute will need to re-compile it each time.
Please note this is done in WPF/C# and not in .net2.0 Winforms
I have a ListBox which contains objects of say Class X. Class X contains a BitmapSource object which is displayed in the listbox, so it displays similar to [Image] [Text]
This is loaded via the use of the CreateBitmapSourceFromHBitmap - note also that I call DeleteHBitmap to delete the handle of the HBitmap during this call, which is well known to do from posts I've seen on google/etc
I have a tree which contains said ListBox in each TreeViewItem - typically the tree has several items loaded. Users can drag/drop these images into different TreeViewItems. To handle these operation I manually call the operations:
<code>
ItemCollection.RemoveAt
</code>
<code>
ItemCollection.Insert
</code>
to move the images from the ListBox item collection, note when I insert I create a new Class X object to insert into the ListBox item collection
I have noticed I get a consistent memory leak from calling such operations several times, over the space of 5-10 mins of consistent dragging and dropping.
My question is:
Am I handling the moving of the BitmapSource's correctly? Is there something I'm doing to cause the Images to not be fully removed from the ItemCollection?
Or is there something fundamental I've missed?
Which is the definition of the variable that holds the image in you ClassX??? The problem may be in the fact that you are creating a new ClassX and the old one is no being deleted by the GC making the head have two different instance of ClassX.
Since you are using unmanged code (CreateBitmapSourceFromHBitmap) you should check if all the finalize method are correctly called (though close or dispose probably) and that the are no static references that can be pointing to your ClassX.
Remember that if you ClassX is not removed the Bitmap instance will be reachable in the graph made by the GC making it not to remove it from the heap.
I recommned using perfmon and add the .Net memory object to see if there are any object that survived finalize or pinned object, those are the one you are probably interested regarding the memory leak.
I hope it helps :P, but it will be nicer if you put the code of the ClassX.