2015-11-12 78 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