在主线程上自定义事件和调用
本文关键字:事件 调用 自定义 线程 | 更新日期: 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
}
}
}