參考資料
https://stackoverflow.com/questions/5436349/what-happened-to-control-invokerequired-in-wpf
https://docs.microsoft.com/zh-tw/dotnet/api/system.windows.threading.dispatcher.invoke?view=windowsdesktop-6.0
https://stackoverflow.com/questions/60759414/delegate-is-never-executed-while-invoked-via-dispatcher-begininvoke-with-context
微軟的WPF框架,將工作從背景執行緒傳遞(Invoke)到視窗執行緒的動作,似乎經歷過幾次改版,使用上有些眉角要注意,這裡包裝成同步(InvokeSync)和非同步(InvokeAsync)兩系列方法,希望能減少用錯的情況

//同步傳遞工作(Action),工作完成前,呼叫端的背景執行緒會暫停往下執行其他程式碼
//工作不會立刻被執行,會放在queue內,等視窗執行緒忙完其他工作後執行
public static void InvokeSync(this DispatcherObject obj, Action<object> act, in DispatcherPriority priority = DispatcherPriority.Normal)
{
if (!obj.CheckAccess())
{
obj.Dispatcher.Invoke(delegate { act(obj); }, priority);
return;
}
act(obj);
}
public static void InvokeSync<T>(this DispatcherObject obj, Action<object, T> act, T arg, in DispatcherPriority priority = DispatcherPriority.Normal)
{
if (!obj.CheckAccess())
{
obj.Dispatcher.Invoke(delegate { act(obj, arg); }, priority);
return;
}
act(obj, arg);
}
public static void InvokeSync<T1, T2>(this DispatcherObject obj, Action<object, T1, T2> act, T1 arg1, T2 arg2, in DispatcherPriority priority = DispatcherPriority.Normal)
{
if (!obj.CheckAccess())
{
obj.Dispatcher.Invoke(delegate { act(obj, arg1, arg2); }, priority);
return;
}
act(obj, arg1, arg2);
}
//非同步傳遞工作(InvokeAsync),工作完成前,呼叫端的背景執行緒會繼續往下執行其他程式碼
//工作不會立刻被執行,會放在queue內,等視窗執行緒忙完其他工作後執行
public static void InvokeAsync(this DispatcherObject obj, Action<object> act, in DispatcherPriority priority = DispatcherPriority.Background)
{
if (!obj.CheckAccess())
{
obj.Dispatcher.InvokeAsync(delegate { act(obj); }, priority);
return;
}
act(obj);
}
public static void InvokeAsync<T>(this DispatcherObject obj, Action<object, T> act, T arg, in DispatcherPriority priority = DispatcherPriority.Background)
{
if (!obj.CheckAccess())
{
obj.Dispatcher.InvokeAsync(delegate { act(obj, arg); }, priority);
return;
}
act(obj, arg);
}
public static void InvokeAsync<T1, T2>(this DispatcherObject obj, Action<object, T1, T2> act, T1 arg1, T2 arg2, in DispatcherPriority priority = DispatcherPriority.Background)
{
if (!obj.CheckAccess())
{
obj.Dispatcher.InvokeAsync(delegate { act(obj, arg1, arg2); }, priority);
return;
}
act(obj, arg1, arg2);
}
//之前寫的,將log加入AppLog動態資料集(_appLogCollection),顯示在DataGrid上
//更新前
void AppendLog(in LogLevel level, in string msg, [CallerLineNumber] in int lineNumber = 0, [CallerMemberName] in string memberName = "")
{
AppLog log = new AppLog()
{
Level = level.Name.ToUpper(),
ThreadID = Thread.CurrentThread.ManagedThreadId,
Message = msg,
CallerLineNumber = lineNumber,
CallerMemberName = memberName,
};
_appLogCollection.Add(log);
}
//更新後
void AppendLog(in LogLevel level, in string msg, [CallerLineNumber] in int lineNumber = 0, [CallerMemberName] in string memberName = "")
{
AppLog log = new AppLog()
{
Level = level.Name.ToUpper(),
ThreadID = Thread.CurrentThread.ManagedThreadId,
Message = msg,
CallerLineNumber = lineNumber,
CallerMemberName = memberName,
};
MainForm.InvokeAsync(delegate
{
_appLogCollection.Add(log);
});
}

另外補充,在學習使用WPF時發現有些方法被設計成[EditorBrowsable(EditorBrowsableState.Never)],譬如DispatcherObject.CheckAccess(),原因不明,使用上要多留意
請先 登入 以發表留言。