2013-05-06 87 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

相关问题