public Task<string> Solve(Captcha captcha) { Action dispose = null, initialize = null; EventHandler timerHandler = null; KeyEventHandler keyHandler = null; RoutedEventHandler playHandler = null; RoutedEventHandler solveHandler = null; RoutedEventHandler reloadHandler = null; RoutedEventHandler cancelHandler = null; RoutedEventHandler toAudioHandler = null; RoutedEventHandler toTextHandler = null; TaskCompletionSource<string> completion = new TaskCompletionSource<string>(); DispatcherTimer timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) }; initialize = () => { this.panel.Visibility = Visibility.Visible; this.Refresh(captcha); this.ApplyButtons(captcha); this.play.Click += playHandler; this.solve.Click += solveHandler; this.solve.IsEnabled = false; this.reload.Click += reloadHandler; this.reload.IsEnabled = true; this.cancel.Click += cancelHandler; this.cancel.IsEnabled = true; this.toAudio.Click += toAudioHandler; this.toText.Click += toTextHandler; this.text.KeyDown += keyHandler; timer.Tick += timerHandler; timer.Start(); }; dispose = () => { this.panel.Visibility = Visibility.Collapsed; timer.Tick -= timerHandler; timer.Stop(); this.play.Click -= playHandler; this.solve.Click -= solveHandler; this.reload.Click -= reloadHandler; this.cancel.Click -= cancelHandler; this.toAudio.Click -= toAudioHandler; this.toText.Click -= toTextHandler; this.text.KeyDown -= keyHandler; this.image.Source = null; this.text.Clear(); }; playHandler = async (sender, args) => { this.Lock(); try { await captcha.Play(); } finally { this.Unlock(); } }; solveHandler = (sender, args) => { completion.SetResult(this.text.Text.Trim()); dispose.Invoke(); }; keyHandler = (sender, args) => { if (this.solve.IsEnabled == true && args.Key == Key.Enter) { completion.SetResult(this.text.Text.Trim()); dispose.Invoke(); } }; reloadHandler = async (sender, args) => { this.Lock(); try { await captcha.Reload.Invoke(); this.Refresh(captcha); } finally { this.Unlock(); } }; toAudioHandler = async (sender, args) => { this.Lock(); try { await captcha.ToAudio.Invoke(); this.Refresh(captcha); this.ApplyButtons(captcha); } finally { this.Unlock(); } }; toTextHandler = async (sender, args) => { this.Lock(); try { await captcha.ToImage.Invoke(); this.Refresh(captcha); this.ApplyButtons(captcha); } finally { this.Unlock(); } }; cancelHandler = (sender, args) => { dispose.Invoke(); completion.SetResult(null); }; timerHandler = (sender, args) => { if (captcha.Cancellation.IsCancellationRequested == true) { dispose.Invoke(); completion.TrySetCanceled(captcha.Cancellation); } }; initialize.Invoke(); return completion.Task; }