2011-10-06 37 views
1

我以前有過這種問題,通過從自定義類中引發的事件更新GUI元素,但我可以用類似的東西繞過它:線程之間傳遞對象會導致異常,因爲不同的線程擁有它

MyTextBlock.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
     (Action)(() => { LoggingTextBlock.Text += Message += "\r\n"; })); 

我認爲這個問題對於UI線程是唯一的,但顯然它適用於所有線程。不幸的是,我的自定義類沒有像UIElements那樣調用.Dispatcher()例程。那麼你應該如何將對象傳遞給其他線程並讓它們能夠使用它們?

例如,我有一個基本偵聽器類,其主要工作基本上是查找一些數據,引發事件並傳遞該數據。以下是數據類的部分,我想經過:

// Just the class for carrying the job data. 
public class JobData 
{ 
    // NOTE: I don't no have trouble accessing these properties from a 
    // different thread 
    public string SomeProperty1 { get; set; } 
    public string SomeProperty2 { get; set; } 
    public string SomeProperty3 { get; set; } 

    // ... 
    // more properties 
    // ... 

    // This a .NET object of type System.Printing.PrintSystemJobInfo. This 
    // is the guy that gives me trouble. Later on, I can't access members 
    // of Job without getting the "The calling thread cannot access this 
    // object because a different thread owns it" error. 
    PrintSystemJobInfo m_Job = null; 
    public PrintSystemJobInfo Job 
    { 
     get 
     { 
      if (m_Job == null) 
      { throw new ArgumentNullException(); } 

      return m_Job; 
     } 

     set { m_Job = value; } 
    } 
} 

以下是在一個線程中運行的類的部分,收集數據,並觸發事件來傳遞數據給關有人在傾聽。

// Thread who monitors looking for data to package into JobData and send 
// to any listeners. 
public class JobMonitor 
{ 
    public delegate void NewJobEvent(JobData jobStuff); 
    public event NewJobEvent NewJob; 

    // Call this when you have some job data and need to notify listeners 
    private void OnNewJob(object newJobData) 
    { 
     JobData newJobData = (JobData)newJobData; 
     if (NewJob != null) 
     { 
      NewJob(newJobData); 
     } 
    } 

    private void WorkerRoutine() 
    { 
     while(true) 
     { 
      // Wait for data 

      // ... 
      // ... 

      // when data is found 

      JobData myJobData = new JobData(); 
      myJobData.SomeProperty1 = "some data"; 
      myJobData.SomeProperty2 = "some data"; 

      int jobID = GetCurrentJobID(); 
      string printerName = GetCurrentPrinterName(); 

      // .NET class System.Printing.PrintQueue 
      PrintQueue printQueue = new PrintQueue(new PrintServer(), printerName); 

      PrintSystemJobInfo jobInfo = null; 
      jobInfo = printQueue.GetJob(jobID); 

      // This is the guy in my JobData class that I'll have trouble accessing 
      // later on. 
      myJobData.Job = jobInfo; 

      // Time to fire off the event 
      OnNewJob(myJobData); 
     } 
    } 
} 

以下是實例化JobMonitor類並捕獲其事件的類的一部分。它無法訪問JobMonitor的其中一個屬性。

// This class signs up to recieve and process events from the JobMonitor class. 
public class JobProcessor 
{ 
    // this is the method that handles the incoming job events. This is where 
    // i have trouble. 
    private void NewJobEventHandler(JobData newJob) 
    { 
     string temp = newJob.SomeProperty1; // this works fine 

     bool bTemp = newJob.Job.IsPaused; // this throws an exception "The 
              // calling read cannot access this 
              // object because a different thread 
              // owns it" 
    } 

    private JobMonitor m_monitor = null; 
    public JobProcessor() 
    { 
     m_monitor = new JobMonitor(); 

     //attaches a method to handle incoming job events. 
     m_monitor.NewJob += new JobMonitor.NewJobEvent(NewJobEventHandler); 
     m_monitor.Start(); 
    } 
} 

所以JobProcessor.NewJobEventHandler()方法是在那裏我得到的例外「因爲不同的線程擁有它調用線程不能訪問該對象」。我需要能夠訪問此屬性和下面的屬性和方法。我需要做什麼才能訪問我需要的內容?

回答

2

我想看看由System.Threading提供的SyncronizationContext。該類具有一個靜態屬性Current,它將提供調用您正在查找的Dispatcher樣式。

其他可能性

如果你想處理在不同的線程比創建您的JobData類的事件,那麼你可能需要將PrintSystemJobInfo的實際檢索移動到事件處理程序。

另一種方法是將您創建的新類(不具有線程關聯性)抽象出System類。

+0

嗯,我等了一會兒,看看是否還有其他建議可能出現。 「SyncronizationContext」方法對我來說並沒有結果。我對這個概念有點遺憾,所以我很可能做錯了。幸運的是,檢索PrintSystemJobInfo對象很容易,並且有足夠的信息可供我的目標線程自行獲取此對象。理想情況下,我不必這樣做,我的目標線程不需要知道如何獲取這些信息。哦,對我來說,放眼未來它並不是一個妥協。 – Ultratrunks

相關問題