Solved! Go to Solution.
public MainWindow() { InitializeComponent(); this.Completed += (sender, result) => { Application.Current.Dispatcher.Invoke(new Action(() => { MessageBox.Show("Result: " + result.Token); }), null); }; LocalGeoprocessingService.GetServiceAsync(gpkLocation, GPServiceType.SubmitJob, localGpService => { if (localGpService.Error != null) return; lgs = localGpService; Thread thread = new Thread(new ParameterizedThreadStart(this.ExecuteGPTask)); thread.Start("Background Thread"); this.ExecuteGPTask("UI Thread"); }); } public void ExecuteGPTask(object token) { //Set up parameters List<GPParameter> parameters = new List<GPParameter>(); string input = "5+5"; GPString inputParam = new GPString("input", input); parameters.Add(inputParam); // Check local GP service is running and there are >=1 tasks if (this.lgs.Status != LocalServiceStatus.Running || this.lgs.Tasks.Count == 0) return; // Assumes only one task in GP Package (GPK) string taskUri = this.lgs.Tasks[0].Url; // Create a new Geoprocessor task Geoprocessor gpContour = new Geoprocessor(taskUri); gpContour.Token = token.ToString(); // Create a timer to schedule CheckJobStatusAsync calls System.Timers.Timer timer = null; // Handler for StatusUpdated event (in response to CheckJobStatusAsync) gpContour.StatusUpdated += (s, e) => { Geoprocessor geoprocessingTask = s as Geoprocessor; switch (e.JobInfo.JobStatus) { case esriJobStatus.esriJobSubmitted: // Disable automatic status checking. geoprocessingTask.CancelJobStatusUpdates(e.JobInfo.JobId); break; case esriJobStatus.esriJobSucceeded: if (this.Completed != null) { this.Completed(this, new MyEventArgs() { Token = gpContour.Token }); if (timer != null) { timer.Stop(); timer.Dispose(); } } // Get the results. // geoprocessingTask.GetResultDataAsync(e.JobInfo.JobId, "<parameter name>"); break; case esriJobStatus.esriJobFailed: case esriJobStatus.esriJobTimedOut: MessageBox.Show("operation failed"); break; } }; JobInfo jobInfo = gpContour.SubmitJob(parameters); timer = new System.Timers.Timer(3000); timer.Elapsed += (s, e) => { gpContour.CheckJobStatusAsync(jobInfo.JobId); }; timer.Start(); }
using System; using System.Threading; using System.Windows.Threading; using ESRI.ArcGIS.Client; namespace UpdateGraphicsConsole { class Program { static string _url = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/FeatureServer/0"; // Make sure the main thread is an STA thread [STAThread] static void Main(string[] args) { // The SynchronizationContext of the main thread is null. // Create and set a new DispatcherSynchronizationContext. var syncCtx = new DispatcherSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(syncCtx); // Get the current dispatcher to check thread access. Dispatcher d = Dispatcher.CurrentDispatcher; // Create a FeatureLayer FeatureLayer fl1 = new FeatureLayer { Url = _url, ID = "23", Mode = FeatureLayer.QueryMode.Snapshot, AutoSave = false, }; // Report which thread the FeatureLayer was created on Console.WriteLine("FeatureLayer created on Thread " + d.Thread.ManagedThreadId.ToString()); // Register a handler for the Initialized event fl1.Initialized += (sender, eventArgs) => { // Report which thread the event fired on (this was always a different thread until the DispatcherSynchronizationContext was set Console.WriteLine("Initialized event handled on Thread " + Dispatcher.CurrentDispatcher.Thread.ManagedThreadId.ToString()); // Get the FeatureLayer FeatureLayer fl2 = sender as FeatureLayer; // Get the FeatureLayer dispatcher Dispatcher d1 = fl2.Dispatcher; // Report the thread we're invoking the Update call on (this was always the original thread) Console.WriteLine("Invoking Update on Thread " + d1.Thread.ManagedThreadId.ToString()); // CheckAccess always returned false because this code was running on a different thread until the DispatcherSynchronizationContext was set if (fl2.Dispatcher.CheckAccess()) { fl2.Update(); } else d1.BeginInvoke( DispatcherPriority.Normal, new Action(delegate() { fl2.Update(); })); }; // Register a handler for the UpdateCompleted event and call SaveEdits() fl1.UpdateCompleted += (sender, e) => { // Get the FeatureLayer FeatureLayer fl3 = sender as FeatureLayer; // Get the FeatureLayer Dispatcher Dispatcher d2 = fl3.Dispatcher; // Update the graphic attribute (or perform any other edits) fl3.Graphics[0].Attributes["description"] = Guid.NewGuid().ToString(); // Write out the new value Console.WriteLine( "Updated Graphic ObjectID " + fl3.Graphics[0].Attributes["objectid"] + " with Description: " + fl3.Graphics[0].Attributes["description"]); // Call CheckAccess to confirm whether we need to post back to the original thread // Then call SaveEdits if (fl3.Dispatcher.CheckAccess()) { fl3.SaveEdits(); } else d2.BeginInvoke( DispatcherPriority.Normal, new Action(() => fl3.SaveEdits())); }; // Register a handler for the EndSaveEdits event and write out the status fl1.EndSaveEdits += (sender, e) => { Console.WriteLine(e.Success ? "Success" : "Fail"); // Can check results online at query endpoint (by description value, objectid, etc) // http://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/FeatureServer/0/query }; // Register a handler for the InitializationFailed event fl1.InitializationFailed += (sender, e) => { // Report error FeatureLayer fl4 = sender as FeatureLayer; Console.WriteLine(fl4.InitializationFailure.Message); }; // Register a handler for the UpdateFailed event fl1.UpdateFailed += (sender, e) => { // Report failure to update layer Console.WriteLine(e.Error); }; // Register a handler for the SaveEditsFailed event fl1.SaveEditsFailed += (sender, e) => { // Report failure Console.WriteLine(e.Error); }; Console.WriteLine("Calling Initialize on Thread " + d.Thread.ManagedThreadId.ToString()); // Call Initialize method (in a map/UI scenario this call would be handled by the Map). fl1.Initialize(); // Need to call Dispatcher.Run Dispatcher.Run(); } } }
Hi,
For your console app you should just need to create and set a new SynchronizationContext e.g.