2015-11-12 49 views
1

我编写了一个WPF程序,该程序读取PC的配置。UI冻结/尝试使用任务/异步等待

该程序必须刷新一个HttpWebRequest将延迟代码,使用户界面将freez。

我试图与async/awaittask s一起工作。

方法Class网:

public TreeView CreatTVURLs() 
{ 
    TreeView TVURLs = new TreeView(); //Here it will break. Says no STA-Thread 
    List<CPingables> lURLs = new List<CPingables>(); 
    lURLs = ReadURLsFromFile(); 
    TVURLs.Name = "URLs"; 
    TVURLs.Background = System.Windows.Media.Brushes.Transparent; 
    TVURLs.BorderThickness = new Thickness(0); 

    foreach (CPingables item in lURLs) 
    { 
     tviURL.Items.Add("IP:\t\t\t" + item.IP.ToString()); 
     tviURL.Items.Add("URL:\t\t\t" + item.URL); 
     ... more stuff 

Thread尝试: 代码在MainWindow:试图用Task

public async void openWindow() 
{ 
    TreeView tvURLs = new TreeView(); 
    tvURLs = (TreeView) TreeViewTest(); 
    //tvURLs = Network.CreatTVURLs(); 
    StackPanel.Children.Add(tvURLs); 
} 

private TreeView TreeViewTest() 
{ 
    TreeView tvURLs = new TreeView(); 
    Thread t = new Thread(() => { tvURLs = Network.CreatTVURLs(); }); 
    t.SetApartmentState(ApartmentState.STA); 
    t.Start(); 
    t.Join(); 
    return tvURLs; 
} 

public async void openWindow() 
{ 
    TreeView tvURLs = new TreeView(); 
    tvURLs = (TreeView) await TreeViewTest(); 
    Task.WaitAll(); 
    StackPanel.Children.Add(tvURLs); 
} 

private Task<TreeView> TreeViewTest() 
{ 
    TreeView tv = new TreeView(); 
    return Task.Factory.StartNew(() => { tv=(TreeView)Network.CreatTVURLs()}); 
} 

我得到总是说必须我STA线程来处理Form项目。

编辑:

HttpWebRequest

public async void pingIP() 
    { 
     try 
     { 
      if (_IPPingAvailible == true) 
      { 
       Ping pinger = new Ping(); 
       PingReply replyIP = pinger.Send(_IP); 
       _PingByIP = replyIP.Status == IPStatus.Success; 
      } 
     } 
     catch (Exception) 
     { 
      _PingByIP = false; 
     } 
     try 
     { 
      if (_UrlAvailible == true) 
      { 
       var uriBuilder = new UriBuilder(_URL); 
       HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriBuilder.Uri); 
       request.Timeout = 1000;     
       using (var response = await request.GetResponseAsync() as HttpWebResponse) 
       { 
        if (response != null && response.StatusCode == HttpStatusCode.OK) 
        { 
         _ReachableByHttp = true; 
        } 
        else 
        { 
         _ReachableByHttp = false; 
        } 
       }      
      } 

     } 
     catch 
     { 
      _ReachableByHttp = false; 
     } 
    } 
+0

不要尝试在后台线程中创建UI控件的实例。这些必须在主线程中完成。而是在后台线程中创建数据对象,然后将这些对象绑定到TreeView。 – Adwaenyth

+0

通常它工作正常。但只有一个freez。即使我在课堂上创造了标签。这就是为什么我有点困惑。 – Shadow

+0

当您在UI线程(在STA中运行)上运行它时,您可以创建如此的UI控件。这不是最佳实践,也不是你如何利用MVVM,但你可以做到这一点。当您尝试在后台线程中创建UI元素时,它会导致异常。 – Adwaenyth

回答

2

的规则是,你只能在UI线程访问UI元素(也称为发送器线程或主线程)。你打破这个规则。你有新的线程: Task.Factory.StartNew(...) resp由new Thread(...);,但你操纵新线程内的UI元素(treeview)。

相反,您应该只在新线程中执行I/O操作或HttpRequest/Response,但其他所有内容(例如,从http响应数据创建树视图)都应在UI线程中完成。

public async void openWindow() 
{ 
    TreeView tvURLs = await Network.CreatTVURLsAsync(); 
    StackPanel.Children.Add(tvURLs); 
} 

public async Task<TreeView> CreatTVURLsAsync() 
{ 
    //you are in dispatcher thread here, so you can access UI elements here 
    TreeView TVURLs = new TreeView(); 
    TVURLs.Name = "URLs"; 
    TVURLs.Background = System.Windows.Media.Brushes.Transparent; 
    TVURLs.BorderThickness = new Thickness(0); 


    List<CPingables> lURLs = null; 
    await Task.Run(() => 
    { 
     //you are in new thread now, so you cannot access UI elements here 
     lURL = ReadURLsFromFile(); 
    }); 

    //you are in dispatcher thread again, so you can access UI elements again 
    foreach (CPingables item in lURLs) 
    { 
     var tviURL = new TreeViewItem(); 
     ..more stuff 
     TVURLs.Items.Add(tviURL); 
    } 
} 
+0

我看到我的错误。一般你应该添加一些说明。无论如何,很好的答案。 – Karolis

+0

您的代码有效。他同时提出请求,但仍然等待响应。 – Shadow