/// <summary> /// Applies this configuration to the given <see cref="GraphControl"/>. /// </summary> /// <remarks> /// This is the main method of this class. Typically, it calls <see cref="CreateConfiguredLayout"/> to create and /// configure a layout and <see cref="CreateConfiguredLayoutData"/> to get a suitable <see cref="LayoutData"/> instance /// for the layout. /// </remarks> /// <param name="graphControl">The <c>GraphControl</c> to apply the configuration on.</param> /// <param name="doneHandler">A callback that is called after the configuration is applied. Can be <see langword="null"/></param> public virtual async Task Apply(GraphControl graphControl, Action doneHandler) { if (layoutRunning) { graphControl.BeginInvoke(doneHandler); return; } var layout = CreateConfiguredLayout(graphControl); if (layout == null) { graphControl.BeginInvoke(doneHandler); return; } var layoutData = CreateConfiguredLayoutData(graphControl, layout); // configure the LayoutExecutor var layoutExecutor = new LayoutExecutor(graphControl, new MinimumNodeSizeStage(layout)) { Duration = TimeSpan.FromSeconds(0.75), AnimateViewport = true, EasedAnimation = true, PortAdjustmentPolicy = PortAdjustmentPolicy.Lengthen }; // set the cancel duration for the layout computation to 20s layoutExecutor.AbortHandler.CancelDuration = TimeSpan.FromSeconds(20); // set the layout data to the LayoutExecutor if (layoutData != null) { layoutExecutor.LayoutData = layoutData; } // start the LayoutExecutor try { await layoutExecutor.Start(); layoutRunning = false; } catch (AlgorithmAbortedException) { MessageBox.Show( "The layout computation has been canceled because the maximum configured runtime of 20 seconds has been exceeded."); } catch (Exception e) { MessageBox.Show( "Running the layout has encountered an error: " + e.Message); } finally { PostProcess(graphControl); // clean up mapperRegistry graphControl.Graph.MapperRegistry.RemoveMapper( LayoutGraphAdapter.EdgeLabelLayoutPreferredPlacementDescriptorDpKey ); doneHandler(); } }
/// <summary> /// Applies this configuration to the given <see cref="GraphControl"/>. /// </summary> /// <remarks> /// This is the main method of this class. Typically, it calls <see cref="CreateConfiguredLayout"/> to create and /// configure a layout and <see cref="CreateConfiguredLayoutData"/> to get a suitable <see cref="LayoutData"/> instance /// for the layout. /// </remarks> /// <param name="graphControl">The <c>GraphControl</c> to apply the configuration on.</param> /// <param name="doneHandler">A callback that is called after the configuration is applied. Can be <see langword="null"/></param> public virtual async Task Apply(GraphControl graphControl, Action doneHandler) { if (layoutRunning) { graphControl.BeginInvoke(doneHandler); return; } var layout = CreateConfiguredLayout(graphControl); if (layout == null) { graphControl.BeginInvoke(doneHandler); return; } var layoutData = CreateConfiguredLayoutData(graphControl, layout); // configure the LayoutExecutor var layoutExecutor = new LayoutExecutor(graphControl, new MinimumNodeSizeStage(layout)) { Duration = TimeSpan.FromSeconds(1), AnimateViewport = true }; // set the cancel duration for the layout computation to 20s layoutExecutor.AbortHandler.CancelDuration = TimeSpan.FromSeconds(20); // set the layout data to the LayoutExecutor if (layoutData != null) { layoutExecutor.LayoutData = layoutData; } // start the LayoutExecutor try { await layoutExecutor.Start(); layoutRunning = false; } catch (AlgorithmAbortedException) { MessageBox.Show( "The layout computation has been canceled because the maximum configured runtime of 20 seconds has been exceeded."); } catch (Exception e) { MessageBox.Show( "Running the layout has encountered an error: " + e.Message); } finally { PostProcess(graphControl); doneHandler(); } }
/// <summary> /// Runs the layout and disposes the module afterwards. /// </summary> /// <remarks> /// This method will be called in a separate thread. If the layout has been called successfully /// the method <see cref="LayoutDone"/> will be called afterwards to apply the layout. /// If the layout has been canceled or an error has happened during layout the <see cref="Done"/> /// will be raised with an instance of <see cref="LayoutEventArgs"/>. /// </remarks> /// <param name="moduleContext">The module context for this operation.</param> /// <param name="graph">The graph to apply the layout to.</param> /// <param name="compoundEdit">The undo edit which wraps the layout. It has been created in <see cref="StartWithIGraph"/> /// and will be closed after a successful layout or canceled otherwise.</param> private async Task RunModuleAsync(ILookup moduleContext, IGraph graph, ICompoundEdit compoundEdit) { GraphControl view = moduleContext.Lookup <GraphControl>(); try { await RunModule(); Dispose(); if (!view.InvokeRequired) { await LayoutDone(graph, moduleContext, compoundEdit); } else { view.Invoke(new LayoutDoneHandler(LayoutDone), graph, moduleContext, compoundEdit); } } catch (ThreadAbortException tae) { compoundEdit.Cancel(); if (!view.InvokeRequired) { OnDone(new LayoutEventArgs(tae)); } else { view.BeginInvoke(new EventHandler(OnDone), view, new LayoutEventArgs(tae)); } } catch (AlgorithmAbortedException aae) { // layout was canceled. do nothing then. compoundEdit.Cancel(); if (!view.InvokeRequired) { OnDone(new LayoutEventArgs(aae)); } else { view.Invoke(new EventHandler(OnDone), view, new LayoutEventArgs(aae)); } } catch (Exception ex) { compoundEdit.Cancel(); if (!view.InvokeRequired) { OnDone(new LayoutEventArgs(ex)); } else { view.Invoke(new EventHandler(OnDone), view, new LayoutEventArgs(ex)); } } finally { FreeReentrant(); TableLayoutConfigurator.CleanUp(graph); } }