/// <summary> /// Waits until a function evaluates to <c>true</c>. /// Shows a dialog. /// </summary> /// <param name="function">The function to evaluate.</param> /// <param name="condition">The condition to evaluate on the functions return value.</param> /// <param name="expectationText">Text that explains the function's expectation.</param> /// <param name="negativeTimeout">The negative timeout.</param> /// <param name="positiveTimeout">The positive timeout.</param> /// <param name="pollingPeriod">The polling time.</param> /// <param name="clickThrough">Whether to enable click-through mode.</param> /// <param name="actionText">The action text.</param> private void Forr <T>(Func <T> function, Predicate <T> condition, string expectationText, TimeSpan negativeTimeout, TimeSpan positiveTimeout, TimeSpan pollingPeriod, bool clickThrough, string actionText) { // init state = State.init; this.positiveTimeout = positiveTimeout; this.negativeTimeout = negativeTimeout; uic = new DialogView(negativeTimeout != TimeSpan.MaxValue, positiveTimeout != TimeSpan.MaxValue && positiveTimeout != TimeSpan.Zero, clickThrough, function != null, actionText); // spawn var c = new CancellationTokenSource(); Task ui = new Task(() => uic.UI(() => OnDialogLoad(expectationText, actionText), OnBadClick, OnGoodClick)); Task ti = new Task(() => Timer(c.Token)); Task po = new Task(() => Evaluator(c.Token, function, condition, pollingPeriod)); // join ui.Start(); ti.Start(); po.Start(); ui.Wait(); c.Cancel(); ti.Wait(); po.Wait(); switch (state) { case State.good_userexit: case State.good_timedout: return; case State.bad_timedout: throw new DialogWaitForTimeoutException(expectationText, negativeTimeout); case State.bad_userexit: throw new DialogWaitForAbortedException(expectationText); default: throw new InvalidOperationException(state.ToString()); } }