这是 WinForms 应用程序的一种方法,如果它具有在应用程序初始化后始终存在的表单“MainForm”。我在静态变量中缓存对它的引用,然后有一个静态辅助方法,我在所有需要访问 UI 的方法中使用它,并且可能从非 UI 线程调用。
我喜欢这种方法的地方在于,在初始设置之后,您可以在任何类中编写 UI 触摸代码,而不仅仅是作为控件的类。并且编码是一个简单的事情,将一个动作包装在一个对MyApp.RunOnUIThread
. 请参阅、 和的定义SomeUIWork1
,了解有关此内容的变体。SomeUIWork2
SomeUIWork3
限制和注意事项:
如果可行,不要像我在这里做的那样,将你的 UI 代码与非 UI 代码分开。例如,将 BackgroundWorker 与 progressChanged https://stackoverflow.com/a/10646636/199364一起使用。
在 C# 中:
public static class MyApp
{
public static MainForm mainForm;
public static void RunOnUIThread(Action action)
{
if (mainForm.InvokeRequired)
mainForm.Invoke(action);
else
action();
}
}
// In the actual project, the Form inheritance is in the Visual Designer file for this form.
public class MainForm : System.Windows.Forms.Form
{
public MainForm()
{
// Defined in the Visual Designer for this form.
InitializeComponent();
MyApp.mainForm = this;
}
}
public class SomeClass
{
public void SomeMethod()
{
// ... do some work ...
SomeUIWork1(true);
// ... do some work ...
SomeUIWork2();
// ... do some work ...
SomeUIWork3(true);
}
// This accesses UI elements, yet is safe to call from non-UI thread.
// Shows inline code.
public void SomeUIWork1(bool param1)
{
MyApp.RunOnUIThread(() =>
{
// ... do the UI work ...
});
}
// This accesses UI elements, yet is safe to call from non-UI thread.
// Shows calling a separate method, when no parameters.
public void SomeUIWork2()
{
MyApp.RunOnUIThread(SomeUIWork2_AlreadyOnUIThread);
}
// This accesses UI elements, yet is safe to call from non-UI thread.
// Shows calling a separate method, when there are parameters.
public void SomeUIWork3(bool param1)
{
MyApp.RunOnUIThread(() => SomeUIWork3_AlreadyOnUIThread(param1));
}
#region "=== Only call from UI thread ==="
// Only call if you are certain that you are running on UI thread.
private void SomeUIWork2_AlreadyOnUIThread()
{
// ... do the UI work ...
}
// Only call if you are certain that you are running on UI thread.
private void SomeUIWork3_AlreadyOnUIThread(bool param1)
{
// ... do the UI work ...
}
#endregion
}
在 VB 中:
Imports Microsoft.VisualBasic
Public Shared Class MyApp
Public MainForm As MainForm
Public Sub RunOnUIThread(action As Action)
If MainForm.InvokeRequired Then
MainForm.Invoke(action)
Else
action()
End If
End Sub
End Class
' In the actual project, the "Inherits" line is in the Visual Designer file for this form.
Public Class MainForm
Inherits System.Windows.Forms.Form ' Or whatever type you are customizing
Sub New()
' This call is required by the designer.
InitializeComponent()
MyApp.MainForm = Me
End Sub
End Class
Public Class SomeClass
Public Sub SomeSub()
' ... do some work ...
SomeUIWork1(True)
' ... do some work ...
SomeUIWork2()
' ... do some work ...
SomeUIWork3(True)
End Sub
' This accesses UI elements.
' Shows inline code.
Public Sub SomeUIWork1(param1 As Boolean)
MyApp.RunOnUIThread(
Sub()
' ... do the UI work ...
End Sub)
End Sub
' This accesses UI elements.
' Shows calling a separate method, when no parameters.
Public Sub SomeUIWork2()
MyApp.RunOnUIThread(SomeUIWork_AlreadyOnUIThread)
End Sub
' This accesses UI elements.
' Shows calling a separate method, when there are parameters..
Public Sub SomeUIWork3(param1 As Boolean)
MyApp.RunOnUIThread(Sub() SomeUIWork_AlreadyOnUIThread(param1))
End Sub
#Region "=== Only call from UI thread ==="
' Only call if you are certain that you are running on UI thread.
Private Sub SomeUIWork2_AlreadyOnUIThread()
' ... do the UI work ...
End Sub
' Only call if you are certain that you are running on UI thread.
Private Sub SomeUIWork3_AlreadyOnUIThread(param1 As Boolean)
' ... do the UI work ...
End Sub
#End Region
End Class