c# 异步调用之异步模式
Func<string, IImageRequest, string> downloadString = (address, req) =>
            {
                var client = new WebClient();
                foreach (var header in req.Headers)
                {
                    client.Headers.Add(header.Key, header.Value);
                }
                client.Credentials = req.Credentials;
                client.Encoding = System.Text.Encoding.UTF8;
                return client.DownloadString(address);
            };

            Action<SearchItemResult> addItem = item => _searchInfo.List.Add(item);

            foreach (var req in GetSearchRequests())
            {
                downloadString.BeginInvoke(req.Url, req, ar =>//BeginInvoke:线程池中一个线程异步调用
                {
                    try
                    {
                        string resp = downloadString.EndInvoke(ar);//downloadString异步方法执行结束,执行ar委托
                        var images = req.Parse(resp);
                        foreach (var image in images)
                        {
                            this.Dispatcher.Invoke(addItem, image);//当前线程回到主线程同步执行
                        }
                    }
                    catch (WebException ex) when (ex.Message.Contains("401"))
                    {
                        MessageBox.Show(errorMessage, "Registration Needed");
                    }
                }, null);
            }

  

c#异步调用之基于事件
foreach (var req in GetSearchRequests())
            {
                var client = new WebClient();
                foreach (var header in req.Headers)
                {
                    client.Headers.Add(header.Key, header.Value);
                }
                client.Credentials = req.Credentials;
                client.DownloadStringCompleted += (sender1, e1) =>
                {
                    try
                    {
                        string resp = e1.Result;
                        var images = req.Parse(resp);
                        foreach (var image in images)
                        {
                            _searchInfo.List.Add(image);//事件处理程序可以直接访问UI
                        }
                    }
                    catch (Exception ex) when (ex.InnerException?.Message.Contains("401") ?? false)
                    {
                        MessageBox.Show(errorMessage, "Registration Needed");
                    }
                };
                client.DownloadStringAsync(new Uri(req.Url));//异步变体方法 以“async”后缀;结束之后会调用事件,此方法对应DownloadStringCompleted事件
            }

  

//异步调用之基于任务(TAP)
        private async void OnTaskBasedAsyncPattern(object sender, RoutedEventArgs e)//async关键字创建了一个状态机
        {
            _cts = new CancellationTokenSource();
            try
            {
                foreach (var req in GetSearchRequests())
                {
                    var clientHandler = new HttpClientHandler
                    {
                        Credentials = req.Credentials
                    };
                    var client = new HttpClient(clientHandler);
                    foreach (var header in req.Headers)
                    {
                        client.DefaultRequestHeaders.Add(header.Key, header.Value);
                    }

                    var response = await client.GetAsync(req.Url, _cts.Token);//解除线程阻塞
                    response.EnsureSuccessStatusCode();
                    string resp = await response.Content.ReadAsStringAsync();//解除线程阻塞
                    await Task.Run(() =>//后台线程运行
                    {
                        var images = req.Parse(resp);
                        foreach (var image in images)
                        {
                            _cts.Token.ThrowIfCancellationRequested();
                            _searchInfo.List.Add(image);//UI调用问题:BindingOperations.EnableCollectionSynchronization,启用集合同步访问功能
                        }
                    }, _cts.Token);
                }
            }
            catch (HttpRequestException ex) when (ex.Message.Contains("401"))
            {
                MessageBox.Show(errorMessage, "Registration Needed");
            }
            catch (OperationCanceledException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }