internal async Task <bool> AsynchronousBreak(RemoteBreakpointInfo info) { using SemaphoreSlim semaphore = new SemaphoreSlim(0, 1); void resumeHandler(object sender, EventArgs e) { semaphore.Release(); } await Dispatcher.UIThread.InvokeAsync(() => { EditorControl.ActiveBreakpoint = info.BreakpointSpan.Start - PreSource.Length - 1; EditorControl.SetSelection(info.BreakpointSpan.End - PreSource.Length - 1, 0); BreakpointPanel.SetContent(info); BreakpointPanel.ResumeClicked += resumeHandler; this.FindAncestorOfType <Window>().Closing += resumeHandler; OpenSidePanel(); }); await semaphore.WaitAsync(); bool tbr = false; await Dispatcher.UIThread.InvokeAsync(() => { tbr = BreakpointPanel.IgnoreFurtherOccurrences; CloseSidePanel(); BreakpointPanel.ResumeClicked -= resumeHandler; this.FindAncestorOfType <Window>().Closing -= resumeHandler; EditorControl.ActiveBreakpoint = -1; }); semaphore.Dispose(); return(tbr); }
/// <summary> /// A function to handle breakpoints in synchronous methods. Pass this as an argument to <see cref="Compile(Func{BreakpointInfo, bool}, Func{BreakpointInfo, Task{bool}})"/>. To prevent deadlocks, this function will have no effect if called from the UI thread. /// </summary> /// <param name="info">A <see cref="BreakpointInfo"/> object containing information about the location of the breakpoint and the current value of local variables.</param> /// <returns><see langword="true" /> if further occurrences of the same breakpoint should be ignored; <see langword="false"/> otherwise.</returns> public bool SynchronousBreak(BreakpointInfo info) { if (!CheckAccess()) { EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); bool tbr = false; async void resumeHandler(object sender, EventArgs e) { await Dispatcher.UIThread.InvokeAsync(() => tbr = BreakpointPanel.IgnoreFurtherOccurrences); waitHandle.Set(); } Dispatcher.UIThread.InvokeAsync(() => { EditorControl.ActiveBreakpoint = info.BreakpointSpan.Start - PreSource.Length - 1; EditorControl.SetSelection(info.BreakpointSpan.End - PreSource.Length - 1, 0); BreakpointPanel.SetContent(info); BreakpointPanel.ResumeClicked += resumeHandler; this.FindAncestorOfType <Window>().Closing += resumeHandler; OpenSidePanel(); }); waitHandle.WaitOne(); Dispatcher.UIThread.InvokeAsync(() => { CloseSidePanel(); BreakpointPanel.ResumeClicked -= resumeHandler; this.FindAncestorOfType <Window>().Closing -= resumeHandler; EditorControl.ActiveBreakpoint = -1; }); return(tbr); } else { return(false); } }