2

我一直在嘗試瞭解更多關於異步任務和線程的知識,但沒有取得很大的進展。C#股票代碼的異步任務

我試圖加載的「發動機」型線,將在啓動時在後臺運行,並能夠訪問UI線程更新變量,不掛UI線程。

在下面的代碼,發動機被調用,並且一個定單對象被創建,其保持(萊特幣/ USD)稱爲最後的電流值,也保持其它幾個值,這將是有用的。此代碼成功地將當前值分配給label1.text。我不一定需要代碼,但是我會採取什麼方法每秒在後臺創建一個代碼對象,並使用每個新的代碼對象值更新UI線程。

這是背景工作者的好例子嗎?

private void Form1_Load(object sender, EventArgs e) 
    { 
     Engine(); 
    } 
    private void Engine() 
    { 
     Ticker ltcusd = BtceApi.GetTicker(BtcePair.LtcUsd); 
     label1.Text = "LTC/USD:" + ltcusd.Last; 
    } 

編輯: 如果我這樣做,LABEL1引發InvalidOperationException由於跨線程操作的企圖(label1的在UI線程)。

private void Form1_Load(object sender, EventArgs e) 
    { 
     var t = Task.Factory.StartNew(() => Engine()); 
     t.Start(); 
    } 
    private void Engine() 
    { 
     while (true) 
     { 
      Thread.Sleep(1000); 
      Ticker ltcusd = BtceApi.GetTicker(BtcePair.LtcUsd); 
      label1.Text = "LTC/USD: " + ltcusd.Last; 
     } 
    } 
+0

您是否使用.NET 4.5和C#5? – 2013-05-05 18:45:18

+0

是的(輸入至少15個字符) – user2163343 2013-05-05 18:47:20

+0

並且'BtceApi'是你控制的東西,還是不是? (理想情況下,你會盡可能地使異步,使你甚至不需要另一個線程。) – 2013-05-05 18:51:54

回答

2

使用async/await,獲取「異步」類型的API的最簡單方法是調用新任務。這不是很好,但它會讓事情變得更簡單。我可能會創建一個新的類,它基本上包裹在任務所有BtceApi方法:

public class BtceApiAsync 
{ 
    public Task<Ticker> GetTickerAsync(BtcePair pair) 
    { 
     return Task.Run(() => BtceApi.GetTicker(pair)); 
    } 

    // etc 
} 

然後你可以使用一個計時器,觸發每秒一次,這將相應地開始了新的任務和更新UI:

// Keep a field of type System.Windows.Forms.Timer 
timer = new Timer(); 
timer.Interval = 1000; 
timer.Tick += DisplayTicker; 
timer.Start(); 

... 

private async void DisplayTicker(object sender, EventArgs e) 
{ 
    Ticker ticker = await BtceApiAsync.GetTickerAsync(BtcePair.LtcUsd); 
    label1.Text = "LTC/USD: " + ltcusd.Last; 
} 

請注意,這並不意味着屏幕會更新每秒一次......會有新的任務每秒啓動一次,只要每個任務完成後,用戶界面將被更新。

這裏使用的await - 從異步方法開始在UI線程 - 意味着你不必擔心使用的用戶界面;整個異步方法將在UI線程上執行,即使抓取本身發生在另一個線程中。

+0

真棒,這種方法對我來說很有意義。謝謝你的時間。 – user2163343 2013-05-05 19:35:41

0

您可以嘗試ContinueWith更新任務結束時的標籤。如果您想在任務結束之前更新事件,則引發在UI線程上註冊的事件。然後該事件可以更新標籤。

0

我想這是Windows窗體。你可以做到「老派風格」,並在UI線程上設置標籤文本,並且可以通過將代理傳遞給BeginInvokeInvoke方法來實現。

private void Engine() 
    { 
     while (true) 
    { 
     Thread.Sleep(1000); 
     Ticker ltcusd = BtceApi.GetTicker(BtcePair.LtcUsd); 
     UpdateText("LTC/USD: " + ltcusd.Last); 
     } 
    } 
    private void UpdateText(string text) 
    { 
     //Inspect if the method is executing on background thread 
     if (InvokeRequired) 
     { 
      //we are on background thread, use BeginInvoke to pass delegate to the UI thread 
      BeginInvoke(new Action(()=>UpdateText(text))); 
     } 
     else 
     { 
      //we are on UI thread, it's ok to change UI 
      label1.Text = text;    
     } 
    } 
+0

我希望我可以upvote,但顯然我沒有足夠的代表,這也工作。謝謝您的幫助。 – user2163343 2013-05-05 19:34:57