I'm trying to create a CollectionViewSource in XAML from an ICollectionView CurrentItem's Property (related table 1..Many), but I got this error:
'System.Windows.Data.BindingListCollectionView' view does not support sorting.
In my VM I have the ICollectionView, wich is the UserControls's DataContext.
public ICollectionView Clients
Client has Loans property, this is what I'd like to bind to a listbox.
It works if I just bind to the CurrentItem's property :
ItemsSource="{Binding Clients/Loans}"
But my problem is the sorting. I want to sort the loans by a property, so I tried to create a CollectionViewSource from that list, but then I got the error above.
<Grid.Resources>
<CollectionViewSource Source="{Binding Clients/Loans}" x:Key="loan_cv">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="CreatedDate" Direction="Descending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Grid.Resources>
Is this possible in XAML without creating a new property in VM ?
If someone else has the same problem, I just created an IEnumerable<> object in VM wich can be ordered. And every time when the CurrentItem property changes on the collectionViewSource, I reset the IEnumerable<> object. It works fine, but some time with large objects, it could be slow..
Related
I have a ComboBox setup to display a bound list of ApplicationNames. The list type the ComboBox is bound to is ObservableCollection<Apps>. I am using a CollectionViewSource to do the sorting as so:
<CollectionViewSource
x:Key="Apps"
Source="{Binding Path=Apps}"
>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="AppNames" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
The ComboBox is written as:
<ComboBox
SnapsToDevicePixels="True"
Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="1"
DataContext="{StaticResource Apps}"
ItemsSource="{Binding}"
ItemContainerStyle="{StaticResource ApplicationItemStyle}"
ItemTemplate="{StaticResource applicationComboTemplate}"
>
</ComboBox>
Now when I open the View that houses this combobox all the application names display properly in the combobox and are sorted. The issue I am having is when I close that view and then re-open the view. When I re-open the view everything loads exactly as it did the first-time, in the way of how I get the ObervableCollection, but this time around nothing shows up in the ComboBox. Also, in the ViewModel I do clear the collection and remove all registered events when the View and ViewModel close.
Here is where I close:
void CleanUpApps()
{
if (this.Apps != null)
{
foreach (var app in this.Apps)
app.Dispose();
this.Apps.Clear();
this.Apps.CollectionChanged -= OnAppsCollectionChanged;
}
}
If I copy {Binding Path=Apps} from the CollectionViewSource and place it over {StaticResource Apps} in the ComboBoxes DataContext, everything works, except the sort now of course, the first time I open the view and every time after.
I am trying to find out what I am doing wrong in the CollectionViewSource, that is causing the second time around loading the view to not have any application names display in the combobox.
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
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.
I have to create in my XAML file a static resource.
<Window.Resources>
<vm:ViewModel x:Key="viewModel" />
</Window.Resources>
I need this static resource to get the items for my combobox
ItemsSource="{Binding Source={StaticResource viewModel}, Path=GetItems, Mode=TwoWay}"
But how can I give the ViewModel (constructor) a instance of my code behind class?
If I understand this correctly, you are violating the MVVM pattern.
You should never provide items from the ComboBox into your VM. You should rather provide the items from you VM and bind it to the Combobox, and the you don't have problems accessing the items.
As far as I understand you want to bind your view and viewmodel according to the MVVM pattern.
You should not reference your viewmodel directly in your view, otherwise you have a strong coupling between them. According to the MVVM pattern, you should couple them by the DataContext
In code behind (for example in file App.xaml.cs) it looks like that
yourWindow.DataContext = yourViewModel
Then in your viewmodel class you will have a property named GetItems
Finally in your window you bind your listbox to GetItems
ItemsSource="{Binding GetItems, Mode=TwoWay}"
Well, you can do it from the code, I mean everything from the code, or you can
try (depends on how your app architcted) , by using ObjectDataProvider.
For example:
<ObjectDataProvider ObjectType="{x:Type ViewModel}" x:Key="viewModel">
<ObjectDataProvider.ConstructorParameters>
<StaticResource ResourceKey="dataProvider"/>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider >
In this case, naturally, the parameter you pass to ctor of the povoder, have to be a resource too.
I am just learning XAML and programming for Windows Phone 7.
Im trying to create an itemtemplate for a WP7 Pivot Control. I was able to make a template which contains a listbox. Is it possible to access this listbox in the code-behind so I can fill it based on a collection of a custom class? Basically how it works is that I have a pivot control and each item in that control is a category. For each category thatis added, there is a list of items that belong to that category. I need to be able to populate the list on each pivot item with items of that category.
I searched for ideas on how to accomplish this, and I get a lot of examples on databinding, but Im not too familiar on how databinding works in XAML.
Would databinding be the way to go or can I somehow get a reference to the listbox and add the items myself?
Any help would be greatly appriciated!
Thank you
I've some considerations on subject:
1) If you fill Categories list via binding, then you don't have entry point where binding is guaranteed comleted (because binding executes in deferred fashion).
2) Working with ItemTemplate's content is more tricky and unreliable, than DataTemplate approach, and you should use it just in exclusive situations. LogicalTreeHelper and VisualTreeHelper classes will help you.
3) But I would recommend you to build your view based on DataTemplates as it is common practice in WPF. Do you really think that this code is pretty complicated?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Window.Resources>
<DataTemplate x:Key="InnerItemDataTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="CategoryDataTemplate">
<StackPanel>
<ListView ItemsSource="{Binding InnerItems}"
ItemTemplate="{StaticResource InnerItemDataTemplate}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Categories}"
ItemTemplate="{StaticResource CategoryDataTemplate}"/>
</Grid>
public class Category
{
public IEnumerable<InnerItem> InnerList
{
get{/*...*/}
}
}
class InnerItem
{
public string Name
{
get{/*...*/}
}
}
public class SampleModel
{
public IEnumerable<Category> Categories
{
get {/*...*/}
}
}
IF you create a new "Windows Phone Pivot Application" the default code shows an example of this but reuses the same items in the listbox in multiple pivotitems.
Here's an overview of what that sample code is doing and how you might go about changing it.
In the constructor of MainPage, the DataContext is set to an object (App.ViewModel).
This Loaded event of MainPage ensures that App.ViewModel is populated.
App.ViewModel is an instance of MainViewModel.
MainViewModel contains an ObservableCollection called "Items". It is this that is bound to an idividual ListBox in a PivotItem:
<controls:PivotItem Header="first">
<ListBox ItemsSource="{Binding Items}">
...
</ListBox>
</controls:PivotItem>
Within the ListBox, you can refer to the contents of the "Items" collection.
If you wanted to adjust this to have different collections for each ListBox/PivotItem you could just adjust this to have multiple collections in the MainViewModel.
HTH.