-4

抱歉,我的问题和努力不准确。我正在开发具有不同组件的控制台应用程序。现在我已经将它们解耦并希望它们使用异步发布者/订阅者方式进行交互;类似于 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 来跟踪我的订阅者,一旦发布者到来,我就会调用某个委托。但它只在主线程上被调用并被挂起。我想在单独的线程上调用 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 事件 sin SCSF 和 WPF ......

谢谢

4

1 回答 1

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
        }
    }
}
于 2013-02-13T16:42:36.323 回答