How to set a filter for a DataGrid ItemSource via MVVM - wpf

I have a DataGrid bound to a CollectionViewSource in XAML.
<Window.Resources>
<local:MainWindowViewModel x:Key="ViewModel"/>
<CollectionViewSource x:Key="cvsEntries"
Source="{Binding LogEntriesStore,
Source={StaticResource ViewModel}}"/>
</Window.Resources>
LogEntriesStore is an ObservableCollection (LogEntry is a DTO that's not important in this discussion)
The DataGrid is declared as:
<DataGrid AutoGenerateColumns="False"
Margin="0"
Name="dataGrid1"
ItemsSource="{Binding Source={StaticResource cvsEntries}}"
IsReadOnly="True">
Now I have context menus on various cells in this DataGrid, to kick off a request for filtering. Right click on a cell, and pick filter to filter all the rows, and show only this particular value.
The MVVM gets the request to filter, but the now the tricky bit. How do I set the filter on the CollectionViewSource?
(as an aside -- this would have been a walk in the park with a Silverlight PagedCollectionView but that doesn't seem to be available in WPF, is that right?)

Very simple. You just need to move the collection view inside the view model:
In MainWindowViewModel define a property of type ICollectionView:
public ICollectionView LogEntriesStoreView { get; private set; }
Right after you have initialized the LogEntriesStore property, you need to initialize the LogEntriesStoreView property with the following code:
LogEntriesStoreView = CollectionViewSource.GetDefaultView(LogEntriesStore);
Then you need to remove the CollectionViewSource from XAML and modify the ItemsSource binding to point to the newly created collection view property:
<DataGrid AutoGenerateColumns="False"
Margin="0"
Name="dataGrid1"
ItemsSource="{Binding LogEntriesStoreView, Source={StaticResource ViewModel}}"
IsReadOnly="True">
That's it. Now you have the access to the collection view inside your view model, where you can modify the filter.

There are several solutions to your problem, but in my opinion, the best solutions are the ones which uses only styles with the standard WPF DataGrid control without inventing a new inherited DataGird type or depending on another third-party control. The followings are the best solutions I found:
Option 1: which I personally use: Automatic WPF Toolkit DataGrid Filtering
Option 2: Auto-filter for Microsoft WPF DataGrid

Related

In focus row in Xceed datagrid doesn't get updated

I have a Xceed Datagrid whose ItemsSource is CollectionViewSource defined in XAML. Whenever grid is updated, only the row which is in focus doesn't show updated values (revert back to original values) but all of other rows are updated. If I directly bound the grid to a Collection in ViewModel then everything works fine. The problem is only when, CollectionViewSource comes into picture. Any help is appreciated.
Can you try using the DataGridCollectionViewSource instead of a CollectionViewSource. By using this, you will reap the benefits of the DataGrid such as built in filtering, sorting, grouping, etc. An example from their documentation:
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
<Grid.Resources>
<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
Source="{Binding Source={x:Static Application.Current},
Path=Orders}"/>
</Grid.Resources>
<xcdg:DataGridControl x:Name="OrdersGrid"
ItemsSource="{Binding Source={StaticResource cvs_orders}}"/>
</Grid>
I got solution...
grid.CurrentItem = null

Showing UserControl once at the time with DataTemplateSelector

I have a couple specific user controls to Show some Content, e.g. simple like Image, WebControl but also two complex specific custom controls drawing on a canvas.
Now I thought using the DataTemplateSelector to handle the different UserControls. I actully used this http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector as a reference.
I changed the code so the form loads the UserControls dynamically (according to the file extension) in the following collection:
ObservableCollection<string> _pathCollection = new ObservableCollection<string>();
The only difference to the reference is now I want to navigate back and forward to the next control by showing one control only at the time. Which control should I use instead of ListView?
<Grid>
<ListView ScrollViewer.CanContentScroll="False"
ItemsSource="{Binding ElementName=This, Path=PathCollection}"
ItemTemplateSelector="{StaticResource imgStringTemplateSelector}">
</ListView>
</Grid>
How do I need to bind it to the template (equal to ItemTemplateSelector above)? WPF is still very new to me and I am learning.
Use a ContentControl. Bind your current item to the Content-property and the DataTemplateSelector to the ContentTemplateSelector-property.
<ContentControl Content="{Binding Path=CurrentItem, Mode=OneWay}", ContentTemplateSelector="{StaticResource imgStringTemplateSelector}" />
Your CurrentItem should be a DependencyProperty or a INotifyPropertyChanged-property of your DataContext. When you change your CurrentItem, the ContentControl will update the template automatically with help of your TemplateSelector.

ComponentOne FlexGrid is empty

I just started using ComponentOne. Among other things, I need DataGrid with filtering capability for my WPF Caliburn.Micro application. So I tried to replace my common DataGrid with C1DataGrid, then C1FlexGrid, but in both cases the DataGrid was empty.
Here is my code:
<c1:C1FlexGrid x:Name="EnrollmentFiles" Grid.Row="1"
AutoGenerateColumns="False"
BaseControls:DataGridExtension.Columns="{Binding EnrollmentFileColumns}"
IsReadOnly="True"
SelectedItem="{Binding Path=SelectedEnrollmentFile, Mode=TwoWay}">
</c1:C1FlexGrid>
Could you please tell me what I am missing? Also, should I use C1DataGrid or FlexGrid?
Thanks
It's possible that by having SelectedItem bound the convention isn't working. If you're using the convention and want ItemsSource bound to EnrollmentFiles and you want to use SelectedItem, then create a property called SelectedEnrollmentFile and CM will do the SelectedItem binding too.

How to get the SelectedItem from a toolkit DataGrid which is on a UserControl in WPF using the MVVM Pattern

My question if very similar to question "Exposing DataGrid SelectedItem in parent UserControl in WPF" which is here in this forum.
I have an XAML file which has two UserControls being used a a master-detail window. The first UserControl is just a DataGrid which holds some widgets and the second one holds the detail information of the selected widget. I am trying to user the MVVM pattern so I am trying to avoid using a RoutedEventHandler to handle the SelectionChanged event of the DataGrid. I created a RoutedEventHandler to test if my Detail-info UserControl would be populated with the selectedItem from the DataGrid and it did. So I proved that it worked.
Now, after removing the RoutedEventHandler and proceeding to use a SelectedItem Dependency Property to let the UserControl which displays the detail info nothing gets display on this UserControl when the DataGrid selection changes. My View needs to be aware of the changes. I read Josh Smith's article in which he provides an example using a listview.
I have read quite a few posts/blogs but most of them do not provide an answer or do not user the DataGrid in a UserControl.
In my view I set the DataContext of my window to the windowViewModel which returns a Collection of widgetViewModel and I also set the DataConext of a groupbox on the same window which holds the Detail widget info to the windowViewModel.SelectedItem dependency property.
here is the main code
<UserControl.Resources>
<Style x:Key="WidgetItemStyle" TargetType="{x:Type toolkit:DataGridRow}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</UserControl.Resources>
<Grid>
<toolkit:DataGrid
x:Name="dgWidgets"
DataContext="{StaticResource WidgetsList}"
ItemsSource="{Binding}"
SelectedItem="{Binding ElementName=WidgetsUserControl, Path=SelectedItem, Mode=TwoWay}"
SelectionUnit="FullRow"
SelectionChanged="dgWidgets_SelectionChanged"
IsSynchronizedWithCurrentItem="true"
ItemContainerStyle="{StaticResource WidgetItemStyle}"
>
<toolkit:DataGrid.Columns>
.... column defs
In the window which contains the two UserControls I have:
var viewModel //this variable holds the windowViewModel
this.DataContext = viewModel;
this.gBox.DataContext = viewModel.SelectedItem;
I have been struggling with this for quite some time and still do not know the problem is.
You are right there. I got this to work simply by binding the SelectedItem to a property "currentWidget" on my VM. When the value is changed, you know the user selected a new record in the master grid. Bind your detail control to the same property (if it contains all the details you need) and you are home.
XAML
SelectedItem="{Binding currentWidget, Mode=TwoWay}"...
VM Code
private Widget _currentWidget;
public Widget currentWidget
{
get { return _currentWidget; }
set
{
_currentWidget = value;
NotifyPropertyChanged("currentWidget");
}
}

Silverlight: Datagrid like grouping in ItemsControl

Is it possible to group items in a ItemsControl or Listbox in Silverlight? These controls are bound to a DomainDataSource.
Or are there any 3rd party controls that do this?
UPDATE:
This is the sort of UI I am trying to create.
You can do this by using nested ItemsControls bound to a PagedCollectionView.
Say I have a datasource - MyItems - with fields: Category, Section and Option. I can create a PagedCollectionView from an IEnumerable(of MyItems) and tell it which fields to group by.
Dim original As IEnumerable(Of MyItems) = GetMyItems()
Dim pcv = New PagedCollectionView(original)
pcv.GroupDescriptions.Add(New PropertyGroupDescription("Category"))
pcv.GroupDescriptions.Add(New PropertyGroupDescription("Section"))
Then I bind my first ItemsControl to the PagedCollectionView
hisMyItems.ItemsSource = pcv.Groups
The PCV creates a nested hierachy like:
-Name
-Items
where Name is the value in the grouped field and Items contains the rows/objects in that grouping. I guess you could also create the PCV in xaml if you prefer.
The xaml would look something like:
<controls:HeaderedItemsControl x:Name="hisMyItems" Header="{Binding Name}" ItemsSource="{Binding Items}" >
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<controls:HeaderedItemsControl Header="{Binding Name}" ItemsSource="{Binding Items}" ItemsPanel="{StaticResource ItemsPanelTemplate1}" >
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Option}" />
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
I hope that makes sense. I have tried to simplify things from my actual app but I could have made some mistakes in copying it over. Obviously you could use normal ItemsControls or other controls too and customize with templates etc.
The DataGrid control supports grouping.
Tim Heuer has a good blog on grouping with a datagrid.
link text
Perhaps the control you are really looking for is the Accordian Control from the Toolkit.
See sample of Accordian behaviour here.
Note that the actual appearance is as style-able as any other control. The basic function is to group categories of items that would otherwise be a straight-forward List.

Resources