自定义事件和SystemEvent之间的区别

时间:2014-06-08 13:44:37

标签: c# wpf

在我的应用程序中,我使用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与我的活动有什么不同?我是否有正确的解决方案?有更简单的解决方案吗?

1 个答案:

答案 0 :(得分:1)

从某些测试看来,错误在于非工作代码是SystemEventCollector对象的实例化。 MS在SessionEvents.***处理程序中执行所有必要的编组操作,这就是为什么第一个示例可以正常工作的原因。在非工作代码SystemEventCollector中,OnStartup函数(从UI线程调用)中没有实例化,但基本上与构造函数一致。当完成SessionEvents的编组时,它会转到错误的线程,从而导致问题。

除了我原来的解决方案之外,还可以通过在SystemEventCollector函数中实现OnStartup来解决问题。

protected override void OnStartup(StartupEventArgs e)
{
    _sysEventCollector = new SystemEventCollector();
     _sysEventCollector.SessionEvent += OnSessionEvent;
}