WPF DataContext vs ItemsSource Performance - wpf

Suppose we have an ItemsControl, which is bounded to a source.
Is there any performance difference between
ItemsControl.DataContext = resultSet;
and
ItemsControl.ItemsSource = resultSet;
(In both cases correctly binded in XAML)

Well, a performance difference doesn't really matter since the two lines do completely different things. The DataContext is the object that local databindings of the ItemsControl are taken from:
<ItemsControl Width={Binding Length} />
Will take the Length property of the object set as the DataContext and bind it to the Width dependency property of the ItemsControl.
On the other hand the ItemSource is the IEnumerable object that should be iterated to create the child items inside the control. (Each object inside the ItemSource will become the DataContext of the child item it created)

Related

How to get rid of using ElementName in WPF bindings in XAML

I am building a WPF application and I have some DependencyProperties in my window's codebehind (actually a big bunch of them). I want to bind a textbox to one of these string values. If I use {Binding ObjectName} it just doesn't work and it complains about not finding the property in the output. If I use {Binding ObjectName, ElementName=window} (where window is my Window's instance name), it works. But I have lots of bindings and I don't want to use the ElementName property each time. Is there any shortcut that will default all the element names to the window objects, as all of my bindings have the same element?
Thanks,
Can.
The default source of a binding is FrameworkElement.DataContext so you have to set the DataContext property of your window to the instance of your window e.g. DataContext = this;

ItemsControl Binding to a DataModel.ObservableCollection

I have a view (MainPage.xaml) which is bound to a ViewModel.
In the ViewModel I have a DataModel property (note that both viewmodel & datamodel implements INotifyPropertyChanged, or what that interface is called).
In my view i have defined an ItemsControl whose ItemsSource is bound to the said property. This property (DataModel) has an ObservableCollection (which i know it populated with valid data).
The xaml snippet looks like this:
<ItemsControl ItemsSource="{Binding Path=CurrentDataModel.Items}">
Note that i am not showing the rest of the xaml. All it shows is the ItemsTemplate which is just a TextBlock.
The issue is that nothing is being drawn for this ItemsControl, even though i can clearly see (while debugging) that the collection has good data.
Is this "Path=..." binding not possible for an ItemsControl's ItemsSource?
The Path syntax looks correct. The most likely cause of failure is that either the DataContext is not set to your ViewModel or that the property path you specified is incorrect.
In your question you state that the ViewModel has a property named DataModel but in the xaml snippet you have CurrentDataModel.

Binding WPF TreeView with generic viewmodel

I have a usercontrol which contains a TreeView control. I am using MVVM pattern.
I want to reuse this user control in different windows, each time binding the usercontrol to a different datacontext.
<UserControl Name="UserControl1".......>
..............
<TreeView ItemSource={Binding ...}...>
<HierarchicalDataTemplate...........\>
</TreeView>
..............
</UserControl>
In window 1, I want to bind a List<ObjectA> to the TreeView.
In Window 2, I want to bind a List<ObjectB> to the TreeView.
Is it possible to write a generic ViewModel for this usercontrol, so that I can bind different Types of data to the TreeView??
In case my question is not understood, please do let me know.
If I am reading this correctly, you have a UserControl which you wish to reuse, setting its DataContext to be different ViewModel's in different parts of your application...
that being so, yes you can certainly specify Lists of different types as an ItemsSource for your TreeView, but:
The list property must be consistently named within each ViewModel
You will need to describe a DataTemplate (or HierarchicalDataTemplate) for each type you expect to pass into the TreeView within your control's xaml
You may find that binding to an ObservableCollection<T> brings greater reward than a List<T> if you wish to add/remove items to/from the collection and hope to see those changes reflected in the UI
Hope this helps :)

Passing Generic lists to a WPF usercontrol

I want to create a usercontrol that takes lists of different objects. These objects would be assigned to the control at design time. Now I want to be able to use linq to object to sort this list inside the usercontrol. Can anyone give me any ideas as how to go about it?
Add a DependencyProperty of type ObservableCollection<T> to your user control class (call it MyItemsSource for example). In your containing XAML, bind that property to your Linq collection, and inside your user control, bind your ListBox (or other ItemsControl) to the property as follows:
{Binding
RelativeSource={RelativeSource
Mode=FindAncester,
AncestorType=UserControl},
Path=MyItemsSource}
Alternatively, you can set the Name property inside the user control on the top level element (the UserControl element) to for example MyUserControl, and bind against an ElementName instead of a RelativeSource as such:
{Binding ElementName=MyUserControl, Path=MyItemsSource}

Where is IsSynchronizedWithCurrentItem property (or equivalent) for a TreeView?

Tell me it ain't so.
I have a typical windows/file explorer like setup.
Left Side I have a TreeView all data bound showing nodes in a hierachy
Right Side I have a ListView showing Node.Properties
ListView has a IsSynchronizedWithCurrentItem property, which rocks. e.g. If I had another ListView showing a list of nodes and both listViews have this property set to true. Changing selection of node in NodesListView will update the PropertiesListView automatically.
Now I need the same thing with a NodesTreeView and a PropertiesListView... and seems like TreeView has no such property.
Is there a more 'the WPF way' kind of solution to this problem ? Or do I have to handle the NodeSelectionChanged event of the Tree and refresh the listView via code.
A really simple solution is to bind your "details" UI elements to the SelectedValue property of the TreeView. For example, if your TreeView looked like this:
<TreeView Name="CategoryName" ItemsSource="{Binding Source={StaticResource A_Collection}, Path=RootItems}" />
Then you could bind details UI elements (like a textbox) using:
<TextBox Text="{Binding ElementName=CategoryTreeView, Path=SelectedValue.Name}"/>
Would cause the text box to be bound to Name property of the items currently selected in the TreeView.
If you want to bind many UI items as details for the selected TreeView item, consider setting up a DataContext on the elemtent that contains all the details controls (DockPanel / Grid / StackPanel, etc).
<ListView Name="listView1"
ItemsSource="{Binding Path=SelectedItem.Modules,
ElementName=treeView1, Mode=OneWay}"
IsSynchronizedWithCurrentItem="True">
Where ".Modules" is the collection of child items off the selected treeview item you want to display. Don't worry about wiring up the "SelectedItemChanged" event on the treeview.
Why exactly it doesn't implement the property, I do not know, but i have a suggestion down below.
Your code above will work, however, it is not what the IsSynchronizedWithCurrentItem property does. Any ItemsControl binds to the ICollectionView of the ItemsSource property. To get that ICollectionView, we can call CollectionViewSource.GetDefaultCollectionView(object o). Depending on the type of object o, you get a different concrete implementation of the ICollectionView inteface. CollectionView and ListCollectionView are two concrete classes that come to mind.
The ICollectionView interface contains a member called CurrentItem. What the IsSynchronizedWithCurrentItem does is: whenever an item is clicked on the ItemsControl, it sets the CurrentItem for the collection view. The ICollectionView also has two events: CurrentItemChanging and CurrentItemChanged. When the IsSynchronizedWithCurrentItem property is set, the ItemsControl will update the SelectedItem based on what the ICollectionView's CurrentItem is. Makes sense?
In master/detail WPF scenarios, we simply are binding to ICollectionViews and their CurrentItem (the CurrentItem syntax is something like {Binding Items/Name}, where Name is the Name property on the collection's CurrentItem.
So although your code works for your purposes, it doesn't do what that property does. To do what the property does, you need to do the following:
When an item is selected, you need to figure out which collection it belongs to. How do we do this? I believe this is why TreeView doesn't implement it. The selected item is displayed in a TreeViewItem. The DataContext is the object itself, but what is the parent collection ? I guess to get it you could either cache it in some hashmap (silly, but will work) or you can walk up the logical tree and get the TreeViewItem's parent that happens to be an ItemsControl. The ItemsSource property will be your collection.
Get the ICollectionView for that collection.
Need to cast that ICollectionView into a CollectionView (ICollectionView doesn't implement CurrentItem setter)
Call SetCurrent(.. , ..) on the CollectionView instance
Now, anything that is bound to that ICollectionView's CurrentItem will be updated.
This became longer than I expected. Let me know if any further clarification is necesary.
My solution to this turned out to be pretty tiny.. don't know if it is equivalent to IsSynchronizedWithCurrentItem. ListView refreshes as expected.
// the XAML
<TreeView DockPanel.Dock="Left" x:Name="tvwNodes" ItemsSource="{Binding}" SelectedItemChanged="OnNewNodeSelected"/>
<ListView x:Name="lvwProperties" ItemsSource="{Binding Path=Properties}"
// the code-behind
private void OnNewNodeSelected(object sender, RoutedPropertyChangedEventArgs<object> e)
{
lvwProperties.DataContext = tvwNodes.SelectedItem; // this returns the selected Node obj
}

Resources