C# - WPF Reverse binded ObservableCollection in XAML - wpf

I have a ObservableCollection which is binded as ItemSource to my ComboBox. It's a ComboBox which shows you your changes which you've done. My Problem is now, that the newest Change is displayed on the bottom of the list.
I tried to reverse it in the property, but when I return ComboboxName.Reverse() I get an IEnumerable back. I also don't want to make a 2nd collection with the reversed data.
An other way would be to solve this in XAML. Does someone have an idea how I can do that?
I found this answer here, but i dont get it how i can implement it.
Reverse order of ObservableCollection

scm stands for
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
There a solution that works for me. You have to adapt it to your case:
<Window.Resources>
<CollectionViewSource x:Key="customerGroups" Source="{Binding Path=Customers}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="IsCompany"></PropertyGroupDescription>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="IsCompany" Direction="Descending"/>
<scm:SortDescription PropertyName="DisplayName" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
Then you reference this resource as ItemsSource of your ComboBox, and bind the content to the property you need:
<ComboBox ItemsSource="{Binding Source={StaticResource customerGroups}}">
<DataTemplate>
<TextBlock Text="{Binding Path= FirstName}"></TextBlock>
</DataTemplate>
</ComboBox>

Related

Grouping in DataGrid bound to a *sample* data source (using Silverlight “Data” window)

Silverlight 5 question. I can group items in a DataGrid by using PagedCollectionView as its ItemsSource (via GroupDescriptions.Add). No problem. However, we are designers (not experienced programmers) working on a prototype and are using the Blend “Data” window extensively where we can conveniently create sample data sources / collections and sample enter data. Unfortunately, GroupDescriptions.Add doesn’t seem to work on these xml-based collections created through the “Data” window.
Is there a way to use grouping in DataGrid without having to use C#? Or is there a way to group the sample data created through the “Data” window in a DataGrid?
I did my research and I'm starting to think this may not be possible. My first post, go easy on me! Thanks -
How to view Silverlight Datagrid group in designer (blend or VS) :
You can try to create a XAML CollectionViewSource bind to a sample data Collection :
Create a new sample data named "customerSampleData" ;
Add a collection property (named "Collection") with 2 sub properties (Name, Age) ;
Add the CollectionViewSource in resources with PropertyGroupDescription.
See the last step :
xmlns:compMod="clr-namespace:System.ComponentModel;assembly=System.Windows"
xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.customerSampleData"
...
</UserControl.Resources>
<SampleData:customerSampleData x:Key="customerSampleData" d:IsDataSource="True"/>
<CollectionViewSource
x:Key="dataSource"
d:IsDataSource="True"
Source="{Binding Collection, Source={StaticResource customerSampleData}}">
<CollectionViewSource.SortDescriptions>
<compMod:SortDescription PropertyName="Name" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Age"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="">
<sdk:DataGrid AutoGenerateColumns="False" DataContext="{Binding Source={StaticResource dataSource}}" ItemsSource="{Binding}" >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
<sdk:DataGridTextColumn Binding="{Binding Age}" Header="Age"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>

Getting an "Items collection must be empty before using ItemsSource" with EF

We're using entity framework to retrieve our data. We're trying to bind a collection view source to a combo box to display the data. Here's the definition for the CollectionViewSource:
<CollectionViewSource x:Key="aSICodesControlledEnvironmentViewSource" d:DesignSource="{d:DesignInstance {x:Type AsiEF:ASICodesControlledEnvironment}, CreateList=True}">
AsiEF is the entity framework assembly. Here's the XAML for the combo box:
<ComboBox x:Name="cmbControlledEnvLast30" Margin="480,20,0,0" DisplayMemberPath="ContEnvDesc" SelectedValue="ContEnvDesc" Width="150" FontSize="14"
ItemsSource="{Binding Source={StaticResource aSICodesControlledEnvironmentViewSource}}">
<CollectionViewSource>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="DisplayOrder" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</ComboBox>
As you can see, we're trying to sort the data by the field DisplayOrder, even though that field isn't visible in the combo box, I would still think that the CollectionViewSource should be able to sort the data by that field.
But where this falls down is in trying to retrieve the data and assign it to the Source of the collection view source in the user control's loaded event:
ComboBoxSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("aSICodesControlledEnvironmentViewSource")));
ComboBoxSource.Source = asiContext.ASICodesControlledEnvironments;
It hangs on the second line, when attempting to assign Source property of the CollectionViewSource object ComboBoxSource. The asiContext is our AsiEF's ObjectContext. The error that gets thrown is, "Items collection must be empty before using ItemsSource". I'm sorry, I don't get what we're doing wrong. I've tried removing the assigning in the ComboBox of ItemsSource from the XAML, but that doesn't work. So, where are we going wrong?
I think you should declare the SortDescriptions in CollectionViewSource definition
<CollectionViewSource x:Key="aSICodesControlledEnvironmentViewSource"
d:DesignSource="{d:DesignInstance {x:Type AsiEF:ASICodesControlledEnvironment}, CreateList=True}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="DisplayOrder" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
and remove the additional CollectionViewSource from ComboBox. This will be interpreted as ComboBox.Items and later when ComboBox.ItemsSource is binding it throws the exception.
<ComboBox x:Name="cmbControlledEnvLast30"
ItemsSource="{Binding Source={StaticResource aSICodesControlledEnvironmentViewSource}}">
</ComboBox>

How can I bind and sort a collection

If I have an unsorted collection, is there an easy way to bind and sort it. I would like to do it in XAML (no Linq, no C#)
If my DataContext has a property, say, MyItems, it is easy to bind against it:
<ListBox ItemsSource={Binding MyItems}/>
However, I'd like to sort it as well. Using the CollectionViewSource should be the solution but it does not work for me:
<ListBox>
<ListBox.ItemsSource>
<Binding>
<Binding.Source>
<CollectionViewSource Source={Binding MyItems}/>
</Binding.Source>
</Binding>
</ListBox.ItemsSource>
</ListBox>
At this point, my ListBox loses its elements.
Am I missing something obvious?
You can define the CollectionViewSource as a resource and provide your desired sorting...
<Window.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding MyItems}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="MyItemName" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}"/>
</Grid>
The scm namespace is xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Create a CollectionViewSource in the CodeBehind which reads from MyItems, and bind your ListBox to that
<ListBox ItemsSource="{Binding MyCollectionViewSource"} />
Neither of the other answers actually address sorting. They are both right about a CollectionViewSource, but you can use that to do the sorting, with CollectionViewSource.SortDescription. Taken from here and modified:
<Window.Resources>
<src:MyItems x:Key="MyItems"/>
<CollectionViewSource Source="{StaticResource MyItems}" x:Key="cvs">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="CityName"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}"
DisplayMemberPath="CityName" Name="lb">
<ListBox.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ListBox.GroupStyle>
</ListBox>
In this example,CityName would be the property on each item in MyItems used to do the sorting

Refreshing the order of the Listbox when item's details has changed

How can I re-sort my Listbox when an item's name is changed using MVVM?
My Listbox is bound to an Observable collection that stores a 'People' class that inherits INotifyPropertyChanged. The Listbox is sorted on property 'Name' and when I change the value of 'Name' for one of the items in the Listbox, I can see that it's value has changed but the Listbox does not automatically re-sort itself.
The initial sorting is done through a CollectionViewSource
<CollectionViewSource x:Key="SortedItems" Source="{Binding PeopleList}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
and is used by the Listbox as follows
<ListBox ItemsSource="{Binding Source={StaticResource SortedItems}}"
SelectedItem="{Binding CurrentSelectedPerson}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When I go to a different page and come back the Listbox has the correct ordering, but when I change the Name of the person the Listbox doesn't refresh. How can this be done while preserving MVVM?
Well this is a known problem which i guess is not been addressed yet.Try implementing a custom CollectionViewSource as mentioned in the below link
http://social.msdn.microsoft.com/Forums/en/wpf/thread/d7eda358-ca16-4164-8773-fd92527c7795
also check this thread for an alternative
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/cb7c5c62-7ca9-49b5-91a0-379581b1c1aa/

WPF ComboBox "option group (optGroup)" type behaviour

I want to have a wpf combobox that displays the dropdown list box with the options grouped under a heading like the <optgroup> behaviour in html. Has anyone seem something like this done before?
See How to: Sort and Group Data Using a View in XAML. You apply a grouping to the CollectionView for your data and then set the GroupStyle on the ComboBox. Done entirely XAML, it would look like this:
<StackPanel>
<StackPanel.Resources>
<CollectionViewSource x:Key="groupedData" Source="{Binding}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Length"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</StackPanel.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource groupedData}}">
<ItemsControl.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ItemsControl.GroupStyle>
</ComboBox>
</StackPanel>
Or you could apply the grouping in code:
this.DataContext = new List<string>() { "foo", "barr", "baz", "fizz" };
var cv = CollectionViewSource.GetDefaultView(this.DataContext);
cv.GroupDescriptions.Add(new PropertyGroupDescription("Length"));
And use the default collection view in Xaml:
<ComboBox ItemsSource="{Binding}">
<ItemsControl.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ItemsControl.GroupStyle>
</ComboBox>
You could customize the look of the grouped data by providing a custom GroupStyle with your own HeaderTemplate.

Resources