在我的应用程序中,我使用SystemEvents
将对象添加到ObservableCollection
(此示例缩短了代码)
public partial class App : Application
{
private ObservableCollection<StateChanged> _messages = new ObservableCollection<StateChanged>();
public ObservableCollection<StateChanged> messages { get { return _messages; } }
protected override void OnStartup(StartupEventArgs e)
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
messages.Insert(0, new StateChanged(DateTime.Now, State.Logoff));
}
}
上面的代码没有问题。
因为我不仅需要处理SessionSwitch
事件,还需要SessionEnding
等等。我写了一个小班,应该提出一个统一的&#39;部分SystemEvents
(再次缩短)的事件
public class SystemEventArgs : EventArgs
{
public State newState { get; set; }
}
public delegate void SystemEventHandler(object sender, SystemEventArgs e);
class SystemEventCollector
{
public event SystemEventHandler SessionEvent;
protected virtual void RaiseSystemEvent(SystemEventArgs e)
{
SystemEventHandler handler = this.SessionEvent;
if (handler != null)
handler(this, e);
}
public SystemEventCollector()
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
protected void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
SystemEventArgs ea = new SystemEventArgs();
ea.newState = State.Unknown;
RaiseSystemEvent(ea);
}
}
当我在我的应用程序中实现此类并订阅SessionEvent
时,执行相同的操作,例如
public partial class App : Application
{
private ObservableCollection<StateChanged> _messages = new ObservableCollection<StateChanged>();
public ObservableCollection<StateChanged> messages { get { return _messages; } }
private SystemEventCollector _sysEventCollector = new SystemEventCollector();
protected override void OnStartup(StartupEventArgs e)
{
_sysEventCollector.SessionEvent += OnSessionEvent;
}
private void OnSessionEvent(object sender, SystemEventArgs e)
{
messages.Insert(0, new StateChanged(DateTime.Now, e.newState));
}
}
messages.Insert()
电话会引发异常
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
我确实理解我无法从另一个线程更新GUI元素,而不是通过使用this SO答案中提到的扩展方法解决此问题。
我的问题是为什么会这样?我的假设是事件在引发的同一个线程上处理,那么为什么直接处理SessionSwitch
事件和处理SessionSwitch
事件时引发事件的方法有区别? SystemEvents
与我的活动有什么不同?我是否有正确的解决方案?有更简单的解决方案吗?
答案 0 :(得分:1)
从某些测试看来,错误在于非工作代码是SystemEventCollector
对象的实例化。
MS在SessionEvents.***
处理程序中执行所有必要的编组操作,这就是为什么第一个示例可以正常工作的原因。在非工作代码SystemEventCollector
中,OnStartup
函数(从UI线程调用)中没有实例化,但基本上与构造函数一致。当完成SessionEvents
的编组时,它会转到错误的线程,从而导致问题。
除了我原来的解决方案之外,还可以通过在SystemEventCollector
函数中实现OnStartup
来解决问题。
protected override void OnStartup(StartupEventArgs e)
{
_sysEventCollector = new SystemEventCollector();
_sysEventCollector.SessionEvent += OnSessionEvent;
}