如何从计时器编辑 C# 中的主窗体?

How to edit the main form in C# from a timer?

我正在尝试在我的表单上显示错误并使用计时器在一秒钟内消除错误。我有:

const string sendingError = "currently sending a message please wait";
System.Timers.Timer timer = new System.Timers.Timer(1000);
commandValues.errorList[sendingError] = sendingError;
commandValues.updateErrorList();

通过使用错误消息更新标签,它可以正常运行

timer.Elapsed += ((source, e) => 
{
    var INDEX = Form.ActiveForm.Controls.IndexOfKey("errorBox");
    Debug.WriteLine(Form.ActiveForm.Controls[INDEX]);
    Form.ActiveForm.Controls[INDEX].Text = "";
    Debug.WriteLine("2" + Form.ActiveForm.Controls[INDEX]);
});

timer.Enabled = true;
timer.Start();

调试行显示

1System.Windows.Forms.Label, Text: currently sending a message please wait
1System.Windows.Forms.Label, Text: currently sending a message please wait
1System.Windows.Forms.Label, Text: currently sending a message please wait
1System.Windows.Forms.Label, Text: currently sending a message please wait
// etcetera

如您所见,第二个调试行从未显示。当我尝试更改标签时,断点同意它离开委托。

我是 C# 的新手,所以任何建议都将不胜感激,但具体来说,我想知道如何在超时后编辑主窗体以及我的尝试失败的原因。

您应该将 Timer thread 的 UI 修改发送到 UI Thread。不允许修改来自其他线程的 UI 个元素。

为此,您需要调用 this.BeginInvoke

How to update the GUI from another thread in C#?

我不确定我理解你的问题,但听起来你在从后台线程更新 UI 时遇到了问题?如果是这样,试试这个:

timer.Start() 启动一个与 Winform 的 UI 线程分开的新线程,因此您可能需要调用 WinForm 的线程才能看到变化。

timer.Elapsed += ((source, e) =>
{
    var INDEX = Form.ActiveForm.Controls.IndexOfKey("errorBox");
    Debug.WriteLine(Form.ActiveForm.Controls[INDEX]);
    //Invoke the instance of "Form" to process changes on the UI thread
    Form.Invoke((MethodInvoker)delegate
    {
        Form.ActiveForm.Controls[INDEX].Text = "";
    });
    Debug.WriteLine("2" + Form.ActiveForm.Controls[INDEX]);
});
timer.Enabled = true;
timer.Start();

我对调用的看法

如果是 WinForm 而不是数据绑定

myControl.Invoke((MethodInvoker) delegate {/*update UI related values here*/});

myForm.Invoke((MethodInvoker) delegate {/*update UI related values here*/});

如果 WinForm 和数据绑定,您可能需要通过更新对象的数据绑定 属性 来更新 UI,或者调用数据绑定对象来更新自己的 属性 (排队 INotifyPropertyChange 或另一个将强制刷新 UI 的类似接口)。请注意,重构您的代码以将对象数据绑定到您的 UI 也可以证明是一个永久的解决方案。

如果 XAML\WPF,您可以使用以下代码片段从基础应用程序的调度程序中强制更新您的 XPF\XAML UI,如下所示:

System.Windows.Application.Current.Dispatcher.Invoke((System.Action)delegate {/*update UI related values here*/});

干杯!