Execute a Query of a Feature Layer from within a ProWindow

715
5
Jump to solution
07-06-2022 05:38 PM
RichardFairhurst
MVP Honored Contributor

I am trying to run a query on a FeatureLayer in the Active Map through a button in a ProWindow, but either the code throws a Thread Exception if I try to perform a Search on the Layer outside of an async/await block or it skips over the code inside the await portion.

Here is the code I have and I have tried it with and without the async/await code:

        private async void Locate_Click(object sender, RoutedEventArgs e)
        {
            String layerName = "Search PLUS Cases";
            var fLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name.Equals(layerName));
            if (fLayer != null)
            {
                if (this.TbxPLUSCase.Text != null && this.TbxPLUSCase.Text != "")
                {
                    Dictionary<long, string> RoadDict = new Dictionary<long, string>();
                    string whereClause = "CASE_ID = '" + this.TbxPLUSCase.Text.ToUpper() + "'";
                    QueryFilter qf = new QueryFilter();
                    qf.WhereClause = whereClause;
                    await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
                    {
                        using (ArcGIS.Core.Data.Table PLUSTable = fLayer.GetTable())
                        {
                            using (RowCursor rowCursor = PLUSTable.Search(qf))
                            {
                                while (rowCursor.MoveNext())
                                {
                                    using (ArcGIS.Core.Data.Row row = rowCursor.Current)
                                    {
                                        string dictvalue = row["CASE_ID"].ToString();
                                        long v = Convert.ToInt64(row["objectid"].ToString());
                                        RoadDict[v] = dictvalue;
                                    };
                                }
                            }
                        }
                    });
                }

            }
            this.Close();
        }
Tags (3)
0 Kudos
1 Solution

Accepted Solutions
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I used your sample code (with a different dataset) and it worked fine.   Here's my code:

    private async void Test_Click(object sender, RoutedEventArgs e)
    {

      String layerName = "TestPoints";
      var fLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name.Equals(layerName));
      if (fLayer != null)
      {
        if (this.TbxPLUSCase.Text != null && this.TbxPLUSCase.Text != "")
        {
          Dictionary<long, string> RoadDict = new Dictionary<long, string>();
          string whereClause = "TheString = '" + this.TbxPLUSCase.Text.ToUpper() + "'";
          QueryFilter qf = new QueryFilter();
          qf.WhereClause = whereClause;
          var iCount = await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
          {
            var cnt = 0;
            using (ArcGIS.Core.Data.Table PLUSTable = fLayer.GetTable())
            {
              using (RowCursor rowCursor = PLUSTable.Search(qf))
              {
                while (rowCursor.MoveNext())
                {
                  using (ArcGIS.Core.Data.Row row = rowCursor.Current)
                  {
                    string dictvalue = row["TheString"].ToString();
                    long v = Convert.ToInt64(row.GetObjectID().ToString());
                    RoadDict[v] = dictvalue;
                    cnt++;
                  };
                }
              }
            }
            return cnt;
          });
          MessageBox.Show($@"Records found: {iCount}");
        }

      }
      this.Close();
    }

 

You should be able to set a breakpoint inside the action for the QueuedTask.Run and step through the code.  I suggest that you also add a try {} catch {} to get any exceptions that are thrown by your code (i.e. misspelled field names).  

This is what I saw with my sample code running:

Wolf_0-1657205333847.png

 

View solution in original post

0 Kudos
5 Replies
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I used your sample code (with a different dataset) and it worked fine.   Here's my code:

    private async void Test_Click(object sender, RoutedEventArgs e)
    {

      String layerName = "TestPoints";
      var fLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name.Equals(layerName));
      if (fLayer != null)
      {
        if (this.TbxPLUSCase.Text != null && this.TbxPLUSCase.Text != "")
        {
          Dictionary<long, string> RoadDict = new Dictionary<long, string>();
          string whereClause = "TheString = '" + this.TbxPLUSCase.Text.ToUpper() + "'";
          QueryFilter qf = new QueryFilter();
          qf.WhereClause = whereClause;
          var iCount = await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
          {
            var cnt = 0;
            using (ArcGIS.Core.Data.Table PLUSTable = fLayer.GetTable())
            {
              using (RowCursor rowCursor = PLUSTable.Search(qf))
              {
                while (rowCursor.MoveNext())
                {
                  using (ArcGIS.Core.Data.Row row = rowCursor.Current)
                  {
                    string dictvalue = row["TheString"].ToString();
                    long v = Convert.ToInt64(row.GetObjectID().ToString());
                    RoadDict[v] = dictvalue;
                    cnt++;
                  };
                }
              }
            }
            return cnt;
          });
          MessageBox.Show($@"Records found: {iCount}");
        }

      }
      this.Close();
    }

 

You should be able to set a breakpoint inside the action for the QueuedTask.Run and step through the code.  I suggest that you also add a try {} catch {} to get any exceptions that are thrown by your code (i.e. misspelled field names).  

This is what I saw with my sample code running:

Wolf_0-1657205333847.png

 

0 Kudos
RichardFairhurst
MVP Honored Contributor

I made sure my code was fully consistent with the code you used and it worked when I launched the form directly.

However, I think the issue arose due to the fact that I originally was launching the search case ProWindow from another ProWindow where the user chooses a search to launch from several search options using radio buttons.  That was my original design for my ArcObjects Add-In using Windows Forms.  The initial Form also did some map set up validation steps through the Search button prior to launching a given search form.  However, I suspect that approach is creating too many complications in ArcGIS Pro, so I probably need to rethink the search selection part of the add-in.

ProWindowChoices.PNG

Would you recommend that I replace the initial ProWindow shown above with a toolbar that contains a dropdown menu of the search choices and a button that launches the appropriate ProWindow based on the kind of search chosen through the dropdown?

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I would recommend using a Dockpane instead of a ProWindow that works similar to the 'Locate' Dockpane in ArcGIS Pro:

Wolf_0-1657266749982.png

On the top of your search Dockpane i would show a drop down that allows the user to select the type of search they want to perform.  Once the user selects the search method the fields specific to the search are displayed.  After the search completes the found records are displayed in a list below the search query info just like on the ArcGIS Pro locate dockpane.   There are plenty of community samples that do something similar.

I attached a search sample dockpane that looks like this:

Wolf_0-1657273051816.png

However you implement this, i would avoid handing off the UI between different windows or dockpanes.  If you have to implement any type of map manipulation (depending on the user's search option selection) do it within a QueuedTask.Run and await the action.

0 Kudos
RichardFairhurst
MVP Honored Contributor

The Search Forms layouts would have to undergo a huge redesign to fit in a single dockpane.  A Button and combobox in the Quick Access Toolbar is working out great.  The button launches the chosen search option as a modal ProWindow which has control over the application until the user either cancels the search dialog to close it or choses a valid feature or list of features and presses the Locate button, which closes the dialog and displays the features on the map.  The forms do not cover valuable screen area when they are not explicitly requested by the user.  My users are very familiar with how my forms behave in ArcMap and want the same experience in ArcGIS Pro.

I also do not see a benefit of keeping the form available in a dockpane and having to monitor everything the user might do in the project that would force the search in progress to reset itself.  The user is unlikely to know what would trigger a reset and do it without realizing why the search interface reset itself. In fact I don't know all of the possible things a user could do that should trigger a reset and don't want to try to imagine what they are or have to debug them all.

While some of the forms are tall and narrow and would easily work in a dockable window, other forms have to be quite wide to be useful.  I do not think redesigning those dialogs to fit in a single dockable window is really an option.  I also don't want to have to control the width of the dockable window or worry that the user might resize it in a way that would make the form unusable.

Anyway, here are the form designs I am trying to port which may give you a better idea of why I think using separate ProWindows is the best design.  So far, all indications are that I can make that design work now that only one ProWindow is open at a time and I am no longer calling a ProWindow from within another ProWindow.

Search Intersections.PNG

Search APN.PNG

Search APN Address.PNG

Search APN Owner.PNG

Search APN Subdivision.PNG

Search Point Address.PNG

Search Survey Legal.PNG

Search Survey Subdivision.PNG

Search PLUS Cases.PNG

Search Road Book Page.PNG

Search Section Township Range.PNG

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Looking at the complexity of your query forms it looks like the best way would be to use a ProWindow.   You could use the tabcontrol that i showed in my Dockpane sample to put all your search forms into the same ProWindow, but i would definitely recommend switching to an MVVM based ProWindow.  There was a tech session at the 2022 Dev Summit that discussed ProWindow vs. Dockpane and assync processing and that might be helpful to you:  Tech Sessions · Esri/arcgis-pro-sdk Wiki (github.com)  click on "Improving Your Dockpane and ProWindow Design Patterns" in order to get the slides and code samples (in 2.x).  There might even be a video of this session available on YouTube or on Esri Videos: GIS, Events, ArcGIS Products & Industries (search for "Improving Your Dockpane and ProWindow Design Patterns").  As forms get more complex (and your forms definitely fall into that category) MVVM based forms are much easier to maintain.  It's a bit of a leap at first (coming from ArcMap winforms) but it will pay off in the long run. 

0 Kudos