【问题标题】:Object that can receive a delegate and invoking every N time each delegate [duplicate]可以接收委托并在每个委托中每 N 次调用一次的对象 [重复]
【发布时间】:2019-01-25 21:01:54
【问题描述】:

如何创建一个异步结构,该结构将由一堆委托组成并弹出它们并每 N 毫秒调用它们中的每一个?

现在的问题是我有很多委托在 ui 上调用更改,这会导致 ui 冻结,所以如果堆栈不为空,如何让这个委托每 N 毫秒调用一次。

现在我有了这个

    class CallbackRestriction
    {
        private Stack<KeyValuePair<Action<ImageWrapper>, ImageWrapper>> _callbackList = 
            new Stack<KeyValuePair<Action<ImageWrapper>, ImageWrapper>>();

        public void AddCallback(Action<ImageWrapper> action, ImageWrapper payload)
        {
            _callbackList.Push(new KeyValuePair<Action<ImageWrapper>, ImageWrapper>(action, payload));
        }

        private async Task CallbackEmitLoop()
        {
            while (true)
            {
                await Task.Delay(TimeSpan.FromMilliseconds(20));

                try
                {
                    var callback = _callbackList.Pop();
                    callback.Key.Invoke(callback.Value);
                }
                catch (Exception e)
                {
                    await Task.Delay(200);
                }
            }
        }
    }

但是我怎样才能让CallbackEmitLoop 在后台启动呢?或任何其他解决方案?

更新 1

我不需要 dispather 计时器,因为它与 wpf 紧密相关,也许对于“计时器”的事情,我应该使用同步上下文。而且我从其他上下文调用我的集合没有问题,因为集合可以准备好并发。我需要一个阀门之类的东西,一旦添加它们就会限制调用代表。所以我如何描述上面的问题我可以一次获得很多“更新”(代表),如果我只是应用它们(调用代表),ui线程将很忙,这将导致冻结,因此我应该以某种方式在应用下一次“更新”之前保持时间。

【问题讨论】:

    标签: c# .net wpf asynchronous architecture


    【解决方案1】:

    这是一种方法。下面的代码使用您的 CallbackRestriction 类和我的 ImageWrapper 虚拟实现。我已经公开了 CallbackEmitLoop 方法,以便我的窗口可以使用 Task.Run 启动它。

    因为我在窗口中维护委托发射器实例,所以只要窗口处于活动状态,它就会运行。一个真正的应用程序可能会从其他一些服务类运行它。

    如果需要使用 WPF UI 元素,回调需要使用 Dispatcher 来调用 UI 线程上的代码,因为 Task 在线程池线程上运行,并且任何委托调用也将在该线程上运行。

    关于这可能是重复问题的评论,OP 正在询问如何让正在运行的 Task 调用与 UI 交互的委托,虽然 DispatcherTimer 肯定是一种合理的方法,但它并没有解决 OP 的问题,它也没有解释为什么 DispatcherTimer 会是更合适的实现。

    // My dummy ImageWrapper
    public class ImageWrapper
    {
        public string Val { get; set; }
    }
    
    public partial class MainWindow
    {
    
        private CallbackRestriction _restriction = new CallbackRestriction();
    
        public MainWindow()
        {
            InitializeComponent();
    
            _restriction.AddCallback(MyCallback, new ImageWrapper() {Val = "Hello"});
    
            Task.Run(_restriction.CallbackEmitLoop);
        }
    
        private void MyCallback(ImageWrapper wrapper)
        {
            // since the callback will be running on the 
            // thread associated with the task, if you
            // want to interact with the UI in the callback
            // you need to use Dispatcher
            Dispatcher.BeginInvoke(new Action(() =>
            {
                Debug.WriteLine(wrapper.Val);
            }));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-05-30
      • 1970-01-01
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-10
      相关资源
      最近更新 更多