Multiple Parameter filters on a FilteredElementCollection using a foreach loop

Multiple Parameter filters on a FilteredElementCollection using a foreach loop

paul.nelsonCDRHK
Participant Participant
403 Views
3 Replies
Message 1 of 4

Multiple Parameter filters on a FilteredElementCollection using a foreach loop

paul.nelsonCDRHK
Participant
Participant

I'm trying to add filters to a list of views, much like the filter on the project browser. Filters are added to a WPF DataGrid with the appropriate parameters stored.  The filtering works but only on the last item on the list, fir example, in the image below, the views should be filtered by view family = Floor Plan, then by scale = 1:50 but only the scale filter is being applied.

viewfilters.PNG

I've tried numerous methods, some of which are commented out in the code below. It seems that the ElementParameterFilter stored in the list of element filters is being redefined on each loop so each ElementFilter stored in the list<ElementFilter> is identical so the LogicalAndFilter isn't functioning?

 

Here's the code:

      // public FilteredElementCollector viewCollector { get; set; }
        public void MakeViewList(UIApplication app, DataGrid data, DataGrid filtergrid, String GroupString)
        {
            Document doc = app.ActiveUIDocument.Document;
            ItemCollection filters = filtergrid.Items;
            FilteredElementCollector vwCollector = new FilteredElementCollector(doc);
            vwCollector.OfClass(typeof(View)).Cast<View>();
            List<ElementFilter> epf = new List<ElementFilter>();
      //     if ((viewCollector == null))
       //         {
       //     }
       //     else
       //     {
       //         vwCollector = viewCollector;
       //     }
           // IList<View> views = vwCollector.ToList<View>();
          //  views.Clear();
         //   foreach (View view in vwCollector)
         //   {
          //      views.Add(view);
         //   }
            
           // IList<Element> views = vwCollector.ToElements() as IList<Element>;
               if (filters.Count > 0)
                {
                    int i = 0;
                    foreach (FilterGrid fg in filters)
                    {
                    
                        if (fg.FilterBy != null)
                        {
                            Parameter bp = fg.parameter as Parameter;
                        string pName = bp.Definition.Name;
                            switch (bp.StorageType)
                            {
                                case StorageType.String:
                                    {
                                    ParameterValueProvider bpvp = new ParameterValueProvider(bp.Id);
                                    FilterStringRuleEvaluator fnrv = new FilterStringEquals();
                                    FilterRule fRule = new FilterStringRule(bpvp, fnrv, bp.AsString(), false);
                                    ElementParameterFilter efilter = new ElementParameterFilter(fRule);
                                    FilteredElementCollector excl = vwCollector.WherePasses(efilter);
                                    if (fg.Operation == "Equals")
                                    {
                                        vwCollector.WherePasses(efilter);
                                    }
                                    else if (fg.Operation == "Not Equal to")
                                    {
                                        vwCollector.Excluding(excl.ToElementIds());
                                    }
                                    epf.Add(efilter);
                                        break;
                                    }
                                case StorageType.Integer:
                                    {
                                    ParameterValueProvider bpvp = new ParameterValueProvider(bp.Id);
                                    FilterNumericRuleEvaluator fnrv = new FilterNumericEquals();
                                    FilterRule fRule = new  FilterIntegerRule(bpvp, fnrv, bp.AsInteger());
                                    ElementParameterFilter efilter = new ElementParameterFilter(fRule);
                                    FilteredElementCollector excl = vwCollector.WherePasses(efilter);
                                     epf.Add(efilter);
                                      if (fg.Operation == "Equals")
                                      {
                                          vwCollector.WherePasses(efilter).ToElements();
                                      }
                                      else if (fg.Operation == "Not Equal to")
                                      {
                                           vwCollector.Excluding(excl.ToElementIds());
                                      }
                                    break;
                                    }
                                case StorageType.Double:
                                    {
                                        ParameterValueProvider bpvp = new ParameterValueProvider(bp.Id);
                                        FilterNumericRuleEvaluator fnrv = new FilterNumericEquals();
                                        FilterRule fRule = new FilterDoubleRule(bpvp, fnrv, bp.AsDouble(), 1E-6);
                                    ElementParameterFilter efilter = new ElementParameterFilter(fRule);
                                    FilteredElementCollector excl = vwCollector.WherePasses(efilter);
                                    epf.Add(efilter);
                                        if (fg.Operation == "Equals")
                                        {
                                        vwCollector.WherePasses(efilter).ToElements();
                                    }
                                        else if (fg.Operation == "Not Equal to")
                                        {
                                         vwCollector.Excluding(excl.ToElementIds());
                                    }
                                        break;
                                    }
                                case StorageType.ElementId:
                                    {
                                    ParameterValueProvider bpvp = new ParameterValueProvider(bp.Id);
                                    FilterNumericRuleEvaluator fnrv = new FilterNumericEquals();
                                    FilterRule fRule = new FilterElementIdRule(bpvp, fnrv, bp.AsElementId());
                                    ElementParameterFilter efilter = new ElementParameterFilter(fRule);
                                    FilteredElementCollector excl = vwCollector.WherePasses(efilter);
                                    MessageBox.Show("efilter = " + efilter.GetRules().ToString());
                                    epf.Add(efilter);
                                        if (fg.Operation == "Equals")
                                        {
                                        vwCollector.WherePasses(efilter);
                                    }
                                        else if (fg.Operation == "Not Equal to")
                                        {
                                         vwCollector.Excluding(excl.ToElementIds());
                                    } 
                          //           IEditableCollectionView editableCollection = vwCollector as IEditableCollectionView;
                          //          editableCollection.EditItem
                          //              vwCollector.
                                    // vwCollector = vwCollector.WherePasses(elementfilter);
                                    break;
                                    }
                 //   if (fg.Operation == "Equals")
                  //  {
                        //views = views.Where(v => v.LookupParameter(pName).AsString() == bp.AsString()) as IList<View>;
                  //      vwCollector.WherePasses(efilter);
                        // views = views.Where(e => e.GetParameters(bp.Definition.Name.ToString()).First<Parameter>().AsString() == bp.AsString()) as IList<Element>;
                  //  }
                  //  else if (fg.Operation == "Not Equal to")
                  //  {
                        //views = views.Where(v => v.LookupParameter(pName).AsString() != bp.AsString()) as IList<View>;
                 //       vwCollector.Excluding(excl.ToElementIds());
                        //views = views.Where(e => e.GetParameters(bp.Definition.Name.ToString()).First<Parameter>().AsString() != bp.AsString()) as IList<Element>;
                  //  }
                    // lf.GetFilters().Add(stringfilter);
                  //  epf.Add(efilter);

                    //viewCollector = vwCollector;
                }


                //    }
                //    else
                //    {
                //    FilterStringRuleEvaluator fnrv = new FilterStringLess();
                //    }

                // vwCollector.Excluding(filter);
            }
                    }
             /*   if (epf.Count > 0)
                {
             //       ElementFilter dummyFilter = new ElementFilter();
                    LogicalAndFilter lf = new LogicalAndFilter(epf);
                    lf.GetFilters().Clear();
                     foreach (ElementParameterFilter ef in epf)
                      {
                             lf.GetFilters().Add(ef);
                        }
                   vwCollector.WherePasses(lf);
                } */
            }
            if (epf.Count > 0)
            {
                LogicalAndFilter lf = new LogicalAndFilter(epf);
                vwCollector.WherePasses(lf);
            }

            ObservableCollection<ViewListStructure> ViewCollection = new ObservableCollection<ViewListStructure>();
            List<Autodesk.Revit.DB.ElementId> vos = ViewsOnSheets(app) as List<Autodesk.Revit.DB.ElementId>;
            foreach (View v in vwCollector)
            {
                //View v = e as View;
...make view list
            )

The data structure for the filters is:

       public struct FilterGrid
        {
            public string FilterBy { get; set; }
            public string Operation { get; set; }
            public string FilterValue { get; set; }
            public object parameter { get; set; }
        }
        public void AddViewFilter(string param, string op, string valueparam, DataGrid data, object paramobj)
        {
            foreach (FilterGrid fg in data.Items)
            {
                FilterGrids.Add(new FilterGrid() { FilterBy = fg.FilterBy, Operation = fg.Operation, FilterValue = fg.FilterValue, parameter = paramobj });
            }
            FilterGrids.Add(new FilterGrid() { FilterBy = param, Operation = op, FilterValue = valueparam, parameter = paramobj });
            data.ItemsSource = FilterGrids;
        }

Also, what is the best practice for filtering Parameter != Value?

Accepted solutions (1)
404 Views
3 Replies
Replies (3)
Message 2 of 4

jeremy_tammik
Alumni
Alumni
Accepted solution

Sorry, Paul, I am a bit like Pooh, just a "bear of very little brain". I don't understand your code off-hand. Can you simplify it, or be more specific in your question? Or, more generic. Both would help understand me better what you actually need, and what the problem is.

  

I can at least say that you can definitely add as many filters as you like to a filtered element collector. There is no known limit. Just be clear that the collector is initialised once only, and every filter you adds limits the results further still. So, with two mutually exclusive filters, you get zero result elements.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 4

paul.nelsonCDRHK
Participant
Participant

I tracked down the bug. Nothing to do with Element Parameter Filters but a silly schoolboy error on my part in the code that adds filter criteria to the filter list. The data grid data source is reconstructed from the values in the WPF form plus the value added and includes a hidden column that contains the parameter to filter the view list on. I was using the new parameter value instead of the one stored in the data grid.

Bug.PNG

I replaced the element parameter filters with a brute force method (loop all views and if the corresponding parameter matches the filter, add/remove as appropriate) before finding the bug and would be interested on opinions as to whether using element parameter filters <where passes> would be more efficient.

0 Likes
Message 4 of 4

paul.nelsonCDRHK
Participant
Participant

Hi Jeremey, Thanks for your quick reply. The app has a couple of WPF data grids, one is to hold the filter criteria and the other a filtered list of views. The first part iterates through filter criteria data grid rows and for each parameter to filter, constructs a filter rule and adds it to a list of rules to pass to a logical and filter. It looks complicated because the switch statement is needed to operate on specific storage types

 

What was happening is that only the last filter in the list was being processed but that was because of an error in the way the filter list was being constructed- every row was being passed the last parameter. You've answered the question as to Element Parameter Filters being more efficient then looping a whole element set to match parameter values. it's a complicated app but here's some simplified pseudo code if you're interested:-

//add item to filter criteria:-
//FilterGrid is a struct that the datageid is bount to
//columns - param to filter by | equals/not | value | Hidden column param obj 
public void AddViewFilter( string param, 
                           string op, 
                           string value, 
                           DataGrid data, 
                           object paramobj)
//rewrite the datasource from WPF datagrid on the dockablepane
            foreach (FilterGrid fg in data.Items)
            {
                FilterGrids.Add(new FilterGrid() 
             { FilterBy = fg.FilterBy, 
               Operation = fg.Operation, 
               FilterValue = fg.FilterValue, 
               parameter = fg.parameter }); // this is where the bug was
                                            // so all rows had the param 
                                            // objectbeing added
            }
// add the new filter
            FilterGrids.Add(new FilterGrid() 
           { FilterBy = param, 
             Operation = op, 
             FilterValue = valueparam, 
             parameter = paramobj });
//update the data source for the filter data grid
            data.ItemsSource = FilterGrids;

The datagrid for displaying the views is updated every time a row is added or removed from the filter list

// pass the view datagrid and filter datagrid to the function
//parameters and grouping strings are stored in in hidden columns instead of // global variables
       public void MakeViewList(UIApplication app, DataGrid data, DataGrid filtergrid, String GroupString)
        {
        Document doc = app.ActiveUIDocument.Document; 
        ItemCollection filters = filtergrid.Items; // list of filter ops
//get all the views
        FilteredElementCollector vwCollector 
            = new FilteredElementCollector(doc);
            vwCollector.OfClass(typeof(View)).Cast<View>();
// declare a list for element filters
            List<ElementFilter> ElemFilterList = new List<ElementFilter>();

            if (filters.Count > 0) //if there are filter operation
            {
                foreach (FilterGrid fg in FilterGrids.ToList())
                {
                 Parameter p = fg.Parameter // the param from hidden filter 
                                            //column
   //get filter parameter storage type and switch
                switch (p.storageType)
                {
                  Case StoreageType.String
                  {          //make a string filter
                   ParameterValueProvider pvp 
                      = new ParameterValueProvider(bp.Id);
                   FilterStringRuleEvaluator fsreval 
                      = new FilterStringEquals();
                   FilterRule filterrule
                      = new FilterStringRule(pvp, fsreval, 
                                              bp.AsString(), false);
                   ElementParameterFilter epfilter 
                     = new ElementParameterFilter(filterrule);
// add ElementParameter Filter to pass to LogicalAndEvaluator
                   ElemFilterList.Add(epfilter)
// add cases for storage types Interger, Double and ElementId
                ...
                }
           }
           if (ElemFilterList.Count() > 0)
             {
              LogicalAndFilter laf = new LogicalAndFilter(ElemFilterList)
              vwCollector.WherePasses(lf);
             }
           ObservableCollection<ViewListStructure> ViewCollection = new ObservableCollection<ViewListStructure>();
            List<Autodesk.Revit.DB.ElementId> vos = ViewsOnSheets(app) as List<Autodesk.Revit.DB.ElementId>;
                foreach (View v in vwCollector)
                {
                string GroupTitle = "";
                if (v != null)
                {
                    ElementId vid = v.Id;
                    string vidString = "";
                    string vTitle = "";
                    string vScale = "";
// discards views on sheets in a sparate list and unwanted view types
                    if ((vos.Contains(vid) == false)
                            && (v.ViewType != ViewType.Legend)
                            && (v.ViewType != ViewType.DrawingSheet)
                            && (v.ViewType != ViewType.Internal)
                            && (v.ViewType != ViewType.ProjectBrowser)
                            && (v.ViewType != ViewType.Undefined)
                            && (v.Name.Contains("<Revision") == false)
                            && (v.Name != "")
                            && (v.Name != " ")
                            && (v.Name.Length > 2)
                            && (v.Name.Contains("System Browser") == false)
                            && (v.IsTemplate == false)
                        )
                    {
                     ... sort out grouping etc.
              // populate the View datagrid (some columns are hidden)
                        ViewCollection.Add((new ViewListStructure() 
                        { GroupName = GroupTitle,  
                          ViewId = vid, 
                          ViewSelected = false, 
                          ViewName = vTitle, 
                          ViewScale = vScale }));
                    }
                }
            }
            data.ItemsSource = ViewCollection;
      // apply grouping to view datagrid
            ICollectionView cvTasks 
              = CollectionViewSource.GetDefaultView(data.ItemsSource);
            cvTasks.SortDescriptions.Add
              (new SortDescription("GroupName", 
                                    ListSortDirection.Ascending));
            if (cvTasks != null && cvTasks.CanGroup == true)
            {
                cvTasks.GroupDescriptions.Clear();
                cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("GroupName"));
            }
            data.Items.Refresh();
            data.UpdateLayout();
            data.VerticalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Visible;  
 
        }

 

 

0 Likes