2013-05-06 84 views
8

我在一些非GUI線程上創建了一個SolidColorBrush,並且想將它傳遞給一個GUI線程來顯示它,但是我得到了InvalidOperationExceptionThe calling thread cannot access this object because a different thread owns it.(即使我嘗試了Freeze();它)。我如何傳遞是在線程X創建線程ÿ對象?如何傳遞是在線程X中創建一個WPF對象,線程Y'

我知道我可以在GUI線程中使用Dispatcher創建此SolidColorBrush對象,但這會使所有事情變得複雜......我想在工作線程中創建它。


的附加細節:

我初始化一些靜態代表在一些靜態類,以允許將來自業務層消息到GUI:

public static class Gui{ 
    private static PrintMethodDelegate _printMethod; 
    public static void InitializeGuiInterface(PrintMethodDelegate printMethod){ 
     _printMethod = printMethod; 
    } 
    public static void Print(GuiMessage data) { _printMethod(data); } 
} 

初始化(在GUI線程):

Gui.InitializeGuiInterface(_messagesToUserHandler.PrintMessage); 

然後在另一個(non-gui)線程中,我使用它:

Gui.Print(new GuiMessage(testDescription) { Foreground = new SolidColorBrush(someColor) }); 

GuiMessage是:

public class GuiMessage { 
    public string Msg { get; set; } 

    private SolidColorBrush _foregroundBrush; 
    public SolidColorBrush Foreground 
    { 
     get { return _foregroundBrush; } 
     set { _foregroundBrush = value; } 
    } 
} 
+0

您是否嘗試將錯誤消息寫入Google?它返回我們可能給出的所有答案。 – I4V 2013-05-06 06:55:23

+1

我想簡短的答案是你不能。應該在UI線程上創建和處理所有與GUI相關的控件/工件。 – 2013-05-06 06:59:48

+0

@ I4V:是的,我試過了。謝謝你的建議。 – Tar 2013-05-06 07:11:39

回答

6

你可以在另一個線程中創建wpf資源,如果你freeze他們,那麼元素可以傳遞到另一個線程或gui線程。 請記住,一次凍結的對象只能通過複製並使用該副本進行修改。您無法凍結具有綁定或動畫的對象。

+0

就是這樣。我立即凍結屬性設置器中的「刷子」。所以這不是一個多線程的限制......它被設計成這種類型的對象('Freezable's) – Tar 2013-05-06 13:40:47

1

您需要使用代理安全調用控制。

使用

Control.Invoke

Control.BeginInvoke

用於這一目的。

private delegate void SetControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue); 

public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue) 
{ 
    if (control.InvokeRequired) 
    { 
    control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue }); 
    } 
    else 
    { 
    control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue }); 
    } 
} 

如果您不使用委託來安全地調用它們,您將會得到異常。

檢查這些鏈接:

How to update the GUI from another thread in C#?enter link description here

enter link description here

+0

我看到了,但如果'Brush'是在非GUI線程中創建的,那麼這將不會對我有所幫助。我只解決了想要在GUI線程中創建的對象上調用的問題,反之亦然。 – Tar 2013-05-06 07:14:51

0

您應該使用Dispatcher

您可以創建一個類,將舉行一個調度員在主線程創建,並通過您的容器上需要與你的主線程交互的後臺線程無論什麼階級執行它注入。

public interface IUiDispatcher 
{ 
    Dispatcher Dispatcher { get; } 
} 

public class UiDispatcher : IUiDispatcher 
{ 
    public UiDispatcher() 
    { 
     if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA 
      && !Thread.CurrentThread.IsBackground 
      && !Thread.CurrentThread.IsThreadPoolThread) 
     { 
      this.Dispatcher = Dispatcher.CurrentDispatcher; 
     } 
     else 
     { 
      throw new InvalidOperationException("Ui Dispatcher must be created in UI thread"); 
     } 
    } 

    public Dispatcher Dispatcher { get; set; } 
} 

public class ExecutedOnABackgroundThread 
{ 
    IUiDispatcher uidispatcher; 

    public ExecutedOnABackgroundThread(IUiDispatcher uidispatcher) 
    { 
     this.uidispatcher = uidispatcher; 
    } 

    public void Method() 
    { 
     // Do something on the background thread... 
     // ... 

     // Now we need to do something on the UI 
     this.uidispatcher.Dispatcher.BeginInvoke(new Action(delegate 
     { 
      // Do something 
     }), null); 
    } 
} 

在一個點你肯定你是在UI線程上,例如應用程序的初始化過程中創建的UiDispatcher實例。使用你的依賴注入容器,確保只創建這個類的一個實例,並將其注入到需要它的任何其他類中,並用它來創建/操作UI組件。

我選擇了代碼來檢查UiDispatcher的構造函數是否在this answer的主線程中執行。

問題是,你不能在UI線程上使用在不同線程上創建的東西。所以你需要你的後臺線程委託給主UI線程,無論涉及UI的東西。

+0

正如我所說的,「我知道我可以在GUI線程中使用Dispatcher創建這個'SolidColorBrush'對象,但這會使所有事情複雜化......我想在工作線程中創建它」 – Tar 2013-05-06 08:15:16

+0

是的,我讀過它。但我不確定會發生什麼複雜的事情。特別是如果你只需要使用'this.dispatcher.BeginInvoke'。你如何在UI線程上使用在後臺線程上創建的東西? [除了將創作委託給用戶界面主題,沒有別的辦法](http://www.google.com.sg/#output=search&sclient=psy-ab&q=The+calling+thread+cannot+access+this+object+因爲+ A +不同+線+擁有+ IT)。 – Guillaume 2013-05-06 08:20:45

+0

我搜索了這個,並認爲這是不可能做到的荒謬。您不能將某些內存段的數據複製到其他內存段?克隆對象?這個不成立。爲什麼這個限制存在? – Tar 2013-05-06 10:42:20

相關問題