ItemsControl that loads items one by one asynchronously - wpf

I am creating a custom DataGrid by deriving the traditional tookit based WPF DataGrid. I want a functionality in the grid to load items one by one asynchronously, wherein as soon as ItemsSource is changed i.e. a new collection is Set to the ItemsSource property or the bound collection is Changed dues to items that rae added, moved or removed (wherein the notifications comes to the data grid when the underlying source implements INotifyCollectionChanged such as ObservableCollection).
This is because even with virtualising stackpanel underneath the datagrid takes time to load (2-3 seconds delay) to load the data rows when it has several columns and some are template based. With above behavior that delay would "appear" to have reduced giving datagrid a feel that it has the data and is responsive enough to load it.
How can I achieve it?
Thx
Vinit.

Sounds like you are looking for data virtualization', which typically means creating your own custom type that resembles IList, and doing a lot of work to hydrate objects after-the-fact.
You will end up having your data that the grid is displaying look something like this:
Index 0: new MyDataObject(0);
Index 1: new MyDataObject(1);
And MyDataObject implements INotifyPropertyChanged.
In the constructor, you do the logic necessary to time, schedule, or interpret when the real results should be read. Until then, you return rather empty data... null and string.Empty from your properties.
Then, once the data becomes available (ideally in a background thread, read from wherever - your own local data, or a database or web service), then you can update the real underlying property values and fire the property change notifications so that the UI gets properly loaded then.
It's a little too complex to just jump into, so some searching will help. Hope this gets you started.

Related

Best collection to use for speed in WPF GUI

I have a listview that contains a list of 'rows', which in term, contains a list of 'columns'. For now, I use List for both rows and columns (i.e. I have a List and it the Rows objet, I have a List, but as the number gets bigger, the time it takes to update the GUI and overall performance of the program gets pretty bad. Plus, the GUI isn't notified when the items (columns within the rows) change, so I have to do an Item.Refresh, which seems to refresh the whole thing each time, adding to the slow performance
Is there any other type of object that I could use to accelerate the whole thing. Meaning it would need to satisfied the following points :
- Faster that List
- When I add a new rows, the listview is updated. Is possible, only the new rows is added instead of the whole listview.
- When I change a Columns object, the GUI is updated. If possible, only the modified columns objet is affected so the whole Listview is not changed.
Note that there are quite a number of actual calculations behind the scene for displaying the columns object. I have currently working on optimizing this end, but I'm pretty sure using a better collection would help quite a lot here.
Thanks
I believe what you are looking for is an Observable Collection
This collection type will fire a CollectionChanged event when items are added. You will not need to refresh the collection because WPF controls support this out of the box.
Note
The CollectionChanged event will not be fired when indiviual elements are updated. If you want these updates to show on the UI, the object within the collection should implement INotifyPropertyChanged

WPF: How to create a collection that can be bound to

My app has a background thread that periodically retrieves data from an external source, in the form of key/value pairs. I would like to expose this data for binding, presumably by storing them in some kind of static(?) model, as the data will be needed by numerous views throughout my app. There are potentially hundreds of these keys, and may be different for each customer, so I can't simply create an INotifyPropertyChanged model with a property for each value.
The app has multiple views visible at any one time, and each of these will have numerous controls (usually textboxes) that I want to bind to individual items in the above collection. When a value in the collection is updated, any controls bound to only that item should change to reflect the new value. I'm assuming an ObservableCollection wouldn't be suitable here, as a change to a single item will result in all controls updating, regardless of which item they are bound to?
To throw a further complexity into the mix, some values (which are numeric) will need formatting for display, e.g. number of decimal places, or adding a suffix such as "volts". The formatting rules are user-defined so I can't hardcode them into (say) the XAML binding's StringFormat expression. Ideally I should be able to access both the raw value (e.g. for calculations), and the formatted version (for display purposes). I'm sure it must be possible to achieve the latter using some clever WPF feature!
I would appreciate any pointers on how I can solve these requirements.
Edit: it's worth mentioning that I've previously tried implementing the model as some kind of collection. The problem is that it won't be initially populated with all values, and these only get added some time later. When they do eventually get added, a bound control doesn't update - presumably because it wasn't initially able to bind to the missing value.
I would take a different approach, namely a variation of Event Aggregation. I would have a single class that manages the overall collection (probably a singleton class like franssu suggested), but instead of binding directly to the collection in that class you create smaller models that are more specific to the individual views.
When your main model receives a new item, it publishes an event, which is consumed by the smaller models who can inspect the new item and determine whether or not they should add that item to their internal collection (the one the individual views are bound to). If it doesn't "belong" to their view, they can simply ignore the event.
You could use similar event publishing for updates to items and such, although if you're binding to the actual items you probably don't need that.
Just implement the INotifyCollectionChanged Interface and the INotifyPropertyChanged and you ll get a Collection like the ObservableCollection.
But rember if you select a Item from your Collection (as example a ObservableCollection) and you change that item your other controls won t update. So if you have a class Person in your Collection and you change the name of one person the other controls won t get the new name of the person.
Inside the Person object you still have to implement the INotifyPropertyChanged Interface and raise the event when your name changes.
So what I want to tell you is: A Collection with the interface INotifyCollectionChanged will only tell the bound controls: There is a new Item, there has been a item removed or a items index changed BUT not if the item itself changes.
So you ll need a Collection that provides the points above and a Item contained by the collection that raises events if a property of it changes.
ObservableCollection is perfect here. You should find that a standard ItemsControl bound to an ObservableCollection will only update the controls of the items that have changed, not every item in the collection.
This is the reason ObservableCollection exists - the events that it raises specifically identify items that have changed, so that the UI can handle them sensibly.
I've tested this locally with a small WPF app and it works fine. Worth noting, though, that a virtualised items panel would probbaly appear to break this behaviour when it scrolls...
EDIT: rereading your question, you actually say "When a value in the collection is updated..." If your collection contains instances of a class, and you update properties on the class, you don't even need ObservableCollection for this to work - you just need the class to implement INotifyPropertyChanged.

How to assign context and refresh it in Entity Framework?

I created a new entity object and bound it to controls in another window (edit window). After modifying and saving I assigned a new entity object into the one in the main window. The old entity object is bound into a datagrid, now I want the datagrid to display the data that I had modified and saved.
ObjectContext.Refresh Method (RefreshMode, Object) seems to be what I want but I don't know how to use it correctly.
In short :
I have a main window with datagrid displaying the whole data of the table. Users can pick one row and edit it in a edit window. After saving, the datagrid should display what has been modified.
Your best bet here is to use an ObservableCollection as your data source for the datagrid instead of the query.
And look at implementing INotifyPropertyChanged interface in your Customer class.
The ObservableCollection is initially populated by the database query. User changes are made to elements within the ObservableCollection and once complete you then just need to trigger transferring the changes to wherever you originally obtained your list of Customer objects
By doing this changes made both to the collection of Customers and to individual Customer objects (if present within the datagrid) will be automatically updated for you.
edit
I must admit that I'm a bit rushed to offer up any code at the moment, but here's a pretty good article that explains how to use ObservableCollections and classes that implement INotifyPropertyChanged. It also has code examples, which although in VB.NET should give you enough of an idea to get started.
In effect you separate your code into distinct layers UI (View), business logic (View Model) and data layer (Model where your entity framework resides).
You bnd your datagrid to the ObservableCollection type property in your Customers class and your edit csutomer window is bound to as instance of your Customer class.

Binding WPF control to multiple sources (not traditional multibinding)

I am trying to do some databinding magic. I have a Shipments view that lists shipments, and provides filtering and ordering ability on the list. The filter string box, Delivery Status filters (checkboxes) and Ordering Radiobuttons are databound to properties in the ViewModel. I want to add the ability to save state and I have elected to do this by saving control states in an xml document. Previously I have done this before with little problem, using databinding to just read/write the values back and forth.
However, now I have a quandry. My filter controls are currently databound to items in the ViewModel. i can write code that changes their databinding from the xml to the ViewModel on load and vice versa, but that would be messy.
Is there a mechanism in place that I can use to achieve the ability to bind to two equal sources and have them updated at the same time?
This sounds like a concern for the view model.
Why not load the saved values into the view model, and have the view model decide what data to expose?
Then the view doesn't have to be concerned with managing data.
None that I'm aware of.
My opinion: I really wouldn't do this anyway - if your datacontext is the viewmodel, and the viewmodel has properties for the filter, you almost certainly should be persisting and retrieving the relevant viewmodel state to keep the state of the filters. Trying to save controlstate, then retrieve it, set it, and set the viewmodel based on the new controlstate sounds like a lot more work and much more prone to bugs.

C# 4.0 .net 4 and WPF UI update

I'm trying to build an app to work with twitter like site , and the problem I'm trying to solve is -
How am i going to update the UI with a background worker and only add show the latest posts(tweets if you will )
on top of the wrap panel without removing the ones that already exist?
in my previous attempt i have done this by storing the tweets/posts in a local SQlite database and then retrieving the last 10 posts which causes the UI to freeze for a bit and reload all the posts.
Any ideas ?
Since you're using WPF, this is fairly easy.
Just store your "posts" in an ObservableCollection<T>. You can then just Insert the new item at the front of the list. If you've bound this to an ItemsCollection control, WPF will handle redrawing everything correctly for you.
Unless you have a LOT of elements, this will work quite well, and be fairly fast. I'd try it first (since it's really easy to implement), and only try to get more "clever" if you find that it has performance problems. I doubt you'll have issues, though, provided you use the proper collections, since WPF's data binding to ObservableCollection is quite fast.
Use databinding. The UI elements are databound to fields of a record in a collection. The panel of multiple rows should be an ItemCollection of some sort - Listbox, most likely - so that it will replicate the item data template for each row in the underlying data collection.
After that, the UI will track with any changes made to the underlying collection, if the collection implements INotifyCollectionChanged. If you use an in-memory collection, you can just add new data to the top of the collection (Insert at index 0) and that will push all the old items down in the UI display. If you use a file or server based data source, you can fetch the data in a background thread and post updates to the in-memory collection on the foreground thread. Just don't update the databound collection from the background thread.

Resources