Bug in EditGeometry Class when moving polygons and polylines

3215
4
03-14-2012 03:55 AM
Labels (1)
KevinSayer
New Contributor III
There seems to be a bug in the EditGeometry class and I thought I'd post my findings on here to see if anyone else has experienced this problem and whether there may be some kind of work around.

The problem is that when moving a polygon or polyline, if you move it back over exactly the same position it was in when the edit started, it automatically cancels the edit. This happens because points in the original geometry are being updated. As Jennifer has pointed out in other threads, canceling the edit as a result of updating the original geometry is by design but the question is, why is the original geometry getting updated? This is happening inside the EditGeometry class and isn't related to my use of the class as it happens in simple, stripped down examples, including those that Jennifer has posted herself. (See the post dated 01-09-2012 04:17pm in this thread.) I'd suggest lining the vertices of the polygon up with the edge of the window before starting the move so that it's easier to return to the exact starting location.

Below is the call stack from inside the GeometryEdited handler after the Cancel occurs:

> EsriEditing.exe!EsriEditing.MainWindow.mEditGeometry_GeometryEdit(object sender, ESRI.ArcGIS.Client.EditGeometry.GeometryEditEventArgs e) Line 83 C#
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.OnGeometryEdit(ESRI.ArcGIS.Client.Graphic g, ESRI.ArcGIS.Client.Geometry.MapPoint newItem, ESRI.ArcGIS.Client.Geometry.MapPoint oldItem, ESRI.ArcGIS.Client.EditGeometry.Action action) + 0x5f bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.StopEdit(bool deletingVertex, bool cancelEdit) + 0x227 bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.CancelEdit() + 0x21 bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.OriginalGeometry_GeometryChanged(object sender, System.EventArgs e) + 0x63 bytes
[Native to Managed Transition]
[Managed to Native Transition]
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.Geometry.Geometry.raiseGeometryChanged() + 0x4f bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.Geometry.Polygon.coll_PointChanged(object sender, System.EventArgs e) + 0x4f bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.Geometry.PointCollection.raisePointChanged() + 0x57 bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.Geometry.PointCollection.point_GeometryChanged(object sender, System.EventArgs e) + 0x60 bytes
[Native to Managed Transition]
[Managed to Native Transition]
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.Geometry.Geometry.raiseGeometryChanged() + 0x4f bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.Geometry.MapPoint.Y.set(double value) + 0x53 bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.Offset(ESRI.ArcGIS.Client.Geometry.MapPoint p, double dx, double dy) + 0x69 bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.Offset(ESRI.ArcGIS.Client.Geometry.PointCollection pnts, double dx, double dy) + 0x7c bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.Offset(System.Collections.Generic.IEnumerable<ESRI.ArcGIS.Client.Geometry.PointCollection> pntsColl, double dx, double dy) + 0x7b bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.Offset(ESRI.ArcGIS.Client.Geometry.Geometry g, double dx, double dy) + 0x5c bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.HandleElementMove(System.Windows.Point screenPoint, ESRI.ArcGIS.Client.Geometry.MapPoint mapPoint) + 0x17e bytes
ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.Map_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) + 0x10c bytes
PresentationCore.dll!System.Windows.Input.MouseEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x34 bytes
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x27 bytes
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x3e bytes
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1bf bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) + 0x79 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x35 bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x311 bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x42 bytes
PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) + 0x62 bytes
PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawMouseActions actions, int x, int y, int wheel) + 0x2e2 bytes
PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.FilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0x22b bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.InputFilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0x75 bytes
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0xbe bytes
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) + 0x7a bytes
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, bool isSingleParameter) + 0x8a bytes
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, bool isSingleParameter, System.Delegate catchHandler) + 0x4a bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.WrappedInvoke(System.Delegate callback, object args, bool isSingleParameter, System.Delegate catchHandler) + 0x44 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, bool isSingleParameter) + 0x91 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority priority, System.Delegate method, object arg) + 0x40 bytes
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) + 0xdc bytes
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0xc4 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() + 0x4c bytes
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) + 0x1e bytes
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) + 0x6f bytes
PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) + 0x26 bytes
PresentationFramework.dll!System.Windows.Application.Run() + 0x19 bytes
EsriEditing.exe!EsriEditing.App.Main() + 0x5e bytes C#
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x3a bytes
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x66 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes

Hopefully you will see this Jennifer and can either confirm the bug or explain the behaviour.

Regards,
Kevin
0 Kudos
4 Replies
JenniferNery
Esri Regular Contributor
It's seems impossible to move the graphic geometry back to its original location to cause a cancel. But based on the stack trace, the OriginalGeometry raised a GeometryChanged event that it was updated outside the EditGeometry. This may have been caused by changing the geometry in code (application): If you add/remove/update PointCollection or X/Y values. Or it may also be caused by existing bug that is triggered by cloning geometries. We have a fix for this in our next release.
0 Kudos
KevinSayer
New Contributor III
Hi Jennifer,

Thanks for your reply.  I forgot to mention versions, so to clarify, we're currently using version 2.4, although this problem also existed in version 2.3.  I guess when you say that it might be fixed in the next version, you're referring to version 3.0?  Do you have any idea when that might be released?

Just out of interest, attached (at the bottom) is a zip file containing a small VS2010 project  for a really simple application that puts a square on the map and doesn't even bother attaching to the geometry changed handler.  As you can see, there's absolutely no application code fiddling with the original geometry.

The best repro is to run this and then pan the map so that the square is lined up with the edges of the button and window as show in the screen shot below.

[ATTACH=CONFIG]12716[/ATTACH]

Now press the button and move the two vertices of the square so it looks like the following screen shot.

[ATTACH=CONFIG]12717[/ATTACH]

Now move the shape away from the corner and then slowly back again so that the top left corner is exactly where it started.  You might have to hover around the corner a little before you get it in exactly the same place.  You'll know when you do however as the shape suddenly reverts back to a square and it comes out of edit mode. This is all obviously due to the edit being cancelled becaue it thinks you've changed the original geometry.

Hopefully this is indeed the same bug that you mentioned will be fixed in the next release.

This leads me on to another, possibly related issue however:

There appears to be a bug in the EditGeometry class which causes a NullReferenceException and crashes our application.  This is obviously a little more serious from our perspective, and is also reproducible from the same application as above.

The crash happens whilst in edit mode and moving a vertex over another existing vertex.  You might have to be quite patient to reproduce this in this little application as just grabbing a vertex and waving it over another will not suffice.  You need to hover over another vertex and keep slowly moving the mouse around.  Even then it might take some time before it happens.  This might sound a little contrived but the fact is, it happens much more readily in our main application in which just dragging a point reasonably quickly across another will usually suffice.  This leads me to suspect that it's probably thread related and more possibly down to garbage collection and the use of weak references in the drawing code. The call stack at the end of this post results from this when breaking on first chance exceptions.  Hopefully this might give some indication as to what is going on.

If you can't get it to occur, a slightly more involved but possible more consistent repro is:

1> Edit the square and drag one of the corners into the centre so that it looks like the following.
[ATTACH=CONFIG]12718[/ATTACH]

2> Add a new vertex so it looks like the following and then come out of edit mode by clicking on the shape.
[ATTACH=CONFIG]12719[/ATTACH]

3> Enter edit mode again and drag the new vertex added in step 2 slowly over the corner that you dragged to the centre in step 1.
4> Continue hovering over the other vertex, slowly moving the mouse around and the exception will ususall occur within a couple of seconds.

Again, this might sound quite contrived but in our application it generally happens much easier than this.  Below is the stack trace when this exception is raised. Hope this is enough information and you have time to take a look at this.

Regards,
Kevin


> ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.UpdateVertexPosition(ESRI.ArcGIS.Client.Geometry.MapPoint pnt, bool isTransformPoint) + 0x838 bytes
  ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.HandleElementMove(System.Windows.Point screenPoint, ESRI.ArcGIS.Client.Geometry.MapPoint mapPoint) + 0x29a bytes
  ESRI.ArcGIS.Client.dll!ESRI.ArcGIS.Client.EditGeometry.Map_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) + 0x10c bytes
  PresentationCore.dll!System.Windows.Input.MouseEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x34 bytes
  PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x27 bytes
  PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x3e bytes
  PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1bf bytes
  PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) + 0x79 bytes
  PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x35 bytes
  PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x311 bytes
  PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x42 bytes
  PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) + 0x62 bytes
  PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawMouseActions actions, int x, int y, int wheel) + 0x2e2 bytes
  PresentationCore.dll!System.Windows.Interop.HwndMouseInputProvider.FilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0x22b bytes
  PresentationCore.dll!System.Windows.Interop.HwndSource.InputFilterMessage(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0x75 bytes
  WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0xbe bytes
  WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) + 0x7a bytes
  WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, bool isSingleParameter) + 0x8a bytes
  WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, bool isSingleParameter, System.Delegate catchHandler) + 0x4a bytes
  WindowsBase.dll!System.Windows.Threading.Dispatcher.WrappedInvoke(System.Delegate callback, object args, bool isSingleParameter, System.Delegate catchHandler) + 0x44 bytes
  WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, bool isSingleParameter) + 0x91 bytes
  WindowsBase.dll!System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority priority, System.Delegate method, object arg) + 0x40 bytes
  WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) + 0xdc bytes
  [Native to Managed Transition]
  [Managed to Native Transition]
  WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0xc4 bytes
  WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes
  WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() + 0x4c bytes
  PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) + 0x1e bytes
  PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) + 0x6f bytes
  PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) + 0x26 bytes
  PresentationFramework.dll!System.Windows.Application.Run() + 0x19 bytes
  EsriEditing.exe!EsriEditing.App.Main() + 0x5e bytes C#
  [Native to Managed Transition]
  [Managed to Native Transition]
  mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x3a bytes
  Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b bytes
  mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x66 bytes
  mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes
  mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes
0 Kudos
Hwee_KiangSim
New Contributor
Hi Kevin,
I have the same NullReferenceException problem as you as you would have read from my post. I would like to share with you what I did.
The following codes will help to catch the exception and not let the application crash. But of course the root of the problem still lies with the dll itself which only ESRI can solve. Heres what I did:

In App.xaml, the registration of the event handler is initialized
<Application x:Class="UnhandledExceptionHandler.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml"
    Startup="Application_Startup"
   DispatcherUnhandledException="Application_DispatcherUnhandledException">
    <Application.Resources>
        
    </Application.Resources>
</Application>


A method is added to App.xaml.cs which will handle this event. This is where the exception handling logic will be added.

  private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
             
               //do whatever handling you want here

                //must set e.handled = true so that application can resume execution
                e.Handled = true;
           
        }

Hopefully this works for you (temporary solution until v3 comes along) So far my users have not complained yet. Thanks
0 Kudos
KevinSayer
New Contributor III
Hi shweekia,

I appreciate the response and thanks for the suggestion.  Unfortunately it's not quite that simple for us as we are writing a COM plugin for our company's flagship MFC application.   The plugin is written in c# and uses interop to communicate with the main application.  It is effectively a modeless window that hosts the WPF map control inside an ElementHost. The main application team (which I've worked on for many years in the past) would definitely not be happy adding a "catch all" top level exception handler.  It would also require a new release of the flagship product which is obviously not going to happen just to work around a bug in third party code.  If Esri haven't resolved the problem before we release the next version of the plugin, the most likely solution will be that we have to drop the shape editing functionality.  This would be a real shame given the context in which we use it.

Regards,
Kevin
0 Kudos