However, when we programmatically add these filters to the newly build grid during the Loaded event of the RadGridView (a la RadGridView.FilterDescriptors.Add(filter);), the new grid correctly filters on the designated columns in the right way, but it does so exclusively. Using the example grid below, if I were to filter the grid on Route ID = 003 and then modify that row (triggering the building of a new grid on the page), the new grid would only display the 003 row (even though the Items attribute contains the other two rows) with no way of accessing the other rows and no filter on the grid even acknowledged. Furthermore, if I try to filter on Route ID again, the only option for me to filter on is 003. I've included some pictures to better explain my problem.
What I'm hoping to accomplish is to allow the building of the new grid as it currently does, but to transfer the filters as they were from the previous grid. I don't want the new grid to be locked into a hard filter on said filters. Is this possible?
TripSet ID Date Route ID
010 4/9/13 001
010 4/9/13 002
010 4/9/13 003
4 Answers, 1 is accepted
May you paste the code that takes care of storing/restoring the filter descriptors. Also it would be nice to know what is the source collection type.
I will have a look and see what went wrong.
Greetings,
Pavel Pavlov
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
public RadGridView BuildGrid(DataTable dataTable, IEnumerable<WspViewRow> gridRows){ RadGridView radGrid = new RadGridView(); radGrid.Loaded += new RoutedEventHandler(_radGrid_Loaded); BuildColumns(radGrid, dataTable); BuildRows(radGrid, dataTable, gridRows); radGrid.ItemsSource = dataTable; return radGrid;}Here is the method that saves the previous grid's FilterDescriptions. It saves some other things, but only the filters are worth noting at this point.
protected override void SaveRunTimeData(){ _runTimeData = new RunTimeData() { GridFilters = RadGridView.FilterDescriptors };}Lastly, here is our RadGridView.Loaded event handler that sets any filters from the previous grid.
void _radGrid_Loaded(object sender, RoutedEventArgs e){ if (_runTimeData != null) { foreach (ColumnFilterDescriptor filter in _runTimeData.GridFilters) RadGridView.FilterDescriptors.Add(filter); _runTimeData = null; }}I have I have consulted with the team on your problem and here is the output :
The column filter descriptors hold a reference to a column . When you recreate RadGridView brand new columns appear which are not the same instances with the old ones.
The Filter descriptors still hold the old columns thus the erroneous behavior.
The solution would be to create new filter descriptors based on the values in the old ones , rather than reusing them.
You may see some working code in this online example. Check the code in the cs files for more info .
All the best,
Pavel Pavlov
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
rgvTo.FilterDescriptors.Clear();
foreach(var fd in rgvFrom.FilterDescriptors)
{
if(fd is MemberColumnFilterDescriptor mcfd)
{
var targetColumn = rgvTo.Columns[mcfd.Member];
if(targetColumn != null)
{
var newDescriptor = new MemberColumnFilterDescriptor(targetColumn);
newDescriptor.CopyFrom(mcfd);
rgvTo.FilterDescriptors.Add(newDescriptor);
}
}
}You can find the example linked by Pavel in the WPF Demos application under the name "GridView Serialization".
About your code, this doesn't work because the FilterDescriptors collection is not automatically synced with the ColumnFilterDescriptor of the column. The synchronization happens only in the opposite direction - ColumnFilterDescritpro --> FilterDescriptors collection.
To make this work you can copy the filter descriptor in the ColumnFilterDescriptor of the target column.
if(fd is MemberColumnFilterDescriptor mcfd)
{
var targetColumn = rgvTo.Columns[mcfd.Member];
if(targetColumn != null)
{
targetColumn.ColumnFilterDescriptor.CopyFrom(mcfd);
}
}But how can the various fields in the associated dialog be set for column filters, which are of the MemberColumnFilterDescriptor type? In other words, which elements are checked, which two operators apply, which operator is used to link them, and which value should be used for the comparison. There are no explicit properties for this in the class.
The code snippet below shows what the CopyFrom method does. These are basically the properties which can be used to get and set the filter operators and values. The order in the code even matches the order in the UI of the FilteringControl. To get the distinct vaues, you can use the filter.DistinctFilter.DistinctValues property, which is not shown in the snippet.
public static void CopyFrom(this IColumnFilterDescriptor target, IColumnFilterDescriptor source)
{
foreach (var dv in source.DistinctFilter.DistinctValues)
{
target.DistinctFilter.AddDistinctValue(dv);
}
target.FieldFilter.Filter1.Operator = source.FieldFilter.Filter1.Operator;
target.FieldFilter.Filter1.Value = source.FieldFilter.Filter1.Value;
target.FieldFilter.Filter1.IsCaseSensitive = source.FieldFilter.Filter1.IsCaseSensitive;
target.FieldFilter.LogicalOperator = source.FieldFilter.LogicalOperator;
target.FieldFilter.Filter2.Operator = source.FieldFilter.Filter2.Operator;
target.FieldFilter.Filter2.Value = source.FieldFilter.Filter2.Value;
target.FieldFilter.Filter2.IsCaseSensitive = source.FieldFilter.Filter2.IsCaseSensitive;
}Oh, yes. I forgot to mention this. Sorry about that.
The base class (ColumnFilterDescriptor) of the MemberColumnFilterDescriptor implements the IColumnFilterDescriptor interface explicitly, which makes the interface members hidden from the derived class. To access these you will need to cast the MemberColumnFilterDescriptor to IColumnFilterDescriptor.
var filterDescriptor = (IColumnFilterDescriptor)mcfd;That fixed it and it's working great now.