I have a ListBox which happily displays data using a code-behind MVVM object. However, I want to sort the entries and so I thought an intermediate CollectionViewSource might work. But instead the program crashes on startup.
Original xaml extract:
<ListBox SelectedItem="{Binding SelectedCategory}"
DisplayMemberPath="name"
ItemsSource="{Binding Categories}"
Name="CategoriesListBox" />
Code behind extract:
public class ViewModel : INotifyPropertyChanged
{
private trainCategory[] _categories;
private trainCategory _selectedCategory;
public event PropertyChangedEventHandler PropertyChanged;
public trainCategory[] Categories
{
get { return _categories; }
set
{
if (_categories == value)
{
开发者_开发知识库 return;
}
_categories = value;
RaisePropertyChanged("Categories");
}
} //etc
Replacement XAML for ListBox:
<ListBox SelectedItem="{Binding SelectedCategory}"
DisplayMemberPath="name"
ItemsSource="{Binding Source={StaticResource SortedItems}}"
Name="CategoriesListBox" />
And the CollectionViewSource:
<CollectionViewSource x:Key="SortedItems" Source="{Binding Categories}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="name"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
It seems to me that the CollectionViewSource goes in between the view model and the ListBox, but it clearly doesn't (or I've done it wrong). Any pointers appreciated.
Use your original xaml
<ListBox SelectedItem="{Binding SelectedCategory}"
DisplayMemberPath="name"
ItemsSource="{Binding Categories}"
Name="CategoriesListBox" />
Update your View Model to use a List instead:
public List<trainCategory> _categories;
public List<trainCategory> Categories
{
get
{ // This LINQ statement returns a sorted list
return (from c in _categories
orderby c
select c);
}
set
{
if (_categories == value)
{
return;
}
_categories = value;
RaisePropertyChanged("Categories");
}
} //etc
Then you can skip all that nastiness of trying to bind to a static resporce. Just bind strait to the property in your view model.
Alternately, you can still use arrays as your backing variable in your viewmodel:
public trainCategory[] _categories;
public List<trainCategory> Categories
{
get
{ // This LINQ statement returns a sorted list
return (from c in _categories
orderby c
select c).ToList();
}
set
{
if (_categories == value.ToArray())
{
return;
}
_categories = value.ToArray();
RaisePropertyChanged("Categories");
}
} //etc
What exception are you getting on startup? Remember to have your Resources
section before all other code that needs to use the resources.
An alternative to that would be:
<ListBox SelectedItem="{Binding SelectedCategory}" DisplayMemberPath="name" Name="CategoriesListBox">
<ListBox.ItemsSource>
<Binding>
<Binding.Source>
<CollectionViewSource Source="{Binding Categories}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="name"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Binding.Source>
</Binding>
</ListBox.ItemsSource>
</ListBox>
Also remember to have the proper xmlns
declaration for scm
in any case.
精彩评论