Select to view content in your preferred language

Opening ProWindow within RowCreatedEvent: "This object has been previously disposed and cannot be manipulated"

1523
4
Jump to solution
11-23-2022 02:00 PM
succip
by
Occasional Contributor

Hello,

I've subscribed my layer to a RowCreatedEvent. I'd like to take some user input from a ProWindow dialog and update the new feature's attributes accordingly. Problem is I'm having trouble preventing the RowCreatedEvent from running entirely before the user has input information. Here's my current OnRowCreatedEvent, 

        public static async void OnRowCreated(RowChangedEventArgs args)
        {
            string lotCount = null;
            await Task.Factory.StartNew(() =>
            {
                CreateLotWindow createLotWindow = new CreateLotWindow();
                createLotWindow.Owner = FrameworkApplication.Current.MainWindow;
                var vm = createLotWindow.DataContext as CreateLotWindowViewModel;
                createLotWindow.ShowDialog();
                lotCount = vm.LotCount;
            }, System.Threading.CancellationToken.None, TaskCreationOptions.None, QueuedTask.UIScheduler); // run this sequence on the UI thread

            Row row = args.Row;
            row["LOT_NO"] = lotCount; // update the row information with the userInput
         }

 error.png

1 Solution

Accepted Solutions
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I think the problem is that you can't re-use the EditOperation that is initiating the OnRowCreated event.  Also switching and awaiting threads in a Row event is not really recommended because this can lead to thread deadlocks.

To reiterate your workflow: On a RowCreated event you need to present a user interface that allows the user to manipulate a value that is then used to update a field value in the newly created row.

In order to do this i had to start the ProWindow on the UI thread after the OnRowEvent finished and then use a separate EditOperation to update the newly created row.

I attached my sample project and please note that it is using C:\Data\FeatureTest\FeatureTest.aprx from the Community Sample GitHub page (Esri/arcgis-pro-sdk-community-samples: ArcGIS Pro SDK for Microsoft .NET Framework Community Samples...)

Using the sample add-in i can initiate my event listener using the 'TestChainedUpdate' button:

ChainedUpdate1.png

Creating a new row will trigger the OnRowCreated event, in the event code i remember the object id for the newly created record (for the later update) and initiate the ProWindow ShowDialog on the UI:

protected void OnRowCreated(RowChangedEventArgs rowChanged)
{
  Module1.UpdatedObjectId = rowChanged.Row.GetObjectID();
  ProApp.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
    {
      OpenPrinWindowInfoInput();
    }));
}

All the work is done in  OpenPrinWindowInfoInput which is executed on the UI thread after the row has been created.

Wolf_0-1669911136139.png

Here is the code:

private async void OpenPrinWindowInfoInput ()
{
  // open the dialog, populate initial data to show and process result
  var prowindowinfoinput = new ProWindowInfoInput();
  prowindowinfoinput.Owner = FrameworkApplication.Current.MainWindow;
  var proWinVm = new ProWindowInfoInputVM
  {
    RecordInfo = $@"Created Record's {Module1.UpdatedObjectIdField}: {Module1.UpdatedObjectId}"
  };
  prowindowinfoinput.DataContext = proWinVm;
  prowindowinfoinput.Closed += (o, e) => { System.Diagnostics.Debug.WriteLine("Pro Window Dialog closed"); };
  var dlgResult = prowindowinfoinput.ShowDialog();
  if (dlgResult == true)
  {
    // user click Ok: update the newly created record with info input data
    // load the inspector with the feature
    await QueuedTask.Run(() =>
    {
      var insp = new Inspector();
      insp.Load(_testLayer, Module1.UpdatedObjectId);
      insp[UpdateField] = proWinVm.InfoData;
      //create and execute the edit operation
      var op = new EditOperation
      {
        Name = "Update newly created record",
        SelectModifiedFeatures = false,
        SelectNewFeatures = false
      };
      op.Modify(insp);
      op.Execute();
    });
  }
}

 After i click 'update' in the ProWindow I use Inspector to get the newly created record and update the newly created record in a new EditOperation:

Wolf_1-1669911373226.png

Ideally i would like to use a Chained EditOperation here but i got an error trying to create a chained edit operation.  However, the transaction is on undo/redo stack:

Wolf_2-1669911503893.png

 

View solution in original post

4 Replies
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I think the problem is that you can't re-use the EditOperation that is initiating the OnRowCreated event.  Also switching and awaiting threads in a Row event is not really recommended because this can lead to thread deadlocks.

To reiterate your workflow: On a RowCreated event you need to present a user interface that allows the user to manipulate a value that is then used to update a field value in the newly created row.

In order to do this i had to start the ProWindow on the UI thread after the OnRowEvent finished and then use a separate EditOperation to update the newly created row.

I attached my sample project and please note that it is using C:\Data\FeatureTest\FeatureTest.aprx from the Community Sample GitHub page (Esri/arcgis-pro-sdk-community-samples: ArcGIS Pro SDK for Microsoft .NET Framework Community Samples...)

Using the sample add-in i can initiate my event listener using the 'TestChainedUpdate' button:

ChainedUpdate1.png

Creating a new row will trigger the OnRowCreated event, in the event code i remember the object id for the newly created record (for the later update) and initiate the ProWindow ShowDialog on the UI:

protected void OnRowCreated(RowChangedEventArgs rowChanged)
{
  Module1.UpdatedObjectId = rowChanged.Row.GetObjectID();
  ProApp.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
    {
      OpenPrinWindowInfoInput();
    }));
}

All the work is done in  OpenPrinWindowInfoInput which is executed on the UI thread after the row has been created.

Wolf_0-1669911136139.png

Here is the code:

private async void OpenPrinWindowInfoInput ()
{
  // open the dialog, populate initial data to show and process result
  var prowindowinfoinput = new ProWindowInfoInput();
  prowindowinfoinput.Owner = FrameworkApplication.Current.MainWindow;
  var proWinVm = new ProWindowInfoInputVM
  {
    RecordInfo = $@"Created Record's {Module1.UpdatedObjectIdField}: {Module1.UpdatedObjectId}"
  };
  prowindowinfoinput.DataContext = proWinVm;
  prowindowinfoinput.Closed += (o, e) => { System.Diagnostics.Debug.WriteLine("Pro Window Dialog closed"); };
  var dlgResult = prowindowinfoinput.ShowDialog();
  if (dlgResult == true)
  {
    // user click Ok: update the newly created record with info input data
    // load the inspector with the feature
    await QueuedTask.Run(() =>
    {
      var insp = new Inspector();
      insp.Load(_testLayer, Module1.UpdatedObjectId);
      insp[UpdateField] = proWinVm.InfoData;
      //create and execute the edit operation
      var op = new EditOperation
      {
        Name = "Update newly created record",
        SelectModifiedFeatures = false,
        SelectNewFeatures = false
      };
      op.Modify(insp);
      op.Execute();
    });
  }
}

 After i click 'update' in the ProWindow I use Inspector to get the newly created record and update the newly created record in a new EditOperation:

Wolf_1-1669911373226.png

Ideally i would like to use a Chained EditOperation here but i got an error trying to create a chained edit operation.  However, the transaction is on undo/redo stack:

Wolf_2-1669911503893.png

 

succip
by
Occasional Contributor

Wolf, I've implemented this solution in my workflow and it works as expected! Thanks again for your help. 

0 Kudos
Asimov
by
Regular Contributor

Hello, I'm fairly new to ArcGIS Pro SDK, coming from ArcObjects development.

I have a very similar scenario to work with. I understand that the solution from @Wolf works: what I'd like to accomplish is to be able to cancel the creation altogether if the user is not able to provide valid data for the feature (via the ProWindow).

My ProWindow would act as a custom form to collect and validate the attributes for the feature that's been created essentially, and it would be also useful for attribute updates and other operations involving edited features eventually.

Now, as far as I understand I can try to implement that solution and manage the undo stack programmatically to cancel the initial creation after a validation is not completed. Before going on with this I would like to know if I understood that this is the right way to do what I want and/or if there are alternative (and maybe simpler/cleaner) ways to achieve the cancelation without having to actually create a feature first.

Thanks in advance.

0 Kudos
Asimov
by
Regular Contributor

Following up my own post: I managed to setup a working solution based on @Wolf solution above. It works fine and it does almost everything I need, the only thing that I couldn't manage to work out is the undo stack management. 

I managed to undo the creation operation when the ProWindow is canceled, also removing the entry from the redo stack, which is a very clean solution, but I still have the two entries in the undo stack whenever the operation is succesful. This is not ideal because I don't want the user to undo the last operation, that would lead to undo only the attribute editing and leave the "blank" feature there (which corresponds to the initial creation). @succip, as far as I can understand your scenario was very similar to mine, did you deal with this  issue too?

I briefly tried the chained operation way but, as Wolf said, it doesn't seem to work in this scenario. I had an eureka moment when I removed the editing entry (the one named "Update newly created record" in Wolf's code) from the undo stack, right after the second edit is succesful: it seems to work cause the entry goes away from the stack and you're left with just the create operation there, which is exactly what I want, but it leads to bad things since edited attributes on the feature go away and when you try to undo the remaining operation nothing actually happens.

Any idea on how to deal with this would be really appreciated, thanks in advance.

0 Kudos