Select to view content in your preferred language

Decoupling asynchronous querytask away from the map. Wait for the async to finish?

704
3
01-21-2011 07:38 AM
MichaelBlom
Deactivated User
Hello,
any suggestions would be very appreciated,

In c# code, I'd like to create a library with some GIS functionality.  My first GP task in my library is to be a point in polygon intersect.

This involves 2 querytasks/queries.  First selects the polygons, the second does the intersect.

I attach the results of my intersects to graphicsLayers, and I want these graphicsLayers to be the returned objects from my methods.

Problem is, I can't figure out how to make my method wait for ESRI's ASync querytasks to finish (and populate the graphics Layers) before it attempts to return the graphics layers.

I???ve tried delegates (denied cross thread access), background worker (cross threads again), and a simple thread.sleep inside a while loop, but nothing.

Simplest would be if i could execute the querytask synchronously, but it doesnt appear that i can.

Below is a simplified version of what I'm trying to do:

[HTML]bool myBool = GetABoolean(5);    

public bool GetABoolean(int id)
{

  bool aBool;

  client.CallAnAsyncMethod(id);  // value is returned in a completed event handler.  Need to somehow get that value into aBool.

  return aBool;  // this needs to NOT execute until aBool has a value

}[/HTML]
0 Kudos
3 Replies
dotMorten_esri
Esri Notable Contributor
Silverlight inherently works asyncronously (and it is the best pattern to use too). So you need to make your own utility library work asyncronously as well. Create a class, declare an event handler, and when the two processes has completed, raise the event you created. You can declare an event that has an eventargument with the graphics layer in it.

Alternatively, you could use a method that takes a delegate to call when the process completes. Fx:
public void StartProcess(string someParameters, Action<GraphicsLayer> onCompleted)
{
     //todo
}

You can parse the onCompleted method around using the userState object in all the ESRI tasks, so you will get it back each time a task completes.

So you call the process like this:
MyUtility.StartProcess("string argument", processComplete);
...
private void processComplete(GraphicsLayer result)
{
    //todo
}
0 Kudos
TomFlahive
Occasional Contributor
Morten,

Do you have any reference to a more complete example of implementing either of the two approaches you mention?  I can't seem to figure it out from the limited code you provide.

Thanks
0 Kudos
JohnnyPenet
Emerging Contributor
Tom,

At the moment I am writing a template silverlight application for replacing the web adf framework. To do heavy lifting in Silverlight I decided to move towards Prism and MVVM Microsoft framework. The solution I show you here is based on this approach. I put some of my experiences on a blog
http://jpenet.blogspot.com , I hope within a couple of weeks to show how editing can be done within this framework approach.

Editing in my approach is based on services. For GIS I have a couple of services, one is GisEditing that does all the functionality of the Editor and the Geometry services. To implement the intersect, you can do the following:

IGisEditing interface :

public delegate void GeometryServiceCompleteHandler(object sender, GraphicsEventArgs args);
public interface IGisEditing
{
string GetGeometryServiceUrl();
void SetGeometryServiceUrl(string geometryServiceUrl);
void Intersect(IList<Graphic> targetGraphics, Geometry intersectGeometry);
void SetGeometryServiceCompleteEvent(GeometryServiceCompleteHandler geometryServiceComplete);
void ResetGeometryServiceCompleteEvent(GeometryServiceCompleteHandler geometryServiceComplete);
}

In the GisEditing component you must implement the interface. By using a complete handler within your viewmodel you can know when the intersect is finished.

public void Intersect(IList<Graphic> targetGraphics,Geometry intersectGeometry)
{
geometryService.IntersectCompleted += GeometryService_IntersectCompleted;
geometryService.Failed += GeometryService_Failed;
geometryService.IntersectAsync(targetGraphics, intersectGeometry);
}

private void GeometryService_IntersectCompleted(object sender, GraphicsEventArgs e)
{
OnGeometryServiceComplete(e);
}

private void GeometryService_Failed(object sender, TaskFailedEventArgs e)
{
// Failed service
GraphicsEventArgs returnEvent = new GraphicsEventArgs();
returnEvent.Results = null;
OnGeometryServiceComplete(returnEvent);
}

Now in the viewmodel you must handle the button that initiate your intersect
In MVVM with Prism this is done by using ICommand

private ICommand _intersectCommand;
public ICommand IntersectCommand
{
get
{
return _intersectCommand;
}
set
{
_intersectCommand = value;
this.RaisePropertyChanged(() => this.IntersectCommand);
}
}

Creation of the command with the start

Constructor of the viewmodel
this.IntersectCommand = new DelegateCommand<object>(
this.OnIntersectCommandClicked, this.CanIntersectCommandClicked);  

The methods of the command

IList<Graphic> targetGraphics = ... ; // Here your first action must filled the values
Geometry geometryDrawn = ...;       //

protected virtual void OnIntersectCommandClicked(object arg)
{
if (EditorTool != null)
{             gisEditing.SetGeometryServiceCompleteEvent(IntersectFinished);
gisEditing.Intersect(targetGraphics,geometryDrawn);
}
}
protected virtual bool CanIntersectCommandClicked(object arg)
{
// Do some verification that the conditions for the intersect are fullfilled
              // The button stays gray until some conditions are met (intersect input)
              // use the RaisePropertyChanged to reflect the change is action
return ?;
}

private void IntersectFinished(object sender,GraphicsEventArgs e)
{
// Do some work on the result
}

This seems a lot of work, but in reality this is a routine development of action once the infra structure of Prism is in place. To generalise it for all kind of geometry services you probably has to change the GraphicsEventArgs with one custom evenargs that covers the range of geometry services.

It is heavy stuff, but for complex GIS applications , this is a solid solution.

Johnny


Morten,

Do you have any reference to a more complete example of implementing either of the two approaches you mention?  I can't seem to figure it out from the limited code you provide.

Thanks
0 Kudos