Select to view content in your preferred language

MeasureAction action finished event?

1620
9
06-02-2010 09:59 AM
RyanCoodey
Frequent Contributor
How can I know when a measure action is finished? (ie. when they double click and the measure graphics go away)...

Things I have looked into:
- No events for MeasureAction
- Measure Actions OnDetaching method is not called (wouldnt expect it too)... don't see any other methods I could override that might be called either.
- Register Maps MouseLeftButtonDown, but from what I can tell Silverlight doesnt support double click events... and don't want to do some time based hack because it may not mesh up with the actions

Thanks a lot!
0 Kudos
9 Replies
DominiqueBroux
Esri Frequent Contributor
You are right, as far as I know, there is no event for the measure action.

I am not sure what you want to do (and not sure MeasureAction is designed for that), but you might subsribe to the map.Layers events. When the action is over, the graphic layer is removed from the collection.
0 Kudos
RyanCoodey
Frequent Contributor
The MeasureAction is launched from a toolbar, and what I am trying to do is relaunch the MeasureAction when it is complete, since the tool is still selected in the toolbar, the user can do another Measurement then...

I tried like you said and subscribed to "Layers.CollectionChanged" and thought it was going to work... so in there I check a few things and then Invoke the MeasureAction again... the problem is that the MeasureAction is trying to recreate the graphics layer, and an error is thrown that "Cannot change ObservableCollection during a CollectionChanged or PropertyChanged event"... so for that reason I cannot do it in there. bummer 😞

Thanks for that great info though, will see what else I can come up with!
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Try to execute your code asynchrounously from your event handler.
Something like :
Dispatcher.BeginInvoke(ActivateActionTool);
0 Kudos
RyanCoodey
Frequent Contributor
Try to execute your code asynchrounously from your event handler.


Worked Great!  Thanks a lot Dominique!
0 Kudos
JosephMcCausland
Esri Contributor
If using the CollectionChanged event, make sure to check the NotifyCollectionChangedEventArgs.Action.  You will get an event for "Remove" and one for "Add".  You will want to only invoke a new measure action on "Remove".  You will end up in an infinite loop otherwise.
0 Kudos
deleted-user-ATjHIWsdQYmT
Deactivated User
Ryan,

Do you mind sharing some code samples?  I'm trying to accomplish exactly what it looks like you've already done.  I'm not quite there yet.  Can you lend a hand?

I've been able to invoke the tool and measure more than one time, but I cannot figure out how to "un-invoke" the tool when another tool is selected.  I tried removing the event handler but it doesnt seem to work.

Thanks.
0 Kudos
PLadd
by
Frequent Contributor
Try to execute your code asynchrounously from your event handler.
Something like :
Dispatcher.BeginInvoke(ActivateActionTool);


This trick does keep the current measure tool active.  I use this code in Layers_CollectionChanged:
Dispatcher.BeginInvoke(() => myMeasureDrawAction("Area"));

But now there's a new problem.  Let's say the user clicks on btnMeasureArea, measures an area, then measures another area and so on without having to keep clicking btnMeasureArea - works great. 

But if the user then clicks btnMesaureLength and clicks on the map, it still has to do an area measure because that's what Dispatcher.BeginInvoke has told it to do on the UI thread.  Finally once an area measure is done, measure length is activated. 

How can we cancel BeginInvoke if the user chooses another measurement option?  I tried _m.Detach();  - where _m is new MeasureAction - but that just made things loopy.  I'm guessing I need some kind of class to unInvoke the execution of

public void Execute()
{
Invoke(null);
}

but, because I was a history major in college, I need one of you C# experts to shed some light on this.  Thanks.
0 Kudos
RyanCoodey
Frequent Contributor
Sorry for the late reply guys, just saw all the posts thanks to Patrick.

So what I did is attach the measure action on the maps PreviewMouseDown (that is if the tool is selected).  This way when it is finished, it is not tied right back into the map.  Also, with the release of the 2.2 API, we can now stop a measure action by calling MeasureAction.Detach().

Here are some of my methods:

        protected void AttachMeasureAction(Map map)
        {
            if (!MeasureActionSelected && map != null)
            {
                MeasureActionSelected = true;
                //ToolLock = true;
                map.Layers.CollectionChanged += Layers_CollectionChanged;
                MeasureAction.Attach(map);
                MeasureAction.Execute();
            }
        }
        protected void StartMeasureAction()
        {
            DisableMeasureAction();
            foreach (Map map in InternalMaps)
            {
                map.PreviewMouseDown += Map_PreviewMouseDown;
                map.Cursor = Cursors.Hand; //Need to reset cursor because measure action changes it upon finish
            }
        }
        protected void DisableMeasureAction()
        {
            MeasureAction.Detach();
            foreach (Map map in InternalMaps)
                map.PreviewMouseDown -= Map_PreviewMouseDown;
            MeasureActionSelected = false;
            //ToolLock = false;
        }

//Events
        protected void Map_PreviewMouseDown(Object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            DisableMeasureAction();
            AttachMeasureAction((Map)sender);
        }
        protected void Layers_CollectionChanged(Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //Restart measure action when finished
            if(MeasureActionSelected)
            {
                if (e.OldItems != null)
                {
                    for (Int32 i = 0; i < e.OldItems.Count; i++)
                    {
                        if (e.OldItems is GraphicsLayer && ((GraphicsLayer)e.OldItems).ID == null)
                        {
                            StartMeasureAction();
                             break;
                        }
                    }
                }
            }
        }


Hope this helps!
0 Kudos
PLadd
by
Frequent Contributor
The above code will only work with WPF, not in Silverlight.  See bottom of this thread:

http://forums.arcgis.com/threads/22131-Accessing-behavior-action-programmatically?highlight=PREVIEWM...

I also looked into using BackgroundWorker but my understanding with that is you can't do anything to the Silverlight UI thread from the background thread.  You'll get a cross-thread exception.

http://forums.silverlight.net/p/210015/494163.aspx

Using MeasureAction.Detach(); will throw things into a loop.

And don't use Dispatcher.BeginInvoke because once you put it on the UI thread, there's no way to remove it:
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/b58d0c8f-92d9-4f6d-bd14-0ff32eedbf17



WHY CAN'T I USE THE MEASURE TOOLS LIKE A TOOL TOOL???
0 Kudos