2010-03-14 94 views
3

我有一個C#程序,通過網絡與儀器(頻譜分析儀)通信。我需要能夠更改儀器中的大量參數並將其讀回到我的程序中。我希望使用backgroundworker來進行與樂器的實際對話,以便UI性能不會受到影響。根據.NET結果更新變量backgroundworker

這種工作方式是 - 1)發送命令來與新的參數值的儀器,2)讀取參數從儀器回來,我可以看到究竟發生了什麼(例如,我嘗試設置高於中心頻率儀器將處理的最大值,它告訴我它將實際處理的內容),以及3)用從儀器接收的實際值更新程序變量。

因爲有很多參數需要更新,我想使用一個通用例程。部分我似乎無法讓我的腦子在周圍更新我的代碼中的變量與通過背景工具從儀器返回的內容。如果我爲每個參數使用單獨的RunWorkerCompleted事件,則可以將更新直接連接到變量。我想提出一種使用能夠更新任何變量的單個例程的方法。我所能想到的是傳遞一個引用號(每個參數都不相同)並在RunWorkerCompleted處理程序中使用switch語句來指示結果。一定有更好的方法。

+2

你能展示一些代碼來給我們一個更好的想法,你想要做什麼? – t0mm13b

回答

0

[編輯 - 回顧更新歷史記錄以查看以前的答案。談論無法看到樹的木材]

是否有任何理由,而不是傳遞一個參考號碼給後臺工作者,你不能傳遞應該更新的標籤的ID價值傳回?

所以UI中含有工作隊列增加了一個文件:

  • 變量改變
  • 嘗試的改變
  • UI ID

和BackgroundWorker的觸發用含有EventArgs的事件

  • 試圖改變
  • 嘗試
  • UI ID
  • 錯誤信息(如果爲null成功)後的實際值

這是你需要不需要通過交換機或多個事件參數來更新你的UI中的所有信息,沒有你的後臺工作人員知道UI細節。

+0

好的 - 謝謝你的幫助。我最初是在尋找類似引用參數的東西,但是看不到任何方式來建立連接。再次感謝。 – Bruce

+0

這是一個非常有趣的想法!我會研究它。再次感謝 - 布魯斯 – Bruce

0

這樣的事情呢?

[TestFixture] 
public class BGWorkerTest 
{ 
    string output1; 
    string output2; 

    [Test] 
    public void DoTest() 
    { 
     var backgroundWorker = new BackgroundWorker(); 
     backgroundWorker.DoWork += (sender, args) => 
            { 
             output1 = DoThing1(); 
             output2 = DoThing2(); 
            }; 
     backgroundWorker.RunWorkerAsync(); 
     //Wait for BG to finish 
     Thread.Sleep(3000); 
     Assert.AreEqual("Thing1",output1); 
     Assert.AreEqual("Thing2",output2); 
    } 

    public string DoThing1() 
    { 
     Thread.Sleep(1000); 
     return "Thing1"; 
    } 
    public string DoThing2() 
    { 
     Thread.Sleep(1000); 
     return "Thing2"; 
    } 
} 
+0

會不會否定使用後臺工作者的觀點? –

+0

不確定你的意思?如果你的意思是睡眠,我只是把它放在那裏來說明在給定的時間之後,方法已經運行並且設置了正確的值。 – Simon

1

我想我會做的是傳遞參數值,和代表BackgroundWorker的列表。這樣,您可以「同步」編寫分配代碼,但延遲執行直到實際檢索值。

開始與「請求」類,它看起來是這樣的:

class ParameterUpdate 
{ 
    public ParameterUpdate(string name, string value, Action<string> callback) 
    { 
     this.Name = name; 
     this.Value = value; 
     this.Callback = callback; 
    } 

    public string Name { get; private set; } 
    public string Value { get; set; } 
    public Action<string> Callback { get; private set; } 
} 

然後再編寫異步代碼使用此:

private void bwUpdateParameters_DoWork(object sender, DoWorkEventArgs e) 
{ 
    var updates = (IEnumerable<ParameterUpdate>)e.Argument; 
    foreach (var update in updates) 
    { 
     WriteDeviceParameter(update.Name, update.Value); 
     update.Value = ReadDeviceParameter(update.Name); 
    } 
    e.Result = updates; 
} 

private void bwUpdateParameters_RunWorkerCompleted(object sender, 
    RunWorkerCompletedEventArgs e) 
{ 
    var updates = (IEnumerable<ParameterUpdate>)e.Argument; 
    foreach (var update in updates) 
    { 
     if (update.Callback != null) 
     { 
      update.Callback(update.Value); 
     } 
    } 
} 

這裏是你將如何揭開序幕更新。比方說,你有一堆要與中使用的參數的實際值更新成員域:

// Members of the Form/Control class 
private string bandwidth; 
private string inputAttenuation; 
private string averaging; 

// Later on, in your "update" method 
var updates = new List<ParameterUpdate> 
{ 
    new ParameterUpdate("Bandwidth", "3000", v => bandwidth = v), 
    new ParameterUpdate("InputAttenuation", "10", v => inputAttenuation = v), 
    new ParameterUpdate("Averaging", "Logarithmic", v => averaging = v) 
}; 
bwUpdateParameters.RunWorkerAsync(updates); 

這就是你必須做的。所有的實際工作都是在後臺完成的,但是您正在編寫簡單的變量賦值語句,就好像它們在前臺一樣。由於實際分配在RunWorkerCompleted事件中執行,因此代碼很短,很簡單,並且完全線程安全。

如果你需要做的不止此,比如除了變量更新的控制,這是非常簡單的,你可以把你想要的回調東西,即:

new ParameterUpdate("Bandwidth", "3000", v => 
{ 
    bandwidth = v; 
    txtBandwidth.Text = v; 
}) 

再次,這將工作因爲它在工作完成之前並沒有真正執行。