在主线程上自定义事件和调用

本文关键字:事件 调用 自定义 线程 | 更新日期: 2023-09-27 18:08:29

我得到了一个通用的API类,它包含一个自定义事件,总是需要由主UI线程调用。我的工作是从自定义类中消除这些调用调用,使其"无痛"。

它应该像WinForms中的默认事件一样同步(例如Timer "Elapsed"事件,当它将值发布到文本框中时也不需要调用)

是否有可能解决这个问题,因为自定义类需要知道在哪里调用?

下面是(重要的部分)代码:

public class ContactSensorHelper
{
    public event OnReleaseStateChanged ReleaseStateChanged;
    public delegate void OnReleaseStateChanged(ContactSensorEventArgs e);
    private ContactSensorEventArgs.ReleaseState recentReleaseState;
    public void ReportStateChanged()
    {
        if (ReleaseStateChanged != null)
            ReleaseStateChanged(new ContactSensorEventArgs()
            {
                State = recentReleaseState
            });
    }
    public class ContactSensorEventArgs : EventArgs
    {
        //......
        public ReleaseState State { get; set; }
        //......
        public enum ReleaseState
        {
            FullReleased,
            PartlyReleased,
            NotReleased
        }
    }
}

来自主UI的调用:

public void SensorInit()
{
    //....
    sensorHelper.ReleaseStateChanged += releaseStateChanged;
    //....
}
private void releaseStateChanged(ContactSensorEventArgs e)
{
    //example
    textBox1.Text = e.State.ToString();   // Thread exception (obviously)
}

有人给我点提示吗?

在主线程上自定义事件和调用

您可以通过使用您自己的事件调用,并在附加事件时存储对线程的引用来实现这一点。

使用事件添加/删除语法,您可以像以前一样将调用者附加到事件上,但在内部存储一个列表,其中包含对线程的引用(使用AsyncOperation)和要调用的委托(在示例中使用包含两者的Tuple)

下面是一个例子。我对它进行了测试,它在测试时工作如预期的那样,但是您可能必须添加一些列表锁定以使其在事件同时添加/删除的情况下线程安全。

    public class ContactSensorHelper:IDisposable
    {
        public delegate void OnReleaseStateChanged(ContactSensorEventArgs e);
        private ContactSensorEventArgs.ReleaseState recentReleaseState;
        public void ReportStateChanged()
        {
            if (statechangedList.Count > 0)
            {
                var e = new ContactSensorEventArgs()
                {
                    State = recentReleaseState
                };
                statechangedList.ForEach(t =>
                    t.Item1.Post(o => t.Item2((ContactSensorEventArgs)o), e));
            }
        }            
        List<Tuple<AsyncOperation, OnReleaseStateChanged>> statechangedList = new List<Tuple<AsyncOperation,OnReleaseStateChanged>>();
        public event OnReleaseStateChanged ReleaseStateChanged
        {
            add
            {
                var op = AsyncOperationManager.CreateOperation(null);
                statechangedList.Add(Tuple.Create(op, value));                    
            }
            remove
            {
                var toremove = statechangedList.Where(t => t.Item2 == value).ToArray();
                foreach (var t in toremove)
                {
                    t.Item1.OperationCompleted();
                    statechangedList.Remove(t);
                }
            }
        }
        public void Dispose()
        {
            statechangedList.ForEach(t => t.Item1.OperationCompleted());
            statechangedList.Clear();
        }
        public class ContactSensorEventArgs : EventArgs
        {
            //......
            public ReleaseState State { get; set; }
            //......
            public enum ReleaseState
            {
                FullReleased,
                PartlyReleased,
                NotReleased
            }
        }
    }