【问题标题】:InvalidOperationException while trying to modify UI from another thread尝试从另一个线程修改 UI 时出现 InvalidOperationException
【发布时间】:2017-07-05 18:13:34
【问题描述】:

我有一个复选框绑定到包装 timer.Enabled 状态的属性。

主窗体:

chbTimer.DataBindings.Add(new Binding("Checked", _inactividadController, "TimerEnabled")
            {
                DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged,
                ControlUpdateMode = ControlUpdateMode.OnPropertyChanged
            });

_inactividadController:

public bool TimerEnabled
    {
        get { return _timer.Enabled; }
        set
        {
            _timer.Enabled = value;
            InvokePropertyChanged(new PropertyChangedEventArgs("TimerEnabled"));
        }
    }

_timer.Elapsed:

private void Test(object sender, ElapsedEventArgs e)
    {
        TimerEnabled = false;
    }

这里发生异常:

public event PropertyChangedEventHandler PropertyChanged;

    public void InvokePropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)  
                  handler(this, e); //<-- BOOM
    }

我完全理解这里发生了什么:Timer 在另一个线程上工作并尝试更新主线程上的 chbTimer,这是一个非法操作。但我不知道如何解决这个问题。

尝试了this 方法但不起作用,因为来自 UI 的更改不会反映在绑定上(当用户选中复选框时,计时器不会更改状态)。

有什么建议吗?谢谢

【问题讨论】:

  • 你也可以显示你的处理程序代码吗?
  • 您需要将调用编组到 UI 线程。不知道如何在 Windows 窗体中执行此操作,而不是使用 Control.Invoke,这在这里不会真正起作用(没有 hacky af)。也许在 UI 线程上创建一个 SynchronizationContext(从而捕获它)然后在您的绑定代码中使用该 SC?
  • @vendettamit 对不起什么? PropertyChangedEventHandler 就在那里。不确定您指的是哪个处理程序。
  • @Will 我不知道那门课,我现在就去读一点
  • @我会使用 SynchronizationContext 让它工作吗?非常感谢您,现在发布答案

标签: c# winforms binding


【解决方案1】:

修改了 InactividadController 的构造函数,使其接收 SynchronizationContext

在 Form.cs 上

_inactividadController = new InactividadController(SynchronizationContext.Current);

并修改了 INotifyPropertyChanged 的​​实现

public void InvokePropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            _originalContext.Post(delegate
            {
                handler(this, e);
            }, null);
        }
    }

【讨论】:

  • 一旦使用SynchronizationContext,就完全不需要ThreadPool.QueueUserWorkItem了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
  • 2014-12-02
  • 2021-04-06
  • 2012-11-05
相关资源
最近更新 更多