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

时间:2014-06-12 08:04:24

标签: c# multithreading

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

它应该像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
        }
    }
}

来自主界面的电话:

public void SensorInit()
{
    //....
    sensorHelper.ReleaseStateChanged += releaseStateChanged;
    //....
}

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

有没有人让我开始提示?

1 个答案:

答案 0 :(得分:1)

您可以通过使用自己的事件调用,并在附加事件时存储对线程的引用来执行此操作。

使用事件添加/删除语法,您可以让调用者像以前一样附加到事件,但在内部存储列表,并引用该线程(使用AsyncOperation)并且委托为调用(在示例中使用了包含两者的元组)

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

    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
            }
        }

    }