Select to view content in your preferred language

about after using measure behavior, the graph can't stay in the map

9025
24
09-28-2010 12:05 PM
DanDong
Deactivated User
Hi,

I want to ask a question about how to make the polygon stay in the map after using the measure function. I mean I use the measure function to measure the distance of each side of a polygon(measuremode="polygon"), but when I double click the last vertex, the polygon disappear?? I want to keep this polygon. What should I add in the xmal file and cs file? Thank you very much!
0 Kudos
24 Replies
PatrickBrooke
Emerging Contributor
Thank you for looking in to that Jennifer,

That is an unfortunate design since I cannot think of anyone would would prefer that behavior, they would only tolerate this behavior.

I currently do use the draw object for measure at this time, its performace is lacking since it does not dynamically track the measurements of a line as does the measure action(Though I could build a tool that does this, but the time involved...). Measure action is almost prefect but lacking nonetheless!!!

I was able to capture the polygon eventually using your code, but what happened was everything would be added to my new graphics layer every time I added a new point, so I had multiple instances of the measurement text on the each line. What I did was capture the graphicslayer added by measure action to the map instead of using the graphics added event "newitems" property. Each time the event fired(when I added a measure point) I added all of the graphics from the measure action graphics layer to my new one. This led to the duplication of graphics in my new one. Not acceptable!

You know what is even more unfortunate? I was soo close to getting this to work, but it appears that when the graphics layer is removed after the measure action is complete, the graphics layer is cleared prior. That ruins everything. I had measure graphic layer stored in a new graphics layer on the map so I could copy the measure graphics in at the end of the measure, but the graphics layer is emptied before it is removed, so I lose all of the graphics!!! Sooo close.... If they just did not clear the graphics layer before removing it!!! A work around would exist!

Thanks again, and I hope the designers/developers see what a limitation this puts on the measure action. Such potential from this tool, but... :rolleyes:
0 Kudos
PatrickBrooke
Emerging Contributor
Ok,

I did the impossible. I got my application to keep the measure action graphics layer after the draw completes(user double clicks).

What this does is add the existing graphics from the added graphics layer (not from the CollectionChangedEventArgs.NewItems property) to a new graphics layer I put on my map. Then each time the user clicks, that graphics layer is cleared, and the next state of the measure action graphics layer is added to that graphics layer. It is cleared each time until the the double click, where a global bool tracks if the user double clicked. If that bool is satisfied, the graphics layer is not cleared, and you are left with the final state of the measure action graphics layer. Easy, right!?

I had an epiphany over the weekend and the logic worked through my head, and wouldn't you know it, it works great!! I out smarted measure action, and now it is finally worth something to me! 

If you want to try my this implementation of measure action, go to http://gis.modestogov.com

My users will be happy!!!!!

Patrick

private GraphicsLayer addedLayer;
private GraphicsLayer graphicsLayer;

void Layers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (var item in e.NewItems)
                    if (item is GraphicsLayer)
                    {
                        addedLayer = item as GraphicsLayer;
                        graphicsLayer = this.MyMap.Layers["MeasureGraphicsLayer"] as GraphicsLayer;
                        graphicsLayer.Visible = false;
                        
                        (item as GraphicsLayer).Graphics.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Graphics_CollectionChanged);
                    }
            }

            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
            { 
               if (addedLayer != null)
                {
                    isDrawOver = true;
                    graphicsLayer.Visible = true;
                }
            }

        
  }

        void Graphics_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                glCollectionChanged = true;

                if (isDrawOver == false)
                {
                    graphicsLayer.ClearGraphics();                    
                }

                else 
                {
                    isDrawOver = false;
                  
                }

                if (graphicsLayer != null)
                {
                    foreach (Graphic item in addedLayer.Graphics)
                    {                        
                        Graphic g = item as Graphic;
                        graphicsLayer.Graphics.Add(new Graphic() { Geometry = g.Geometry, Symbol = g.Symbol });                        
                    }                   
                }
            }
        }
DanDong
Deactivated User
Ok,

I did the impossible. I got my application to keep the measure action graphics layer after the draw completes(user double clicks).

What this does is add the existing graphics from the added graphics layer (not from the CollectionChangedEventArgs.NewItems property) to a new graphics layer I put on my map. Then each time the user clicks, that graphics layer is cleared, and the next state of the measure action graphics layer is added to that graphics layer. It is cleared each time until the the double click, where a global bool tracks if the user double clicked. If that bool is satisfied, the graphics layer is not cleared, and you are left with the final state of the measure action graphics layer. Easy, right!?

I had an epiphany over the weekend and the logic worked through my head, and wouldn't you know it, it works great!! I out smarted measure action, and now it is finally worth something to me! 

If you want to try my this implementation of measure action, go to http://gis.modestogov.com

My users will be happy!!!!!

Patrick


Thank you Patrick, it really helps me a lot. I have a little question.

bool isDrawOver = true;
bool glCollectionChanged = true;

Those two bool variables have the initial of True right?
0 Kudos
PatrickBrooke
Emerging Contributor
isDrawOver should always be false except when the measure graphics layer is removed (true), then it is reset to false waiting for the next measure to happen. I simply use that so I can track when the user is done measuring, so then I freeze the graphics layer and then make it visible.

you should not need glCollectionChanged, I used this to meet the need of my specific application, you should just delete that out.
0 Kudos
DanDong
Deactivated User
isDrawOver should always be false except when the measure graphics layer is removed (true), then it is reset to false waiting for the next measure to happen. I simply use that so I can track when the user is done measuring, so then I freeze the graphics layer and then make it visible.

you should not need glCollectionChanged, I used this to meet the need of my specific application, you should just delete that out.


Thank you. I have another question. How do you make sure in the process of measuring, the graphic is first drawn on addedlayer, then from added layer it is added to the graphicslayer.
0 Kudos
PatrickBrooke
Emerging Contributor
If I am understanding your question, that happens here when the measure tool is first activated

if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
   {
                foreach (var item in e.NewItems)
                    if (item is GraphicsLayer)
                    {
                        addedLayer = item as GraphicsLayer;
                        graphicsLayer = this.MyMap.Layers["MeasureGraphicsLayer"] as GraphicsLayer;
                        graphicsLayer.Visible = false;
                  
 }


Then I simply copy the graphics from added layer to graphicslayer. addedlayer is set to the graphic that the measure tool adds to the map, every time the tool is invoked. graphicslayer is a layer that I put on the map and is loaded when the map initializes.

I am not sure I answered your question.
0 Kudos
DanDong
Deactivated User
If I am understanding your question, that happens here when the measure tool is first activated

if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
   {
                foreach (var item in e.NewItems)
                    if (item is GraphicsLayer)
                    {
                        addedLayer = item as GraphicsLayer;
                        graphicsLayer = this.MyMap.Layers["MeasureGraphicsLayer"] as GraphicsLayer;
                        graphicsLayer.Visible = false;
                  
 }


Then I simply copy the graphics from added layer to graphicslayer. addedlayer is set to the graphic that the measure tool adds to the map, every time the tool is invoked. graphicslayer is a layer that I put on the map and is loaded when the map initializes.

I am not sure I answered your question.


Yes. I think I get it. Thank you very much! 😛
0 Kudos
BrandonCales
Regular Contributor
I have this working...thanks Patrick.

How are you reactivating the Measure, so once the prior measure is shown on the graphics layer and new MeasureAction begins?

Also...does anyone know of a way to cancel Measure in the middle of running it?
0 Kudos
BrandonCales
Regular Contributor
Here is my code for this - it works well, however all I want to do is allow the user to measure again without having to click on the tool again.

.xaml
<!-- Measure Tools Window-->
        <userControls:WindowPanel x:Name="MeasureTools" HorizontalAlignment="Left" Margin="420,10,0,0" VerticalAlignment="Top"  IsOpen="{Binding ElementName=ToolsMenu_Measure, Path=IsChecked, Mode=TwoWay}">
                    <StackPanel Orientation="Vertical" Margin="5">
                    <StackPanel Orientation="Horizontal" Margin="5">
                    <RadioButton Content="Distance"
       ToolTipService.ToolTip="Distance"
       GroupName="MeasureMode"
       Margin="5,0,0,0" Foreground="White" FontSize="11" Click="MeasureTools_Click">
                            <!--<i:Interaction.Triggers>
                                <i:EventTrigger EventName="Click">
                                    <esri:MeasureAction                                  
                                    AreaUnit="SquareMiles"
                                    DisplayTotals="True"
                                    DistanceUnit="Miles"
                                    MapUnits="Feet"
                                    MeasureMode="Polyline"                                   
                                    FillSymbol="{StaticResource DefaultFillSymbol}"
                                    TargetName="MyMap"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>-->
                        </RadioButton>
                        <RadioButton Content="Area"
       ToolTipService.ToolTip="Area"
       GroupName="MeasureMode"
       Margin="5,0,0,0" Foreground="White" FontSize="11" Click="MeasureTools_Click">
                            <!--<i:Interaction.Triggers>
                                <i:EventTrigger EventName="Click">
                                    <esri:MeasureAction                                  
                                    AreaUnit="SquareMiles"
                                    DisplayTotals="True"
                                    DistanceUnit="Miles"
                                    MapUnits="Feet"
                                    MeasureMode="Polygon"                                   
                                    FillSymbol="{StaticResource DefaultFillSymbol}"
                                    TargetName="MyMap" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>-->
                        </RadioButton>
                        <RadioButton Content="Clear"
       ToolTipService.ToolTip="Clear" IsChecked="True"
       GroupName="MeasureMode"
       Margin="5,0,0,0" Foreground="White" FontSize="11" Click="MeasureTools_Click">
                    </RadioButton>
                    </StackPanel>
                    <TextBlock Foreground="Yellow" FontSize="11" 
                               Text="Double-Click to Complete" TextWrapping="NoWrap" Height="Auto" 
                               HorizontalAlignment="Center" Margin="5,3,0,0" FontStyle="Italic" />
                    </StackPanel>
                    <userControls:WindowPanel.ContentTitle>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="Images/icons/i_measure.png" 
                           HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="Fill" 
                           Width="20" Height="20" Margin="5,2,0,0" />
                            <TextBlock Foreground="White" FontSize="12" 
                               Text="Measure" Width="100" TextWrapping="NoWrap" Height="Auto" 
                               HorizontalAlignment="Left" Margin="5,3,0,0" />
                        </StackPanel>
                    </userControls:WindowPanel.ContentTitle>
        </userControls:WindowPanel>



.cs
#region MeasureTool
            private GraphicsLayer addedLayer;
            private GraphicsLayer MeasureGraphicsLayer;
            private myMeasureAction ma = new myMeasureAction();
            private string MeasureTool = null;


            private class myMeasureAction : ESRI.ArcGIS.Client.Actions.MeasureAction
            {
                public void Execute()
                {
                    Invoke(null);
                }
            }

            private void MeasureTools_Click(object sender, System.Windows.RoutedEventArgs e)
            {
                if ((RadioButton)sender != null)
                {
                    MeasureTool = ((RadioButton)sender).Content.ToString();

                    MeasureGraphicsLayer = this.MyMap.Layers["MeasureGraphicsLayer"] as GraphicsLayer;
                    MeasureGraphicsLayer.ClearGraphics();
                    MeasureGraphicsLayer.Visible = false;

                    ma.DisplayTotals = true;
                    ma.AreaUnit = ESRI.ArcGIS.Client.Actions.AreaUnit.SquareMiles;
                    ma.DistanceUnit = ESRI.ArcGIS.Client.Actions.DistanceUnit.Miles;
                    ma.FillSymbol = LayoutRoot.Resources["DefaultFillSymbol"] as FillSymbol;
                    ma.Attach(MyMap);

                    //MeasureTool = ((RadioButton)sender).Content.ToString();

                    if (MeasureTool == "Distance")
                    {
                        ma.MeasureMode = myMeasureAction.Mode.Polyline;
                        ma.Execute();
                    }
                    else if (MeasureTool == "Area")
                    {
                        ma.MeasureMode = myMeasureAction.Mode.Polygon;
                        ma.Execute();
                    }
                    else
                    {
                        MeasureGraphicsLayer.ClearGraphics();
                        MeasureGraphicsLayer.Visible = false;
                        ma.Detach();
                    }
                }   
            }

            private void MeasureTools_Clear_Click(object sender, RoutedEventArgs e)
            {
                MeasureGraphicsLayer.ClearGraphics();
                MeasureGraphicsLayer.Visible = false;
                ma.Detach();
            }

            private void Layers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    foreach (var item in e.NewItems)
                    {
                        if (item is GraphicsLayer)
                        {
                            addedLayer = item as GraphicsLayer;
                            MeasureGraphicsLayer = this.MyMap.Layers["MeasureGraphicsLayer"] as GraphicsLayer;
                            MeasureGraphicsLayer.Visible = false;

                            (item as GraphicsLayer).Graphics.CollectionChanged += Graphics_CollectionChanged;
                        }
                    }
                }
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
                {
                    if (addedLayer != null)
                    {
                        isDrawOver = true;
                        MeasureGraphicsLayer.Visible = true;

                        //Tried to rerun here....but error
                    }
                }
            }

            private void Graphics_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    if (isDrawOver == false)
                    {
                        MeasureGraphicsLayer.ClearGraphics();
                    }
                    else
                    {
                        isDrawOver = false;
                    }

                    if (MeasureGraphicsLayer != null)
                    {
                        foreach (Graphic item in addedLayer.Graphics)
                        {
                            Graphic g = item as Graphic;
                            MeasureGraphicsLayer.Graphics.Add(new Graphic() { Geometry = g.Geometry, Symbol = g.Symbol });
                        }
                    }
                }
                else
                {
                    //MessageBox.Show(e.Action.ToString());
                }
            }
        #endregion
0 Kudos
EkaterinaTitova
Deactivated User
Ok,

I did the impossible. I got my application to keep the measure action graphics layer after the draw completes(user double clicks).

What this does is add the existing graphics from the added graphics layer (not from the CollectionChangedEventArgs.NewItems property) to a new graphics layer I put on my map. Then each time the user clicks, that graphics layer is cleared, and the next state of the measure action graphics layer is added to that graphics layer. It is cleared each time until the the double click, where a global bool tracks if the user double clicked. If that bool is satisfied, the graphics layer is not cleared, and you are left with the final state of the measure action graphics layer. Easy, right!?

I had an epiphany over the weekend and the logic worked through my head, and wouldn't you know it, it works great!! I out smarted measure action, and now it is finally worth something to me! 

If you want to try my this implementation of measure action, go to http://gis.modestogov.com

My users will be happy!!!!!

Patrick

private GraphicsLayer addedLayer;
private GraphicsLayer graphicsLayer;

void Layers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (var item in e.NewItems)
                    if (item is GraphicsLayer)
                    {
                        addedLayer = item as GraphicsLayer;
                        graphicsLayer = this.MyMap.Layers["MeasureGraphicsLayer"] as GraphicsLayer;
                        graphicsLayer.Visible = false;
                        
                        (item as GraphicsLayer).Graphics.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Graphics_CollectionChanged);
                    }
            }

            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
            { 
               if (addedLayer != null)
                {
                    isDrawOver = true;
                    graphicsLayer.Visible = true;
                }
            }

        
  }

        void Graphics_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
           
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                glCollectionChanged = true;

                if (isDrawOver == false)
                {
                    graphicsLayer.ClearGraphics();                    
                }

                else 
                {
                    isDrawOver = false;
                  
                }

                if (graphicsLayer != null)
                {
                    foreach (Graphic item in addedLayer.Graphics)
                    {                        
                        Graphic g = item as Graphic;
                        graphicsLayer.Graphics.Add(new Graphic() { Geometry = g.Geometry, Symbol = g.Symbol });                        
                    }                   
                }
            }
        }


Can you help please, why this decision doesn't work for myMeasureAction.MeasureMode = MeasureAction.Mode.Radius? Procedure Graphics_CollectionChanged is never started...
0 Kudos