I would like my xamdatagrid to show filter options only on the header row of the top band. The dropdown for the filter values should list all values in the column, even though there are multiple bands in the column. Then, the selected value would filter all records across bands. Is this possible?
I have played with these attributes, but cannot get exactly what i desire.
<
DataPresenter:XamDataGrid.FieldLayoutSettings><DataPresenter:FieldLayoutSettings ExpansionIndicatorDisplayMode="CheckOnExpand" FilterUIType="FilterRecord" FilterRecordLocation="OnTopFixed" RecordFilterScope ="AllRecords"
I uploaded a snapshot, but I cut out the data.
Hello,
You would have to allow filtering only on the top FieldLayout. Using the XamDataGrid.FieldLayoutSettings will allow filtering on all of the layouts therefore you have to use the FieldLayout.Settings property.
Let me know if you have questions on this.
That makes sense. we are turning the filter on/off based upon user click and were were binding to the setting as follows:
var binding = new Binding{ Path = new PropertyPath("FieldSettings.AllowRecordFiltering"), Converter = new NullableBooleanConvertor(), Mode = BindingMode.TwoWay }; I think we will have to write code to get at the top fieldlayout.
var binding = new Binding{
Path = new PropertyPath("FieldSettings.AllowRecordFiltering"),
Converter = new NullableBooleanConvertor(),
Mode = BindingMode.TwoWay
};
I think we will have to write code to get at the top fieldlayout.
Setting it in code only loads the top row with values from that band. It does not collect data from the other bands. I really want this to work like Excel with subtotals activated. In that scenario, all values appear in the filter list. Thanks.
public static void SwitchFilter(XamDataGrid grid) {
if (grid.FieldLayouts == null || grid.FieldLayouts.Count == 0) return;
grid.FieldLayouts[0].FieldSettings.AllowRecordFiltering =
!(grid.FieldLayouts[0].FieldSettings.AllowRecordFiltering ?? false);
}
I have taken a different approach and I need a little help with applying the filter. Again, I am trying to filter all values in the grid column, allowing the parent record to stay visible when a child record matches a filter.
Here is how I am successfully loading the filter drop down. The event handler and the recursive routine do the job. But the magic that happens after is where I am struggling. See below.
private void xdGrid_RecordFilterDropDownPopulating( object sender, RecordFilterDropDownPopulatingEventArgs e) { e.IncludeUniqueValues = true; var comparer = e.Field.FilterOperatorDefaultValueResolved; var viewModel = ViewModel; var collection = viewModel.BindableAffiliation; var list = new List<string>(); foreach (var child in collection.SelectMany(item => item.ChildAffiliation)) list.AddRange(GetChildField(child, e.Field.Name)); foreach (var item in list) e.DropDownItems.Add(new FilterDropDownItem(new ComparisonCondition(comparer, item), item)); e.Handled = true; } private static IEnumerable<string> GetChildField(BusinessAffiliateEditObject businessAffiliate, string fieldName) { object container = businessAffiliate; var list = new List<string> { (ObjectHelper.GetPropertyValue(ref container, fieldName) ?? string.Empty).ToString() }; if (businessAffiliate.ChildAffiliation != null) foreach (var child in businessAffiliate.ChildAffiliation) list.AddRange(GetChildField(child, fieldName)); return list; }
private void xdGrid_RecordFilterDropDownPopulating(
object sender, RecordFilterDropDownPopulatingEventArgs e)
{
e.IncludeUniqueValues = true;
var comparer = e.Field.FilterOperatorDefaultValueResolved;
var viewModel = ViewModel;
var collection = viewModel.BindableAffiliation;
var list = new List<string>();
foreach (var child in collection.SelectMany(item => item.ChildAffiliation))
list.AddRange(GetChildField(child, e.Field.Name));
foreach (var item in list)
e.DropDownItems.Add(new FilterDropDownItem(new ComparisonCondition(comparer, item), item));
e.Handled = true;
private static IEnumerable<string> GetChildField(BusinessAffiliateEditObject businessAffiliate, string fieldName)
object container = businessAffiliate;
var list = new List<string>
{ (ObjectHelper.GetPropertyValue(ref container, fieldName) ?? string.Empty).ToString() };
if (businessAffiliate.ChildAffiliation != null)
foreach (var child in businessAffiliate.ChildAffiliation)
list.AddRange(GetChildField(child, fieldName));
return list;
Applying filter: Here is where things get a little hairy. I have tried so many different ways to get at the datarecords in child bands. Nothing I try seems to work and even when I can get at the datarecords, the filter.MeetsCriteria often returns true when it should return false.
private void xdGrid_RecordFilterChanging(object sender, RecordFilterChangingEventArgs e)
foreach (var fieldLayout in xdGrid.FieldLayouts)
ClearExistingFilterConditions(fieldLayout);
SetRowVisibility(xdGrid.RecordManager.DataPresenter.Records, e.NewRecordFilter);
e.NewRecordFilter.Conditions.Clear();
private static void ClearExistingFilterConditions(FieldLayout fieldLayout)
if (fieldLayout.RecordFilters != null && fieldLayout.RecordFilters.Count > 0)
foreach (var recordFilter in fieldLayout
.RecordFilters
.Where(recordFilter => recordFilter.Conditions != null
&& recordFilter.Conditions.Count > 0))
recordFilter.Conditions.Clear();
private static void SetRowVisibility(IEnumerable<Record> records, RecordFilter filter)
foreach(var record in records)
var dataRecord = record as DataRecord;
if (dataRecord == null) continue;
var criteriaMet = filter.MeetsCriteria(dataRecord);
if (criteriaMet || (record.HasChildren &&
ChildMeetsCriteria(dataRecord.ViewableChildRecords, filter)))
record.Visibility = Visibility.Visible;
SetRowVisibility(dataRecord.ViewableChildRecords, filter);
else
record.Visibility = Visibility.Hidden;
private static bool ChildMeetsCriteria(IEnumerable<Record> records, RecordFilter filter)
return (from ExpandableFieldRecord expandableFieldRecord in records
select expandableFieldRecord
.ViewableChildRecords
.OfType<DataRecord>()
.Any(dataRecord =>
filter.MeetsCriteria(dataRecord)
|| (dataRecord.HasChildren
&& ChildMeetsCriteria(dataRecord.ViewableChildRecords, filter))))
.FirstOrDefault();
I have an acceptable solution. The only thing that I haven't allow is applying 'and' conditions between column filters. For now, each column is an overriding filter, but that is ok for this scenario.
Here are the changes:
1) DropDown Filter List: Grab only unique values
list.Where(x => !x.IsNullOrEmpty()).Distinct().ToList()
2) Accessing Records: _grid.RecordManager.Unsorted
The key here was that each expandable record.ChildRecords collection does not return the child band data, but rather the data record wrapped by the expandable control. So, while iterating the records, I added a recursive call to get the actual child records. if (record is ExpandableFieldRecord) { SetRowVisibility(GetChildRecords(record), filter); continue; } 3) filter.MeetsCriteria: using reflection, you cannot use this method on a single filter across field layouts. You will see this in the meets critieria routine: if ((field != null) && (field.Owner == record.FieldLayout)) { . . . } return true; To avoid this problem, you can change the field property of the filter at runtime:
if (record is ExpandableFieldRecord) {
SetRowVisibility(GetChildRecords(record), filter);
continue; }
3) filter.MeetsCriteria: using reflection, you cannot use this method on a single filter across field layouts. You will see this in the meets critieria routine: if ((field != null) && (field.Owner == record.FieldLayout)) { . . . } return true; To avoid this problem, you can change the field property of the filter at runtime:
if ((field != null) && (field.Owner == record.FieldLayout)) { . . . } return true;
if ((field != null) && (field.Owner == record.FieldLayout))
{ . . . }
return true;
To avoid this problem, you can change the field property of the filter at runtime:
filter.Field = record.FieldLayout.Fields[filter.FieldName]; return filter.MeetsCriteria(record);
filter.Field = record.FieldLayout.Fields[filter.FieldName];
return filter.MeetsCriteria(record);