參考資料
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)兩系列方法,希望能減少用錯的情況

invoke.jpg

 

//同步傳遞工作(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);
    });
}

 

EditorBrowsableState.jpg

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

創作者介紹
創作者 GNAySolution 的頭像
Yang

GNAySolution

Yang 發表在 痞客邦 留言(0) 人氣( 13 )