Sorting Horizontal ListView - c#

I want a list view to sort based on an Object its bounded to
<ListView x:Name="ListView1" Grid.Row="2" Grid.Column="2" VirtualizingStackPanel.IsVirtualizing="True" ScrollViewer.CanContentScroll="False" ItemsSource="{Binding Path=CurrentProductsImages}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="0,0,2,0" >
<Image Source="{Binding Path=Data, Converter={StaticResource ImageSourceConverter}}" RenderOptions.BitmapScalingMode="Fant" Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView} },Path=ActualHeight, Converter={StaticResource HeightMinusConverter}}" />
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
So the Binded Item CurrentProductsImages has a variable called "DisplayOrder"
I want to order the Listview off this value but can't find a way. Most vertical methods of sorting use a gridview but as mines stacked horizontally i cant get it to work?
I can sort the object prior to binding but i wanted it to be more on the WPF side. any ideas? Many thanks

The xaml way of sorting would be to use a collectionviewsource. That has sortdescriptions.
<CollectionViewSource x:Key="SortedItems" Source="{Binding UnsortedItems}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Blaa" />
<scm:SortDescription PropertyName="Blaa2" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
The problem being you can't bind those sortdescriptions.
You could potentially do something with a behaviour or custom frameworkelement. That would allow you to write a bunch of code and kind of make this work in the UI. It'd be more complicated than doing the sorting in the viewmodel though.
I suggest you instead add a collectionview to your viewmodel and handle the sorting there in code. You can define a custom icomparer to use or just clear and add sortdescriptions.
Or sort using Linq if that is better suited to your requirement / skillset.
Examples of sorting (and doing other stuff ) with collections:
https://social.technet.microsoft.com/wiki/contents/articles/26673.wpf-collectionview-tips.aspx
There's a working sample linked.
Esentially, with an observablecollection of People, this is bound using:
public CollectionView PeopleView {get; set;}
Set up:
CollectionViewSource cvs = new CollectionViewSource();
cvs.Source = People;
PeopleView = (CollectionView)cvs.View;
Sorted:
PeopleView.SortDescriptions.Clear();
PeopleView.SortDescriptions.Add(new SortDescription("OrganizationLevel", ListSortDirection.Ascending));
PeopleView.SortDescriptions.Add(new SortDescription("LastName", ListSortDirection.Ascending));
PeopleView.SortDescriptions.Add(new SortDescription("FirstName", ListSortDirection.Ascending));

Related

Combobox not showing groupings

I'm trying to organize the items in a combobox into groups. To do this I've created an object that has project and group name strings. I then set the GroupStyle and ItemTemplate to display these values. However, Currently, only the project string is displayed in the combobox (and the box has a red border, indicating some kind of error).
Here's the xaml for my combobox:
<ComboBox x:Name="comboBoxProjects" Margin="165,90,28,0" Grid.Column="0" VerticalAlignment="Top" Height="25"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0" Style="{StaticResource ComboBoxDefault}"
ItemsSource="{Binding Path=ProjectClientSelections.ProjectGroupItems,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Path=ProjectClientSelections.SelectedProject, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding GroupName}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Project}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Does anyone see where I'm going wrong?
In GroupStyle, the DataContext is not your item (the type contained in your ItemsSource), but a CollectionViewGroup object, which is formed based on the collection of items that you have grouped. Because of this you have to declare a binding path to one of the properties in CollectionViewGroup, for example, based on your code you probably want to use Name property. See MSDN CollectionViewGroup Class
Change your GroupStyle.HeaderTemplate to this:
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
You don't show how you have formed your GroupDescriptions. If you have not grouped the items already, you can do it in following way (assuming the XAML you have provided is contained inside Window and Window's and GroupBox's DataContext is the same):
<Window.Resources>
<CollectionViewSource
Source="{Binding ProjectClientSelections.ProjectGroupItems}"
x:Key="GroupedProjectItems">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription
PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
After this change GroupBox ItemSource binding to the following (directly to CollectionViewSource resource):
ItemsSource="{Binding Source={StaticResource GroupedProjectItems}}"

Listbox live sort using CollectionViewSource on ObservableCollection

I would like to enable live sorting of ListBox items bound to an ObservableCollection; I would also like to enable the live sorting exclusively via my XAML markup (if possible). As things stand, the list is properly sorted on application startup, but items are simply appended (not sorted) to the ListBox when new items are added to the ObservableCollection.
In my viewmodel I have the following public property:
public ObservableCollection<Equipment> EquipmentList { get; set; }
Equipment is an auto-generated class from Entity Framework which contains a public string property named 'Description'. This is my sort target.
My XAML has the following DataTemplate which is intended to enable the live sorting:
<DataTemplate x:Key="EquipmentDescriptionTemplate"
DataType="{x:Type e:Equipment}">
<DataTemplate.Resources>
<CollectionViewSource x:Key="SortedEquipmentList"
Source="{Binding Path=Description,
Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}"
IsLiveSortingRequested="True">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Description"
Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.LiveSortingProperties>
<clr:String>Description</clr:String>
</CollectionViewSource.LiveSortingProperties>
</CollectionViewSource>
</DataTemplate.Resources>
<TextBlock Text="{Binding Path=Description}" />
</DataTemplate>
And finally the XAML ListBox item:
<ListBox x:Name="EquipmentList"
ItemsSource="{Binding Path=EquipmentList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
ItemTemplate="{StaticResource EquipmentDescriptionTemplate}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding EquipmentSelection, UpdateSourceTrigger=PropertyChanged}"
Grid.ColumnSpan="2" Grid.Row="1" Margin="5,5,5,5"/>
There's a lot of extra attributes which I added in my desperate attempts to get the live sorting to work (when in doubt, guess wildly!). I've left them in so folks can see what I've tried, and snicker.
How do I enable live ListBox sorting via XAML?
You'll want to bind the ItemsSource to the CollectionViewSource, not to the underlying collection:
<ListBox x:Name="EquipmentList"
ItemsSource="{StaticResource SortedEquipmentList}"
...
/>
Place the CollectionViewSource somewhere above, in your page's resource dictionary. Bind its source to the underlying collection ("EquipmentList"):
<CollectionViewSource x:Key="SortedEquipmentList"
Source="{Binding EquipmentList.View}"
IsLiveSortingRequested="True">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Description" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.LiveSortingProperties>
<clr:String>Description</clr:String>
</CollectionViewSource.LiveSortingProperties>
</CollectionViewSource>

Sort an editable ComboBox in XAML

I would like to sort an editable combobox in pure WPF, after the addition of a new record. After some research I found some tips, which used a CollectionViewSource.SortDescription, but it does not work for me correctly. What am I doing wrong? The DataContext of the item which used my DataTemplate works fine, but the binding between the DataTemplate and the resource part to sort my entry list doesn't.
My XAML Part
<DataTemplate x:Key="Document">
<DataTemplate.Resources>
<CollectionViewSource x:Key="SortedLabels" Source="{Binding Parent.Labels}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Items"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</DataTemplate.Resources>
<Grid>
...
<ComboBox Name="cbLabel"
ItemsSource="{Binding Source={StaticResource SortedLabels}}"
IsEditable="True"
LostFocus="cbLabel_LostFocus"
KeyUp="cbLabel_KeyUp"
Visibility="{Binding Path=IsUndiscovered, Converter={StaticResource ResourceKey=BooleanToVisibilityConverter}}"/>
...
</Grid>
</DataTemplate>
EDIT
The Collection Parent.Labels are of type ObservableCollection<String>.
Hard to say since you didn't show what the collection is you're trying to sort, but my guess is that each object in Parent.Labels doesn't have a Items property. The PropertyName refers so a property on the individual objects in the list that it will look at and try to sort. I'd guess you want something more along the lines of "Name" or some other property.

Add more of my usercontrol container or usercontrol collection display

I do not know what the container/control im looking for would be called, so I cannot really search for it.
Add More of Same Usercontrol Usercontrol
Clicking on + would add a new instance of My Usercontrol to the right of the existing ones
Clicking on X would dispose the usercontrol that was clicked
I'm not really looking for a tab control that would put each new instance on a new tab, but if there is nothing else then it might do.
The design is not to be as shown in the image obviously, the image just illustrates the basic idea
Any keyword/name suggestions or links to existing implementations?
e.g. Maybe there is a style that turns a ListBox into something suitable?
I would use an ItemsControl and customize it's ItemsPanelTemplate to be whatever you want.
ItemsControls are meant for iterating through a collection of objects, and displaying them in whatever form you want. I wrote some simple code samples of them here if you're interested, or here's another quick example:
<DockPanel x:Name="RootPanel">
<Button Style="{StaticResource AddButtonStyle}"
DockPanel.Dock="Right" VerticalAlignment="Center"
Command="{Binding AddItemCommand" />
<ScrollViewer>
<ItemsControl ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<local:MyUserControl />
<Button Style="{StaticResource RemoveButtonStyle}"
Command="{Binding ElementName=RootPanel, Path=DataContext.RemoveItemCommand}"
CommandParameter="{Binding }"
HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
Your ItemsControl would be bound to an ObservableCollection of objects, and your Add/Remove buttons would simply add/remove items from that collection. Since it is an ObservableCollection, it will notify the UI when the collection gets changed and automatically update.
You can indeed use a ListBox and set its ItemTemplate and ItemsPanelTemplate:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Of course, your ItemTemplate would be a reference to your control.
You could look at something called a carousel control which uses a list of objects behind it and displays them similarly to itunes. This could be a bit over the top but is one solution. An example can be seen here
If this is too advanced for your needs, could it be as simple as a stackpanel with a scrollbar which is bound to a list of your user controls?

Silverlight DataGrid styling

I have a DataGrid whose ItemsSource is bound to a changing Observable Collection. Inside of this collection is a Business Object. Based on some of the values of the Business Object's properties, I would like to be able to modify the color of the text for each item displayed in my DataGrid once the ItemsSource is created.
Has anyone done this before or ran across something similar? Thanks in advance.
<DataTemplate x:Key="MyTemplate">
<Grid x:Name="LayoutRoot">
<TextBlock Text="{Binding MyText}"
Foreground="{Binding MyStatus, Converter={StaticResource colorConverter}}" />
</Grid>
</DataTemplate>
I added the above code and inserted the TemplateColumn to the grid as below:
<data:DataGridTemplateColumn Header="Testing"
CellTemplate="{StaticResource MyTemplate}"/>
The code works fine and pulls out the correct text but the converter never fires and the Binding of the foreground is never called from the get on it.
Any ideas?
Yes. Use a Value Converter when databinding.
<UserControl.Resources>
<myconverters:BackColor x:Key="BackColor" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="{Binding SomeValue, Converter={StaticResource BackColor}" >
</Grid>
Then have your converter class implement IValueConverter and return a Brush object of some kind. You usually don't have to implement ConvertBack()
Adding to BC's answer:
You can make a DataGridTemplateColumn and specify a data template for cells in a column. In the data template you can bind the text colour.
<swcd:DataGrid ... >
<swcd:DataGrid.Columns>
<swcd:DataGridTemplateColumn Header="MyColumn" CellTemplate="{StaticResource MyColumnDataGridCellTemplate}"/>
...
in resources:
<DataTemplate x:Key="MyColumnDataGridCellTemplate">
<Grid>
<TextBlock Text="{Binding someproperty}" Foreground="{Binding someotherproperty, Converter={StaticResource MyConverter}}"/>
...

Categories

Resources