道歉我的问题和努力并不准确。我正在开发具有不同组件的控制台应用程序。现在我已将它们分离并希望它们使用异步发布者/订阅者方式进行交互;类似于WPF。所以在这种情况下,我将有一个主线程,它始终存在,并根据请求它将调用事件,例如DataRequested将在后台线程上触发。一旦后台线程完成进程,它将再次触发事件,例如DataCompleted应返回调用线程,即主线程。我希望我的解释清楚。
So far I have coded below; where I have EventBroker.
public class EventBroker
{
public static event EventHandler SubscriptionAdded;
public static event EventHandler SubscriptionRemoved;
private static volatile EventBroker instance;
private static object syncRoot = new Object();
private static Dictionary<string, List<Delegate>> subscriptions;
/// <summary>
/// Initializes a new instance of the <see cref="T:EventBroker"/> class.
/// </summary>
private EventBroker()
{
}
/// <summary>
/// Gets the instance.
/// </summary>
/// <value>The instance.</value>
public static EventBroker Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new EventBroker();
subscriptions = new Dictionary<string, List<Delegate>>();
}
}
}
return instance;
}
}
/// <summary>
/// Gets or sets the internal subscriptions dictionary.
/// </summary>
/// <value>The subscriptions.</value>
private static Dictionary<string, List<Delegate>> Subscriptions
{
get { return EventBroker.subscriptions; }
set
{
lock (syncRoot)
{
EventBroker.subscriptions = value;
}
}
}
/// <summary>
/// Raises the subscription added event.
/// </summary>
/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
private static void OnSubscriptionAdded(EventArgs e)
{
if (SubscriptionAdded != null)
SubscriptionAdded(instance, e);
}
/// <summary>
/// Raises the subscription removed event.
/// </summary>
/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
private static void OnSubscriptionRemoved(EventArgs e)
{
if (SubscriptionRemoved != null)
SubscriptionRemoved(instance, e);
}
/// <summary>
/// Subscribe method to the specified event.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="method">The method Delegate to be invoked when Event fires.</param>
public static void Subscribe(string id, Delegate method)
{
//Check if there is a existing event
List<Delegate> delegates = null;
if (Subscriptions == null)
Subscriptions = new Dictionary<string, List<Delegate>>();
if (Subscriptions.ContainsKey(id))
{
delegates = subscriptions[id];
}
else
{
delegates = new List<Delegate>();
Subscriptions.Add(id, delegates);
}
delegates.Add(method);
OnSubscriptionAdded(new EventArgs());
}
/// <summary>
/// Unsubscribe method from event notifications
/// </summary>
/// <param name="id">The id.</param>
/// <param name="method">The method.</param>
public static void Unsubscribe(string id, Delegate method)
{
if (Subscriptions.ContainsKey(id))
{
if (Subscriptions[id].Contains(method))
{
Subscriptions[id].Remove(method);
OnSubscriptionRemoved(new EventArgs());
}
if (Subscriptions[id].Count == 0)
Subscriptions.Remove(id);
}
}
/// <summary>
/// Fire the specified event by and pass parameters.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="args">The args.</param>
public static void Execute(string id, object sender, EventArgs e)
{
if (Subscriptions.ContainsKey(id))
{
for (int i = 0; i < Subscriptions[id].Count; i++)
{
Delegate x = Subscriptions[id][i];
DynamicInvoke(id, x, sender, e);
if (!Subscriptions.ContainsKey(id))
break;
}
}
}
/// <summary>
/// Checks to see if target of invocation is still a valid
/// (non-disposed objects). Then it dinamicly invokes Delegate.
/// </summary>
/// <param name="id">Event ID</param>
/// <param name="x">Delegate to invoke</param>
/// <param name="args">Object array of arguments</param>
private static void DynamicInvoke(string id, Delegate x, object sender, EventArgs e)
{
if (x.Method != null)
{
if (x.Target is Control)
{
Control ctl = (Control)x.Target;
if (ctl.IsDisposed)
{
Unsubscribe(id, x);
return;
}
}
if (x.Target == null)
{
Unsubscribe(id, x);
return;
}
x.DynamicInvoke(sender, e); ***//this becomes blocking call untill EventHandle is completed and hangs Master Thread***
}
}
}
我使用此EventBroker来跟踪我的订阅者,一旦Publisher来了,我就会调用某个委托。但它仅在Master线程上调用,并且被挂起。我想在单独的线程上调用EventHandler。
public class MasterClass
{
public MasterClass()
{
EventBroker.Subscribe("Topic2", new EventHandler<EventArgs<string>>(CallBackfromWorker));
}
public void InvokeTest()
{
EventArgs<string> EventArgs = new EventArgs<string>("Test");
EventBroker.Execute("Topic1", null, EventArgs); //I want both of this to be asynchronous.
}
public void CallBackfromWorker(object sender, EventArgs<string> e)
{
Debug.Pring("Get Called Asynchronously from Worker thread through Event");
}
}
**//Worker Class**
public class WorkerClass
{
public WorkerClass()
{
EventBroker.Subscribe("Topic1", new EventHandler<EventArgs<string>>(HandleRapRequest1));
}
public void HandleRapRequest1(string RAPRequest)
//public void HandleRapRequest1(object sender, EventArgs<string> e)
{
Logger.LogToDisplay("WorkerClass Request" + RAPRequest);
Logger.LogToDisplay("AsyncClient : " + System.Threading.Thread.CurrentThread.IsBackground);
Logger.LogToDisplay("AsyncClient : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
Logger.LogToDisplay("Going to Sleep");
System.Threading.Thread.Sleep(10000); ***//Hangs my Master Thread***
EventBroker.Execute("Topic2", null, EventArgs); //I want both of this to be asynchronous.
}
}
所以底线是我在控制台应用程序中寻找异步基于事件的发布者/订阅者...类似于CAB事件罪SCSF和WPF ......
由于
答案 0 :(得分:4)
这很简单:
public class Foo
{
public event Action MyEvent;
public void FireEvent()
{
Action myevent = MyEvent;
if (myevent != null)
{
Task.Factory.StartNew(() => myevent())
.ContinueWith(t =>
{
//TODO code to run in UI thread after event runs goes here
}, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext());
}
}
}
如果您使用的是C#5.0,则可以使用await
来简化此代码:
public class Foo
{
public event Action MyEvent;
public async Task FireEvent()
{
Action myevent = MyEvent;
if (MyEvent != null)
{
await Task.Run(() => myevent());
//TODO code to run in UI thread after event runs goes here
}
}
}
如果您不需要在UI线程中运行的代码在事件处理程序全部完成后启动,并且它可以同时继续在UI线程上运行,您还可以将代码简化为:
public class Foo
{
public event Action MyEvent;
public void FireEvent()
{
Action myevent = MyEvent;
if (MyEvent != null)
{
Task.Factory.StartNew(() => myevent());
//TODO code to run in UI thread while event handlers run goes here
}
}
}