Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 来自MTA的STA呼叫_C#_.net_Multithreading_Sta_Mta - Fatal编程技术网

C# 来自MTA的STA呼叫

C# 来自MTA的STA呼叫,c#,.net,multithreading,sta,mta,C#,.net,Multithreading,Sta,Mta,我刚刚开始处理STA/MTA问题,因此,对于问题的简单性表示歉意。在这个阶梯的底部,我找不到一个我能真正理解的答案 我正在为另一个软件编写插件,在一个工作线程中,我需要创建一些UI元素。我明白我不能从工作线程内部完成这项工作,因为它不是STA线程,我需要返回主(或者只是另一个?)STA线程来创建UI元素。一些澄清将大有帮助 是否所有STA线程都具有相同的“权限”,即如果主线程是STA并创建了一个窗口,则会向其中添加一些UI元素。然后衍生出另一个STA线程,第二个线程同样创建了一些UI元素,它们是

我刚刚开始处理STA/MTA问题,因此,对于问题的简单性表示歉意。在这个阶梯的底部,我找不到一个我能真正理解的答案

我正在为另一个软件编写插件,在一个工作线程中,我需要创建一些UI元素。我明白我不能从工作线程内部完成这项工作,因为它不是STA线程,我需要返回主(或者只是另一个?)STA线程来创建UI元素。一些澄清将大有帮助

  • 是否所有STA线程都具有相同的“权限”,即如果主线程是STA并创建了一个窗口,则会向其中添加一些UI元素。然后衍生出另一个STA线程,第二个线程同样创建了一些UI元素,它们是否在同一个“空间”(糟糕的单词选择,但我不知道还能使用什么)中进行操作,并且可以访问彼此的UI元素而不会造成死亡和破坏?或者我是否需要显式跳回主/原始STA线程,并且仅从该(而不仅仅是任何)STA线程创建UI元素

  • 如果是这种情况(只允许1个STA线程生成UI元素),我如何正确地做到这一点?我看过很多与此相关的帖子,但出于某种原因,我不能完全理解到底发生了什么,我希望得到一个真正简单的答案

  • 请不要“这是一个很酷的方法…”我只需要一个简单的方法,在执行点,我需要一些UI元素跳回到主STA线程,如果这是必要的

    如果没有必要,那么我将只让该工作线程成为STA线程并继续我的方式,这公平吗?还是我在制造灾难

  • 如果线程创建控件。即使存在其他STA线程,也只有该特定线程可以与其交互
  • 在WinForms中,您可以在控件上调用一个方法:
    control.invoke
    。在WPF中,您可以由调度程序执行:
    dispatcher.invoke
  • WinForms:

    form1.Invoke(/* a delegate for your operation */)
    
    WPF:

    您所做的不是更改“单个单元”中的对象,而是请求(调用)控制它的STA线程(调用的委托)为您执行该操作。您还可以使用
    BeginInvoke
    进行异步操作

    如果主线程是STA并创建了一个窗口,则向其中添加一些UI元素。然后产生另一个STA线程,第二个线程同样创建一些UI元素,它们是否在同一个“空间”[snip…]中进行操作,并且可以访问彼此的UI元素而不会造成死亡和破坏

    如果线程A和线程B都是STA,那么它们可以各自创建和更新自己的UI元素,但不能相互创建和更新。任何其他想要影响UI的线程都必须使用
    BeginInvoke
    风格的方法之一来请求相应的线程进行更新

    如果没有必要,那么我将只让该工作线程成为STA线程并继续我的方式,这公平吗?还是我在制造灾难

    如果工作线程已设置为MTA并已初始化,则可能无法使其成为STA线程。你可能得做一条新线

    你是怎么做到的?您似乎希望在UI中使用WPF(
    System.Windows.*
    ),因此,如果您正在“插入”的应用程序也在使用WPF,您应该能够访问它并重新使用它的UI线程。如果没有,您可以创建一个新线程,并在其上创建一个新的
    应用程序
    ,然后调用
    Run
    。这将为您设置一个调度程序

    类似这样的东西(伪代码是从其他地方的一些工作代码复制过来的)


    等等

    STA和MTA是与COM编程相关的术语。你真的在做COM吗?如果不是这样,那么只需要关注保持UI线程安全的需要,并使用类库提供的基本原语封送调用。Winforms中的Control.Begin/Invoke(),WPF或应用商店中的Dispatcher.Begin/Invoke()。这是我收到的错误:System.InvalidOperationException:调用线程必须是STA,因为许多UI组件都需要它。因此,我认为这是STA/MTA问题。我并没有明确地使用COM(我知道),但我正在为一个更大的软件编写一个插件,我知道它正在使用COM。你应该更多地了解你正在编写插件的“更大”软件的体系结构。有些应用程序有多线程UI,每个主UI窗口都位于自己的线程中。举几个例子:微软Word,Windows资源管理器。你的主机应用程序会是这种情况吗?我想我正在使用WinForms(C#的新功能),所以想法应该是,首先为我想要创建所有UI元素的线程创建一个Dispatcher对象单例样式,并在需要时随时抓住它?对不起,我想我正在做WPF查看您的编辑。我只是以编程方式创建一个窗口,然后向面板添加控件,并使面板成为该面板的窗口内容。WPF,对吗?调度员是WPF。在winforms中,表单基本上是windows。它们具有作为控件的按钮和文本框。如果您有一些非STA线程想要更新UI。它需要一个对该表单的引用(比如说,_mainForm是名称),只需调用invoke
    _mainForm.invoke(()=>_button.Text=“New button”)我没有运行任何表单。软件的主要部分对我来说是一个黑匣子。在我这方面,我正在创建一个新窗口(System.Windows.window win=new window())并向其中添加控件。在这里不想太复杂:)所以我需要在进入辅助线程之前在主线程上提前创建该窗口?@AaronMarcus System。Windows是WPF名称空间,所以您不使用winforms。在这种情况下,您需要使用dispatcher:
    win.dispatcher.Invoke(()=>/*需要在STA线程下运行的任何代码*/)
    Ok。但我仍然需要它
    window1.Dispatcher.Invoke(/* a delegate for your operation */)
    
    Dispatcher dispatcher = null; // we 'get to' the UI thread via the dispatcher
    
    if(Application.Current) { // re use an existing application's UI thread
        dispatcher = Application.Current.Dispatcher;
    } else {
        var threadReadyEvent = new ManualResetEvent(false);
    
        var uiThread = new Thread(() => {
            Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
    
            var application = new Application();
            application.Startup += (sender, args) => {
                dispatcher = application.Dispatcher;
                threadReadyEvent.Set();
            };
    
            // apps have to have a "main window" - but we don't want one, so make a stub
            var stubWindow = new Window {
                Width = 1, Height = 1, 
                ShowInTaskbar = false, AllowsTransparency = true,
                Background = Brushes.Transparent, WindowStyle = WindowStyle.None
            };
            application.Run(stubWindow);
        }){ IsBackground = true };
    
        uiThread.Start();
        threadReadyEvent.WaitOne();
        threadReadyEvent.Dispose();
    }
    
    dispatcher.Invoke(() => {
        // ask the UI thread to do something and block until it finishes
    });
    
    dispatcher.BeginInvoke(() => {
        // ask the UI thread to do something asynchronously
    });