0

我有一個庫,它使用來自異步tcp操作的事件數據。 雖然我得到跨線程操作異常,但在UI中收到它們之後在控件中使用這些數據時。如何在圖書館的消費者獲得數據顯示在他的控制之前解決這個問題。所以基本上我需要把數據放到自己的線程中使用庫?如何從另一個線程安全地使用數據控件?

用於具有鏈接文件的緊湊框架的相同代碼。

我在圖書館內使用這個方法有一個幫助控制說,如果調用是必需的,但它不工作。

public static void InvokeIfNecessary(Control control, Action setValue) 
{ 

    if (control.InvokeRequired) 
    { 
     control.Invoke(setValue); 
    } 
    else 
    { 
     setValue(); 
    } 
} 

使用事件向使用該庫的用戶提供數據的示例代碼。

if (OnClientChangeConnection != null) SafeData.InvokeIfNecessary(_helpControl,() => OnClientChangeConnection(ConnectedClients, requestClientInfo)); // ConnectedClients is an integer and requestClientInfo is a List<ClientInfo> class type. 

謝謝。

+0

爲什麼它不工作的一類?怎麼了? – SLaks 2011-05-16 20:36:00

+0

我不明白它,它只是從來沒有進入control.Invoke(setValue)如果。該庫用於異步TCP通信目的。奇怪的是在Compact Framework上我沒有問題。 – 2011-05-16 20:38:51

+0

你在調試器中看到什麼? – SLaks 2011-05-16 21:01:02

回答

0

您可以從UI線程保存對SynchronizationContext.Current的引用,然後調用其PostSend方法在UI線程上運行代碼。

1

正確的方法是使用SynchronizationContext對象。我已經包含示例代碼。基本上你必須做的是把你的線程任務包裝在一個類中,該類可以保存對主線程提供的同步上下文對象和回調的引用,然後在工作關閉後調用它們。

這是一個簡單的形式:

public partial class Form1 : Form 
{ 
    private SynchronizationContext _synchronizationContext; 

    public Form1() 
    { 
     InitializeComponent(); 
     //Client must be careful to create sync context soimehwere they are sure to be on main thread 
     _synchronizationContext = AsyncOperationManager.SynchronizationContext; 
    } 

    //Callback method implementation - must be of this form 
    public void ReceiveThreadData(object threadData) 
    { 
     // Can use directly in UI without error 
     this.listBoxMain.Items.Add((string)threadData); 
    } 

    private void DoSomeThreadWork() 
    { 
     // Thread needs callback and sync context. 
     // You probably want to derive your own callback from the NET SendOrPostCallback class. 
     SendOrPostCallback callback = new SendOrPostCallback(ReceiveThreadData); 
     SomeThreadTask task = new SomeThreadTask(_synchronizationContext, callback); 
     Thread thread = new Thread(task.ExecuteThreadTask); 
     thread.Start(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     DoSomeThreadWork(); 
    } 

} 

這是具有線程任務

/// SomeThreadTask defines the work a thread needs to do and also provides any data required along with callback pointers etc. 
/// Populate a new SomeThreadTask instance with a synch context and callnbackl along with any data the thread needs 
/// then start the thread to execute the task. 
/// </summary> 
public class SomeThreadTask 
{ 

    private string _taskId; 
    private SendOrPostCallback _completedCallback; 
    private SynchronizationContext _synchronizationContext; 

    /// <summary> 
    /// Get instance of a delegate used to notify the main thread when done. 
    /// </summary> 
    internal SendOrPostCallback CompletedCallback 
    { 
     get { return _completedCallback; } 
    } 

    /// <summary> 
    /// Get SynchronizationContext for main thread. 
    /// </summary> 
    internal SynchronizationContext SynchronizationContext 
    { 
     get { return _synchronizationContext; } 
    } 

    /// <summary> 
    /// Thread entry point function. 
    /// </summary> 
    public void ExecuteThreadTask() 
    { 

     //Just sleep instead of doing any real work 
     Thread.Sleep(5000); 

     string message = "This is some spoof data from thread work."; 

     // Execute callback on synch context to tell main thread this task is done. 
     SynchronizationContext.Post(CompletedCallback, (object)message); 


    } 

    public SomeThreadTask(SynchronizationContext synchronizationContext, SendOrPostCallback callback) 
    { 
     _synchronizationContext = synchronizationContext; 
     _completedCallback = callback; 
    } 

} 
+0

謝謝你的時間,這看起來是一個很好的解決方案,我會標記爲答案的第一個,並指出你作爲某種方式分享一些功勞。比你 – 2011-05-16 22:13:46

相關問題