Changing structure of underlying IVirtualTreeList Datasource for DevExpress TreeList - c#

I have TreeList that is displaying my business object hierarchy, all of its parts implementing IVirtualTreeListData. However, at some point I want to make changes: remove some data, maybe add some data or move a leaf to another containing node. I can make the changes to underlying business objects, but displayed tree is not affected.
I presume the reason lies in the fact TreeList walks down the hierarchy of IVirtualTreeListData once, (it corresponds to first time expansion of the nodes), and then just uses he data stored in nodes retrieved on the way. How, then, can change in data source be propagated into view?

To enable automatical synchronization of the XtraTreeList nodes hierarchy with the underlying business objects, please implement an IBindingList interface for child objects collection which you provided as the VirtualTreeGetChildNodesInfo.Children property.
The simplest way to accomplish this task is to create a BindingList<YourBusinessObject>() instance within your BusinessObject to store all child object and assign it to the info.Children property within theIVirtualTreeListData.VirtualTreeGetChildNodes() method implementation.
In this case, the TreeList will automatically refresh the corresponding node when a your object is changed or deleted.

Related

HierarchicalDataTemplate - Ignore specific types on generation

My problem is the following: I got a Tree which has an dynamic depth of categories (each category can have sub-categories as well as entries).
Now I added a HierarchicalDataTemplate for the categories to display correctly in the TreeView. But I get a lot of empty entries, which do not apply the Template (wrong type) but show up in the tree as 'corpse'.
How can I ban them from the generation process? Because it's an abstract tree, they are of the same base-class as the categories are. So they get into the tree, because the tree always searches the "Branches"-property which contains either categories, entries or both.
Any ideas? I didn't find any event of the TreeView which probably give me the opportunity to skip various entries during generation nor any option/property of the template to do so.
Detailed Description: I got a generic Tree class. This class has branches of type "A_TreeLeaf" (abstract). The Tree's generic type must inherit A_TreeLeaf of course. My data is structured in categories (CategoryTreeLeaf) and Data (DataTreeLeaf). Each leaf can have sub-leaves (branches), of course.
Now I load my data from a database and build the tree. Each category has X sub-categories. And each category also could contain some Data. This structure helps me a lot, because I got an clear hierarchic structure of categories and data. This way it should be visualized to the user. But I want to separate Data and Categories. The TreeView should show just the categories (by an HierarchicalDataTemplate) and the ListView just the Data (by an DataTemplate). The ListView works fine, but the Tree shows some "corpse"-entries which are the DataTreeLeaf-instances.
I want to filter the DataTreeLeafs on generation or just stop the TreeView displaying them. Is there any "non-hack" solution? I don't want to copy the tree and remove the Data-leaves unless it's really necessary... because this would cause a lot of overhead work to do for me and to manage either the code behind which uses the real tree or the visualization with the fake-tree (because I need to bridge it somehow that it's updated automatically when one of both changes).
You have a unique problem... you have some data items in your hierarchical data that you don't want to display, but for some reason can't remove. If that sums up your problem, then you're doing something wrong.
In WPF, you shouldn't need to hide data items from the UI, instead you simply don't put them into the collection in the first place. It sounds like your process of filling your hierarchical data is flawed and you'd be better off fixing that at the source than trying to deal with the problems that it causes in the UI.
If you can't fix the actual process for whatever reason, then your next best option is to iterate through the data before you display it and simply remove any data elements that shouldn't be there. When using WPF, it is always best to provide your UI with data that fits the purpose.
However, if for whatever reason you can't even do that, then your last option is to simply define an additional DataTemplate for your abstract base class and just leave it empty:
<DataTemplate DataType="{x:Type YourDataTypesPrefix:YourBaseClass}">
</DataTemplate>
Of course, you'd have to define DataTemplates for each sub type, or they'd also be rendered empty.

Performance, is it better to use Observable collection or INotifyPropertyChange?

I have to make some programs in c# and in order to perform IO between programs i have to use, or property using INotifyPropertyChange(on a List<>) or ObservableCollection<>.
I'd like to know which one is the better to perform IO operation between c# programs.
Thank you for reading
Based on the criteria you list in the question & comments, you're best off with an ObservableCollection.
The INotifyPropertyChanged interface exists to tell you just that - a property changed. When you're talking about a list, the properties will be things like Count and Item[]. This means that, effectively, all you're actually being told is "the contents of the list have changed" but not any details as to what that change actually was. Without any such information, all your control can really do is redraw itself completely based on the current state of the collection.
With ObservableCollection, however, you get told when an item is added (and what that item was and where it was added) and when an item is removed (and what that item was and where it used to be). This is enough information for your UI control to only have to redraw what has actually changed, which is far more efficient than redrawing the entire thing. This is why ObservableCollection was invented - use it!
Take a note that ObservableCollection inherits both INotifyCollectionChanged, and INotifyPropertyChanged.
[SerializableAttribute]
public class ObservableCollection<T> : Collection<T>,
INotifyCollectionChanged, INotifyPropertyChanged
See documentation from link above:
In many cases the data that you work with is a collection of objects. For example, a common scenario in data binding is to use an ItemsControl such as a ListBox, ListView, or TreeView to display a collection of records.
You can enumerate over any collection that implements the IEnumerable interface. However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. This interface exposes the CollectionChanged event, an event that should be raised whenever the underlying collection changes.
WPF provides the ObservableCollection class, which is a built-in implementation of a data collection that implements the INotifyCollectionChanged interface.
Before implementing your own collection, consider using ObservableCollection or one of the existing collection classes, such as List, Collection, and BindingList, among many others. If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index. Implementing IList provides the best performance with the data binding engine.
INotifyPropertyChanged is used to notify the UI when the bounded property value or collection is changed. Whereas ObservableCollection is used to notify the UI when the bound collection is modified(Ex adding or removing object from the collection) It cant notify the UI if the property value in one of the collection object is changed.
These two alternatives do not do the same thing. You are choosing between these two options:
a list property implementing INotifyPropertyChanged, where you throw the event every time the list is modified
a property of type ObservableCollection
With option 1, when you modify the list, an event is raised that says "the entire list has changed." If you have a UI element bound to this list (say, a ListBox), the entire element will have to be redrawn, because it has to assume that the entire list has been changed (that is: it may no longer be the same list!).
With option 2, you are raising specific events about individual items that were added or removed in the list. If you have a UI element bound to this list, it can respond by only modifying the UI that is relevant for these elements.
Consider the example where you remove an item from your list, and the list is bound to a WPF ListBox control. With option 1, the entire content of the list is re-created. With option 2, the removed item's control is removed but the rest of the list is left intact.
It should be clear from this example that the ObservableCollection - because it supports an event that is specific to what you are doing - will be more efficient in many cases. That said, unless you have a huge amount of data in the collection or a very complex UI, the performance gain will be negligible. Further, if you're making large modifications to your list, you may well find that it's faster to refresh the whole list.
Ultimately, no performance question can be answered accurately on StackOverflow without repeating the mantra: profile your code, and make a decision based on the results.

Most efficient way to retrieve/update an object from a collection?

I'm working with a silverlight datagrid that is bound to an observable collection of a business object.
We do not support inline editing of the objects within the grid but we do display a corresponding editing panel for the user selected row.
When the user submits the edits from this panel, I'm persisting the changes in the DB but I'd like the changes to also reflect in the grid.
I know that through the use of the observable collection and notify property changed that if I change the object that the selected row is bound to, the changes will display in the grid.
However, since I'm not inline editing, I need to search the observable collection for the object and make the change to the business object's instance in the observable collection.
I'd like to avoid having to loop through the collection to find said object but I'm worried this is the only real way.
There's no other more efficient, less performance-heavy way that I'm not aware of to retrieve an object from a collection correct? Other than simply to loop through until I hit it?
can you bind your edit grid to the selected item of the display grid? Since they are references this will push/pull changes into the observable collection which can then be persisted.
after having some critical exceptions happen that i couldn't keep track of i decided to avoid the databinding to the edit panel and go with Jeffrey L Whitledge's suggestion.
i'm maintaining a reference to the object displayed in the panel and with the notify changed, when i the user submits the update panel and i persist the changes to the business objects, i'm setting the changes to the grid row object that's bound.
thx guys

How do I cache TreeViewItems to re-expand after a re-binding?

I have a TreeView that is bound to a collection class that I have no control over. Inside this class is a collection of objects, which each have their own collection of items. This hierarchy is fixed at 3 deep. The children of the TreeView are contained in an ObservableCollection and are updated in the TreeView accordingly. The collections inside each of these objects are not observable, and thus I have to manually re-bind the data to the TreeView each time I add an object to one of the children. This causes all of the expanded children to be reset to an unexpanded state. I am trying to cache the objects that were expanded so they can be re-expanded after re-binding. The children work as I would expect, however when I try to expand a grandchild of the TreeView I get a null object.
To get a TreeViewItem I use the ItemContainerGenerator property of the ItemsControl:
TreeViewItem cfItem = treeView.ItemContainerGenerator
.ContainerFromItem(obj) as TreeViewItem;
cfItem.IsExpanded = true;
The second level collections all have a reference to their parent object. So since I have many of these object, they are looped over and each uses it's parent object to find the TreeViewItem of it's parent. The order in which they are added to the collection guarantees (I think) that the children will always be processed after the parent. Thus I get this ugly line of code:
qualItem = (
(TreeViewItem)treeView.ItemContainerGenerator
.ContainerFromItem(
((Child)obj).ParentObject
)
)
.ItemContainerGenerator.ContainerFromItem(obj) as TreeViewItem;
This line always fails when it attempts to get the container from item obj. It successfully gets the parent TreeViewItem, but when attempting to get the Child's TreeViewItem container, I always receive null. The documentation states that ContainerFromItem() returns
"A System.Windows.UIElement that
corresponds to the given item. Returns
null if the item does not belong to
the item collection, or if a
System.Windows.UIElement has not been
generated for it."
I know that the second level child exists in the parent's item collection. I checked in the debugger in VS 2010, and all of the items are there. I spent a good bit of time on Google searching for an answer and came across someone who said that the container items are created on a background worker thread and may not be generated by the time an attempt is made to get the child item container. I tried waiting for the Status property of the ItemContainerGenerator to be equal to GeneratorStatus.ContainersGenerated, but I still got the same result. I need to somehow obtain the TreeViewItem container for my second level children so they can be re-expanded just like the first level children.
"A System.Windows.UIElement that corresponds to the given item. Returns null if the item does not belong to the item collection, or if a System.Windows.UIElement has not been generated for it."
Looks like because of Virtualization, the UIElement you look for doesn't exist when you are looking for it. If the collection is not too large, try turning the Virtualization off.
The solution is to add another layer of abstraction between the data and the TreeView. The top level collection is an ObservableCollection, and that contains several ViewModels, which implement INotifyPropertyChanged, and also have ObservableCollections of elements that are in the tree beneath it. This system allows WPF to more easily bind and keep track of the elements that are being added and deleted.
My main source of information was this article:
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

Explicitly handle or create the data object that’s bound to the control

I read somewhere that one of few weaknesses in data binding model is that you never explicitly handle or create the data object that’s bound to the control and as a result you don’t have a chance to add an extra item. But I’m not sure what is meant by that.
What or how exactly would you be able to add an extra item if you were allow to explicitly create a data object? Would you basically be able to bind control to data source and let the runtime automatically fill the control with data source’s data , and additionally that control could also get an extra item from data source by manually creating it?! How would it be able to do that?!
thanx
When you use the OnItemDataBound event, you have full access to the underlying datasource object via e.Item.DataItem. You can use this data to populate any controls in the ItemTemplate via e.Item.FindControl("controlname"). You can also use functions inside the <%# %> tags to format text or calculate values.
What you have read, in my estimation, is pure crap. Up until the point of binding, I can alter the objects in question. One common scenario, for example, is adding a column to rows in a DataTable object (which is actually a collection of rows and columns). I can, in fact, alter by adding a column (let's say sum) to each row.
I can, with some restrictions on classes, do the same with other types of collections and objects.
After I have bound the object, I can still add items to the output by using the databinding method for a row, so I am still not restricted.
In general, I find those that are expounding this garbage are defending using ASP style code in an ASP.NET page.

Categories

Resources