wpf 在主线程中运行代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20300164/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 10:08:20  来源:igfitidea点击:

Run code in main thread

c#wpfmultithreadingwinformsthread-safety

提问by Alex Zhukovskiy

It's similar to many questions, but not rly. I need something like BeginInvokefor Winforms, but not for winforms only. So i need single method, that works for any type of application, so i'm calling

它与许多问题相似,但不完全相同。我需要类似BeginInvokeWinforms 的东西,但不仅仅是 Winforms。所以我需要单一的方法,适用于任何类型的应用程序,所以我打电话

void ExecuteInMainContext(Action action)
{
   ...
}

and it should work, be called from Console, winforms, wpf and so on. All methods i saw was using BeginInvokefor winforms, Dispatcher.Invokefor WPF etc. But i should call it from library and i don't know from where it's called. And it also should be transparent to calling code, so it shouldn't pass something like pointer to calling main thread etc, lib should get this info itself from environment, not from user code and without any global variables, of course.

它应该可以工作,可以从控制台、winforms、wpf 等调用。我看到的所有方法都BeginInvoke用于 winforms、Dispatcher.InvokeWPF 等。但我应该从库中调用它,我不知道从哪里调用它。并且它也应该对调用代码透明,因此它不应该传递诸如指向调用主线程等的指针之类的东西,当然,lib 应该从环境中获取此信息,而不是从用户代码中获取,并且没有任何全局变量。

I've tried to use Task.ConfigureAwait, but it didn't help.

我试过使用Task.ConfigureAwait,但没有帮助。

i found this one

我找到了这个

You can't do this (without a lot of work) in a Console application. The mechanisms built into the TPL for marshaling the call back onto a thread all rely on the thread having an installed SynchronizationContext. This typically gets installed by the user interface framework (ie: Application.Run in Windows Forms, or in WPF's startup code, etc).

您不能在控制台应用程序中执行此操作(无需大量工作)。TPL 中内置的用于将回调编组回线程的机制都依赖于安装了 SynchronizationContext 的线程。这通常由用户界面框架安装(即:Windows 窗体中的 Application.Run,​​或 WPF 的启动代码等)。

but I hope it's possible.

但我希望这是可能的。

code for tests:

测试代码:

using System;
using System.Threading;

namespace Test
{
    class Program
    {
        private static void Main(string[] args)
        {

            Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);
            Publisher publisher = new Publisher(Method);
            Console.ReadLine();
        }

        private static void Method(string s)
        {
            Console.WriteLine(s + " " + Thread.CurrentThread.ManagedThreadId);
        }

    }

    class Publisher
    {
        public event Action<string> Action;

        protected virtual void OnAction(string obj)
        {
            Action<string> handler = Action;
            if (handler != null)
            {
                SafeCall(() => handler(obj));
            }
        }

        private static void SafeCall(Action action)
        {
            // ???
            action(); // should write 1
        }

        public Publisher(Action<string> action)
        {
            Action = action;
            Console.WriteLine("Publisher thread: " + Thread.CurrentThread.ManagedThreadId);
            Thread thread = new Thread(() => OnAction("hello"));
            thread.Start();
        }
    }
}

so it should write same number anywhere.

所以它应该在任何地方写相同的数字。

采纳答案by yo chauhan

Try this

尝试这个

void ExecuteInMainContext(Action action)
    {
        var synchronization = SynchronizationContext.Current;
        if (synchronization != null)
        {
            synchronization.Send(_ => action(), null);//sync
            //OR
            synchronization.Post(_ => action(), null);//async
        }
        else
            Task.Factory.StartNew(action);

        //OR
        var scheduler = TaskScheduler.FromCurrentSynchronizationContext();

        Task task = new Task(action);
        if (scheduler != null)
            task.Start(scheduler);
        else
            task.Start();
    }