C# MVVM DataGrid Binding Strategies? - c#

What is the difference between:
<DataGrid
ItemsSource="{Binding MyCollection}"
/>
and...
<CollectionViewSource x:Key="CollectionData" Source="{Binding MyCollection}"/>
...
<DataGrid
DataContext="{StaticResource CollectionData}"
ItemsSource="{Binding}"
/>
They both seem to work. The only difference is that the second snippet, I can't bind to the SelectedItem. So why would someone pick one strategy over the other? Why wouldn't someone just use the first snippet? Thanks.

MSDN states...
CollectionViewSource has a View
property that holds the actual view
and a Source property that holds the
source collection.
CollectionViewSource seperates the actual collection from the view that is representing the collection. This give you the ability to change the visual structure of the visible collection (think filtering out certain items as you type) without actually changing the underlying collection. It is a wrapper around the actual collection containing the objects needing a visual representation. Bea has a great article about it.
In addition you'll notice the explicit wrapping taking place in the CollectionViewSource in your second example...
Source="{Binding MyCollection}"
Then the CollectionViewCource is now being bound to via the DataGrid providing the seperation I mentioned earlier; whereas the collection was being bound to directly in your first example.

A CollectionViewSource has more features that an ObservableCollection or whatever IEnumerable you use for your ItemsSource. For example, it has SortDescriptions that can allow you to group data. An example can be found here.
TLDR; its a more powerful data structure.

As an aside, provided IsSynchronizedWithCurrentItem is true on the DataGrid, you can bind to the SelectedItem by appending a slash i.e. {Binding /}

Related

What is different between {binding} and inherit in wpf datacontext?

I have some problems about datacontext binding.
My app has virtualization listbox.
Sometimes Button is not fired dataContextChanged.
So I found this.
<Grid DataContext={Binding ~~>
<Button DataContext={Binding}/>
</Grid>
<Grid DataContext={Binding ~~>
<Button/>
</Grid>
My Code is first one. but It's not fired DataContextChanged sometimes, So I changed code to second one.
snoop said first one is from inherit, and second one is from parentTemplate.
What is different first one and second one?
TL;DR:
SomeProperty={Binding} will bind the SomeProperty to the ENTIRE DataContext object from the parent. SomeProperty does not have to be the DataContext from the child. In this special case I don't think there is any difference, since the DataContext is inherited anyways. You are simply explicitly stating, what is already the default. Discussed here
More Info:
Here is an explanation from the official documentation for
<Button DataContext={Binding}/>
As long as the binding already has a data context (for example, the
inherited data context coming from a parent element), and whatever
item or collection being returned by that context is appropriate for
binding without requiring further path modification, a binding
declaration can have no clauses at all: {Binding}. This is often the
way a binding is specified for data styling, where the binding acts
upon a collection. For more information, see Using Entire Objects as a Binding Source.
and from here
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="true"/>
The above example uses the empty binding syntax: {Binding}. In this
case, the ListBox inherits the DataContext from a parent DockPanel
element (not shown in this example). When the path is not specified,
the default is to bind to the entire object. In other words, in this
example, the path has been left out because we are binding the
ItemsSource property to the entire object. (See the Binding to
collections section for an in-depth discussion.)
In general, the DataContext is inherited from parent elements. So in your 2nd example the button gets the DataContext from the Grid. Example
"ItemsControl" are special: Example
I don't know what ~~ is, is this meant to be a placeholder?
Some more information on Bindings and Markup Extensions:
Link1
Link2
Link3

WPF Dynamic Ordering

I have a Model with one of it property being Order with is a type of int. The model is put inside an ObservableCollection say for example ModelList is bound to a listbox.
Using this code
<CollectionViewSource Source="{StaticResource ModelList}" x:Key="SortedItems">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Order"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Then this list is Bound to a listbox using
<ListView ItemsSource="{Binding Source={StaticResource SortedItems}}" />
Works Fines. But I want to change the order of the list by its Order property, that is when i change the Order via code I want the listbox to reflect the change.
How can I achieve this.
In order to resort a CollectionViewSource, you need to update the SortDescriptions property
To access your CollectionViewSource from code, declare it in your viewmodel and bind to it (instead of declaring it in XAML). For items in the visual tree, you can use x:Name, though this does not seem to work from a Resources tag, at least via initial testing

CollectionViewSource Live Sorting is not working

I have created a user control containing a ListBox which is bound through a CollectionViewSource. The ListBox has CheckBoxes for the user to do multiple selection on. I would like the list to be sorted with the selected CheckBoxes at the top. I am hoping for this to work as soon as the user selects or unselects something. I can't seem to find anything thing that does this through xaml. What am I doing wrong?
In my xaml
<CollectionViewSource x:Key="SortedItems"
Source="{Binding Items, ElementName=Selector}"
IsLiveSortingRequested="True">
<CollectionViewSource.LiveSortingProperties>
<System:String>IsSelected</System:String>
</CollectionViewSource.LiveSortingProperties>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="IsSelected"
Direction="Descending" />
<scm:SortDescription PropertyName="CodeDescriptionText" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
and my list box
<ListBox x:Name="ItemsControl"
SelectionMode="Multiple"
ItemsSource="{Binding Source={StaticResource SortedItems}}"
ItemTemplate="{Binding ItemTemplate, ElementName=Selector}"
ItemContainerStyle="{StaticResource ListBoxItemStyle}"
Grid.Row="1"
Grid.ColumnSpan="3">
I also had the same issue, and eventually I found out the problem is with the data source, and I suspect that your issue is the same as mine.
While CollectionViewSource can work with a number of different types of data sources, not all of them will work with live sorting. To ensure everything work smoothly, it is best to use an ObservableCollection of items that implement INotifyPropertyChanged for the data source.
But if you have to use a custom collection class instead of ObservableCollection, then make sure that class implements IList, not just the generic IList<>. If you don't, live sorting will most likely be disabled. And to ensure all other areas work smoothly, I strongly advise you to also implement INotifyCollectionChanged and INotifyPropertyChanged for it as well.
No matter which collection class you use, the items contained in it still have to implement INotifyPropertyChanged. There are no other ways around it.
In your ItemTemplate, are you binding bool properties to the Checkbox.IsChecked properties? If you are, then you should be able to set that property as the SortDescription.PropertyName property as it seems that you are doing. If not, then that is what you need to do.

Binding a method to a column in datagrid WPF

I have a data grid in wpf which is bound to Collection. In one of the columns i want to bind a public method which returns string instead of a property.
Is there a way to resolve this in WPF.
By the way its one way binding.
I'm not entirely sure what you want to do and the advice of the previous two answers may be (and probably are more) appropriate in your scenario but just you answer your question, you can indirectly bind to a method using an ObjectDataProvider.
<Window>
<Window.Resources>
<ObjectDataProvider x:Key="newGuidProvider"
ObjectType="{x:Type Guid}"
MethodName="NewGuid"
/>
</Window.Resources>
...
<TextBlock Text="{Binding Source={StaticResource newGuidProvider}" ... />
...
</Window>
This is just a quick example and you can look into the ObjectDataProvider to see if it's right in your scenario. Here is a great resource which shows additional possibilities such as passing parameters to a method etc., via bindings.
You may be able to accomplish this by using
some evil tricks
an IValueConverter
an attached property
a behavior
by creating a read only proxy property.
However I'll would recommend using a property. It's the way WPF is supposed to work and handles all UI updating logic for you, too.
Why do you want to bind to a method?
If I right understand what you want, it should be enough to you to implement IValueConverter interface and assign it in XAML to you columns data binding's Converter attribute: here is an example how to use it: WPF Converter Example
for more detailed analysis can have a look on SvnRadar opensource project that use a bunch of them.
EDIT
There is no DataGrid control actually, there is a ListView, but the consept is the same.
Hope this helps.

Sorting a databound Silverlight DataGrid

I have a databound Silverlight DataGrid control that I am trying to sort. I am using RIA services (beta) for my data source, if that makes any difference.
I am quite new to databinding in Silverlight, so this might be something really obvious that I've missed, but I can't seem to find any info on it. I want to be able to set the binding of the ItemSource to a collection in xaml using binding syntax, and have it sorted on one column.
I realize I could set the ItemsSource in code and use LINQ to .OrderBy(). But I don't get a binding that way. It seems like there should be a simple way to do this but I can't find one. How can I keep the binding yet order my collection?
have a look at using a CollectionViewSource. You basically use one as a 'middleman' between your actual collection of data and you data-bound control.
rough example:
<Window.Resources>
<CollectionViewSource
Source="{Binding <<<bind to your collection here >>> }"
x:Key="myDataView" />
</Window.Resources>
...
<ListBox Name="lsyFoo"
ItemsSource="{Binding Source={StaticResource myDataView}}">
...
then in your code behind:
myDataView.SortDescriptions.Add(
new SortDescription("<<<insert property to sort by>>>", ListSortDirection.Ascending));
(ps. you can also add grouping using PropertyGroupDescription)
As you are using RIA Services, you can use the DomainDataSource in your XAML. This will allow you to add SortDescriptors which will do your ordering. See my example below:
<riaControls:DomainDataSource.SortDescriptors>
<riaData:SortDescriptor Direction="Ascending"
PropertyPath="Name" />
</riaControls:DomainDataSource.SortDescriptors>

Categories