使用continue async更新UI任务通过对象列表无法按预期执行

时间:2017-09-18 15:56:19

标签: c# wpf multithreading asynchronous progress-reports

在我的应用程序中,我有一个与PLC通信的通讯驱动程序,这很好用。我想管理所有的值更新请求,为此我创建了在ValueListenManager中注册自己的ValueListener对象,这也可以正常工作。在我的同步测试中,UI性能如预期的那样缓慢。现在完美让我们让它变得异步。

我尝试了不同的方法,例如backgroundworker,timer和Task.Run 这是迄今为止我能做的最好的,它可以正常工作,如果我printcreen任务ManagedThreadId线程ID是不同的(什么告诉我它应该是异步的)

但UI响应性能似乎并没有真正改善,这告诉我它并不是真正的异步。谁能帮我这个?

到目前为止,我发现的唯一奇怪的事情是,当CheckPlcValuesTask已经更新时,可以将ValueListener添加到Managers ListenList,这也表明我不是真的异步,我做错了什么? (我是异步编程的新手,所以感谢任何帮助或提示)

编辑:代码现在编译

  public class CommManager
     {
         public static class ValueListenManager
        {
            static private List<ValueListener> ListenList = new List<ValueListener>();

            public async static void Start()
            {                    
                var UpdateChangedValues = new Progress<List<ValueListener>>(UiUpdateList =>
                {
                    foreach (ValueListener item in UiUpdateList)
                        item.TriggerChange();
                });
                await Task.Run(() => CheckPlcValuesTask(UpdateChangedValues));
            }


            private static Task CheckPlcValuesTask(IProgress<List<ValueListener>> progressList)
            {
                List<ValueListener> returnList = new List<ValueListener>();
                while (true)
                {
                    if (returnList.Count != 0)
                        returnList.Clear();

                    Parallel.ForEach(ListenList, (CurrentItem) =>  // ListenList is the static List declared in the top
                    {
                        if (CurrentItem.CheckValue())
                            returnList.Add(CurrentItem);
                    });

                    if (progressList != null)
                    {
                        progressList.Report(returnList);
                        Thread.Sleep(1000);
                    }
                }

            }

            static internal void RegisterLister(ValueListener Listner)
            {
                ListenList.Add(Listner);
            }

            static internal void UnRegisterLister(ValueListener Listner)
            {
                ListenList.Remove(Listner);
            }
        }
    }
}


internal class ValueListener
{
    public event EventHandler<ValueChangeEventArgs> Changed;
    public string FullPath { get; }
    public object Value { get; private set; }
    private object oldObjectValue;

    internal ValueListener(string Path) // update prio is a enum
    {
        this.FullPath = Path;
        CommManager.ValueListenManager.RegisterLister(this);   // here i register into the ListenList above
    }

    ~ValueListener()
    {
        CommManager.ValueListenManager.UnRegisterLister(this);  // de-register after destruction
    }

    // Check for value changes
    public bool CheckValue()
    {
        var SmallTest = new Random();
        Value = SmallTest.Next(1, 5);
        if (Value != null && !Value.Equals(oldObjectValue))
            return true;

        return false;
    }


    // Check for value change, here is where i trigger updates on the UI
    public void TriggerChange()
    {
        if (Changed != null)
            Changed.Invoke(this, new ValueChangeEventArgs(Value, oldObjectValue));
        oldObjectValue = Value;
    }
}


public class ValueChangeEventArgs : EventArgs
{
    public ValueChangeEventArgs(object Value, object OldValue)
    { }
}

1 个答案:

答案 0 :(得分:0)

这应该对你有用。它利用了Microsoft TPL Dataflow, 这是一个nuget包。

public static partial class CommManager
{
    public static class ValueListenManager
    {
        public static event Action<object> NewValueAvailable;

        private static Thread s_valueQueryThread;
        private static ActionBlock<object> s_newValueActionBlock;
        private static bool s_shouldRun;

        private static Random s_valueGenerator; //for testing purposes

        public static void Start()
        {
            //These flow options will make sure your action block executes on the UI thread. Make sure you call start on the UI Thread!
            var flowOptions = new ExecutionDataflowBlockOptions(){ TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext() };

            s_newValueActionBlock = new ActionBlock<object>(new Action<object>(OnNewValue), flowOptions);
            s_valueQueryThread = new Thread(CheckPlcValues);

            s_valueQueryThread.IsBackground = true;
            s_valueQueryThread.Start();
        }

        public static void Stop()
        {
            s_shouldRun = false;

            s_valueQueryThread.Join();
            s_valueQueryThread = null;

            s_newValueActionBlock.Complete();
            s_newValueActionBlock = null;
        }

        private static void OnNewValue(object value)
        {
            if(NewValueAvailable != null)
                NewValueAvailable(value);
        }

        private static void CheckPlcValues()
        {
            s_shouldRun = true;

            while(s_shouldRun)
            {
                var curPlcValue = s_valueGenerator.Next(1, 5);

                s_newValueActionBlock.Post(curPlcValue);

                Thread.Sleep(1000);
            }
        }
    }
}

internal class ValueListener
{
    public event EventHandler<ValueChangeEventArgs> ValueChanged;

    public string FullPath { get; private set; }
    public object Value { get; private set; }

    internal ValueListener(string path)
    {
        this.FullPath = path;
        CommManager.ValueListenManager.NewValueAvailable += CommManager_ValueListenManager_NewValueAvailable;
    }

    ~ValueListener()
    {
        CommManager.ValueListenManager.NewValueAvailable -= CommManager_ValueListenManager_NewValueAvailable;
    }

    void CommManager_ValueListenManager_NewValueAvailable(object newValue)
    {
        if(newValue != null && !newValue.Equals(Value))
        {
            var args = new ValueChangeEventArgs(newValue, Value);
            Value = newValue;

            if(ValueChanged != null)
                ValueChanged(this, args);
        }
    }
}

public class ValueChangeEventArgs : EventArgs
{
    public ValueChangeEventArgs(object Value, object OldValue) { }
}