The scenario:
I am creating and populating a Treelist using a database.
This is a rather time-consuming task, and don't want to hang the gui (nor have any "progress-bar" etc).
So I decided to move all this to a Backgroundworker, but since I cant update the tree from another thread then the one who created it I am creating a temp-tree in the background-thread and when done, just copy the entire contents to the GUI-shown tree.
What is the best way to traverse and copy all nodes, node-data etc?
Is there another (better?) way to do this, ie build/create a tree in a Backgroundworker and showing it in the GUI?
Edit: I am aware of the 'hack' of populating a GUI component in a background-thread, but since I just got thrown into this project and asked to "stop the gui from hanging quite often" with a very limited time frame, re-writing the loading and creation of the data is not really an option (even though this would ofc be the best practice).
I just changed the "CreateTree"-function to run in a new thread, pass the newly created tree to "ThreadComplete" and copy it.
Cheers
UI elements, like a TreeView, should stay in the UI end of things. There are technical reasons for this - Windows doesn't allow updating UI elements from any threads but the main UI threads - but also architectural reasons: your back-end DB-accessing code shouldn't be tightly coupled to any specific UI implementation. If you decide to switch from TreeList to a different control, by DevExpress or any other vendor, you'll have to replace code all through your system.
What you want to do is have your back-end code create a more general data structure, like a list of business objects with a hierarchical structure, like this:
public class MyBusinessObject
{
public string Name {get;set;}
public List<MyBusinessObject> ChildObjects {get;}
}
and return a list of MyBusinessObject from your background thread. This list should be connected to your TreeList using databinding. You didn't specify what UI platform you're using - XtraaTreeList is a WinForms control, right? - but all common frameworks have databinding options to bind this list of business objects to the UI control, rather than have you do all the work yourself.
In order to update a Component from another thread, you can use a SynchronizationContext and then traverse it like it's in the same thread.
Related
I thought I had a pretty good handle on threading until I came across a scenario in which I wanted to benchmark updates to different grids.
I created a window with a grid control, bound an ObservableCollection to it and populated it with 5000 rows of some complex data type (which contains no locks).
Then I created a task using
Task.Factory.StartNew()
This went through a very tight loop (10 million iterations) updating a random property on a random item in my ObservableCollection, each of which raises an INotifyPropertyChanged event of course.
Now since the updates are all happening on the background thread I expected the UI to update, albeit hard-pressed to keep up with this background thread spinning in a tight loop.
Instead the UI froze for several seconds (but didn't go blank or produce the usual spinning cursor of doom) and then came back once the background thread finished.
My understanding was that the background thread would be taxing a core pretty heavily while producing tons of INPC's, each of which get marshalled automagically by the WPF runtime to the UI thread.
Now the UI thread is doing nothing so I expected it to consume all these INPC's and update the grid but it didn't; not a single update occurred. However, when I do this using a Timer (instead of a tight loop) it works fine.
Would someone please enlighten me as to what the heck the UI thread is doing? Thanks in advance!
If you clog up the message pump with a lot of dispatched updates like this, other messages won't get a chance to be processed, which causes the 'freeze' effect you observe.
One thing that can help here is to use Data Virtualization on your UI control so that only the visible rows are actually bound and listening to INPC updates. This is turned on by default for DataGrid, but if you're using a more custom approach to visualizing the data, this could be an issue.
That said, this won't help with frequent modifications to items that are currently visible, as truly rapid fire updates will still clog up the dispatcher. If you have a use case like this, you probably want to isolate your view model objects a bit and have a way to 'batch' your updates. One technique is to have a way to suppress notification while you do a bunch of updates, then call RaisePropertyChanged(null) (or whatever equivalent method on your INPC helper base class) on each instance to update all bindings to that instance.
Another mechanism is to make the data updates in some other layer (whatever model object(s) your view model instance is representing), then copy over those properties to the view model class at well-defined intervals. For rapidly updating background data, I often use a polling loop rather than triggering on events, simply because the events would occur more frequently than the UI cares about and it slows down the background processing to send all these unnecessary notifications constantly.
I have a long running background worker control that exists as a part of my main form. Up until now, this worker's method hasn't had a lot to do. But the addition of some new features and some better error detection, within the worker method, has meant that it has now bloated a little, with a number of methods that have been extracted out of the worker method.
The main job that the background worker does, is execute methods on many instances of a user control that are loaded and displayed in a panel control. The background worker and all the user controls are children of the main form. As the background worker is now getting quite large, I thought it was time to extract the background worker (or at least the methods) into its own class to make future changes easier, improve readability and simplify access to data between the background worker methods.
My question is this, how should I structure the new class with respect to the user controls and the main form?
My thoughts have been...
To pass in all the references of the user controls into the new class as the background worker begins. This would maintain the parent-child-sibling relationships as they were before but I don't know if passing UI element references into a non-UI class is a bad idea. Also not very abstract.
Use events from within the new class to have the main form execute the methods in the user controls. This feels messy, unnecessary and easy to break. Would be abstract.
Some how make the new class a parent of all instances of the user control. I feel like the main form should be the parent of the user controls as they are both UI elements whereas the new class would have no UI elements. Though I feel this offers better structure but less abstraction (see below).
I think that I'm struggling with the program hierarchy in terms of UI and function. Is the display of controls more important than the function or the other way round? I feel like the function should be as abstract as possible from the UI, that the UI is really just a fancy way of setting arguments in what could be a command-line program. I also think abstraction is my buzz philosophy at the moment (I've learned programming through micro-controllers where it doesn't count as much.)
It's been a long day and I'm not sure if any of that makes sense. Please feel free to correct me and I'll try to clarify anything too confusing. Thanks in advance.
I would go with your first approach, and pass the objects to your new class. This would pretty much apply to what dependency injection suggests: http://en.wikipedia.org/wiki/Dependency_injection
I know I need to create and add elements to another element on the main UI thread in WPF and you can easily do this when on another thread using the Dispatcher.
However I would like to build my elements off the UI thread then add them all in one batch if possible.
This is because I am building thousands of elements and the couple seconds it takes on the UI thread freezes the whole application.
Is there any way to do this?
I don't think so; however, you can create a smoother user experience by gradually loading the elements without making the GUI hang completely. This can be done by subscribing to the CompositionTarget.Rendering event, which will be called each time a frame is rendered. If you maintain a list of the view models (and corresponding control types) that you need to add, you can create some (say, fifty) of them and add them the visual tree inside the event handler. The next time the event is invoked, you add fifty more, and so on.
It could be possible, what you do is you create two UI threads. On one UI thread you build up your window and show some kind of progress indication (progress bar) on the other UI thread. Make your window visible when you've built it up.
http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/
I recommend to you to use some composite application patter, like Prims. See Patterns For Building Composite Applications With WPF.
Prism allows to decouple your apps components, and also load them on demands.
Also you can see: Prism
Hope this helps...
I need to write an application in c# that keeps track of multiple tasks, each being implemented as a class instance running on its own thread. A user interface will be used to display the status of each task instance depending on which task I select from tree view which will display the list of tasks.
An idea I have is to create some other class, called PropertyClass which will have an instance of the TaskClass and some properties relating to this TaskClass instance. Then whenever the TaskClass instance changes its state the related property in the PropertyClass instance will get updated and then the UI will be updated with these property values from the PropertyClass when the task is selected from the Tree View list.
There will probably be hundreds of these tasks running which will be communicating with a service on a remote machine.
How else can I go about coding this solution in an efficient way?
Read this document from the MSDN on the Task Parallel Library first.
I have a few suggestions.
First, you need a way to make sure you don't end up with threads blocking your app from closing. One sure fire way to do this is to make sure all your threads are background threads. That can be a little problematic if you have to make sure a thread's work is done before it is joined or aborted.
Second, you could look at using the ThreadPool class which should make creating and using threads more efficient. The thread pool is there to help you manage your threads.
Third, you will need a method of synchronizing your data access from the GUI to data in the other threads. In WPF you use the Dispatcher and in WinForms you'll use Invoke.
Forth, the BackgroundWorker class can help with all of these if it'll fit in the model of your application.
Fifth, events and delegates can be BeginInvoked which essentially puts them on another thread. It's kind of implicit multi-threading and can be useful.
Sixth, and I've not yet had the chance to use this, .Net 4 has the Parallel Task Library that may be of use to you.
Seventh, safe shared data access and synchronization can be accomplished using lock and/or Monitor.
Hope this helps.
-Nate
If each TaskClass instance corresponds to a node on the tree view, you can store the TaskClass instance in the tree view item's Tag property. Or you could create a dictionary of TaskClasses, keyed by a unique identifier such as a GUID, and store the identifier in the Tag property.
In either case, use a callback method to signal that a TaskClass instance has an update.
I have a number of Windows Forms controls which are used to interact with my program objects. Currently they subscribe to an "Updated" event on the object and manually update values when needed. I would like to replace all (or as much as possible) of this boilerplate code using data binding.
The problem I'm running into is that the object state can be modified by any one of several different threads at any moment. Currently I use Invoke() to handle this, which works fine, but when I switch to data binding I get swamped by illegal cross-thread control exceptions. Is there a preferred method to handle this gracefully using data binding, or am I better off just leaving things the way they are now?
Thanks!
If you are data binding your controls to the data sources that are being updated from the underlying thread, then you will have to move the code that does the updating to the UI thread through a call to Invoke.
Or, if you want, you could get a ISynchronizeInvoke implementation (or a SynchronizationContext) and have all the events fire on the UI thread. Of course, this could cause unintended problems with your code, as you weren't firing the events on the UI thread in the first place.