问题
It's similar to many questions, but not rly. I need something like BeginInvoke
for Winforms, but not for winforms only. So i need single method, that works for any type of application, so i'm calling
void ExecuteInMainContext(Action action)
{
...
}
and it should work, be called from Console, winforms, wpf and so on. All methods i saw was using BeginInvoke
for winforms, Dispatcher.Invoke
for 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.
I've tried to use Task.ConfigureAwait
, but it didn't help.
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).
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.
回答1:
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();
}
来源:https://stackoverflow.com/questions/20300164/run-code-in-main-thread