我是 C# 和異步編程的新手,所以我遇到的問題的解決方案可能很簡單(或者不是?!)。
這是問題:
- 我有一個 onClick 函式,它創建一個新的 UIControl 并將其作為新選項卡添加到當前表單中。
- 我先讓它同步運行并且沒有崩潰,但 UI 被阻塞了幾秒鐘,因為提供給此選項卡的資料需要大量計算。
- 我將 onclick 移動到 async 并在 Control 的 datprocessing 函式上添加了一個等待,但我現在得到了臭名昭著的:
“在創建視窗句柄之前,不能在控制元件上呼叫 Invoke 或 BeginInvoke”。
private async void btnNewTab_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = true;
openFileDialog.Filter = "*.test";
DialogResult dialogResult = openFileDialog.ShowDialog();
if (dialogResult == DialogResult.OK)
{
//Display a basic loading Control while the other control is being prepared
TabPage myTabPage = new TabPage("loading");
LoadingControlPanel loadingPanel = new LoadingControlPanel();
loadingPanel.Dock = DockStyle.Fill;
myTabPage.Controls.Add(loadingPanel);
tabControl.TabPages.Add(myTabPage);
tabControl.SelectTab(myTabPage);
//Load Data from files
List<DataFile> result = await Task.Run(() => loadFiles(openFileDialog.FileNames));
// create Control to display the data loaded
MyTabControl newPanel = new MyTabControl();
newPanel.Dock = DockStyle.Fill;
// provide Data to new control (long processing)
await Task.Run(() => newPanel.processData(result));
// rename Tab, remove loading Control and display the tab with the processed Data
myTabPage.Text = "Loaded";
myTabPage.Controls.Remove(loadingPanel);
myTabPage.Controls.Add(newPanel);
}
}
崩潰總是在我呼叫函式“processData”時發生,但并不總是在同一位置。我有一些除錯行,它們的處理方式并不總是相同。
The crash tells me the issue in on the line: "Application.Run(new FormMain());"
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
}
Here is the full stack trace:
System.Reflection.TargetInvocationException HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib StackTrace: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Delegate.DynamicInvokeImpl(Object[] args) at System.Delegate.DynamicInvoke(Object[] args) at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam) at Interop.User32.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.Interop.Mso.IMsoComponentManager.FPushMessageLoop(UIntPtr dwComponentID, msoloop uReason, Void* pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(msoloop reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(msoloop reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at Program.Main() in Program.cs:line 22This exception was originally thrown at this call stack: [External Code]
Inner Exception 1: InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
What on earth am I doing wrong with all this?
uj5u.com熱心網友回復:
問題是Task.Run(() => newPanel.processData(result)),這只能在 processData() 不接觸任何 UI 內容時起作用(但為什么它會成為面板的一部分?)
您只能使用 Task.Run() 處理內容,然后在主執行緒的 UI 中加載結果。
看看你能不能讓它看起來像:
//await Task.Run(() => newPanel.processData(result));
var data = await Task.Run(() => ProcessData(result));
newPanel.AcceptData(data);
LoadData 和 ProcessData() 最好是某些服務類的一部分,而不是您的 Form。但那是關于架構,而不是關于直接問題。
uj5u.com熱心網友回復:
這段代碼在這里
TabControl newPanel = new TabControl();
newPanel.Dock = DockStyle.Fill;
// provide Data to new control (long processing)
await Task.Run(() => newPanel.processData(result));
嘗試創建一個新的 TabControl,但從不顯示它,因此它從來沒有關聯的視窗句柄。這與您是同步還是異步進行資料處理完全無關。
您似乎也缺少一些相關代碼,因為System.Windows.Forms.TabControl沒有processData方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/344608.html
標籤:c# asynchronous async-await invoke
下一篇:CompletableFuture.allOf()在等待完成時是否比CompletableFuture.join()回圈有任何優勢?
