开始调用不是 运行

Begin Invoke is not running

我正在使用 System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() => ... 进行 wpf 图形刷新。

它在我的其他功能中非常有效,但在我的 SQL 删除功能中它不会是 triggered/executed。

我用 System.Windows.Forms.Application.DoEvents(); 试过了,但它什么也做不了。

Set_Loading_Changed()
{
    System.Windows.Application.Current.Dispatcher.BeginInvoke(
        DispatcherPriority.Input, 
        new Action(() =>
        {
            if (BLoading)
            {
                DataGrid_Anzeige.IsEnabled = false;

                Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
            }
            else
            {
                DataGrid_Anzeige.IsEnabled = true;
        
                Mouse.OverrideCursor = null;
            }
        }));
}
Btn_Remove()
{
    ...
    Set_Loading_Changed();

    using (OleDbConnection ODC = new OleDbConnection("..."))
    {
        foreach (var selectedRow in DataGrid_Anzeige.SelectedItems.OfType<DataRowView>())
        {
            sSQL_Statement = "...";

            ODC.Open();
            OleDbCommand ODCmd = new OleDbCommand(sSQL_Statement, ODC);

            ODCmd.ExecuteNonQuery();
            ODC.Close();

编辑:

我插入了我的 Set_Load_Changed() 函数的完整部分,希望您能从这些信息中得到线索。

我主要在我的搜索主题 (Task.Factory.StartNew(() => { ... }));) 中使用它,所以它一定是 DispatcherPriority.Input

如果想在 Set_Loading_Changed() 连接到数据库之前执行任何操作,您应该调用 Invoke 而不是 BeginInvoke:

Set_Loading_Changed()
{
    System.Windows.Application.Current.Dispatcher.Invoke(...);
}

What's the difference between Invoke() and BeginInvoke()

您 运行 陷入了误解 WPF 线程系统的常见问题。 WPF 的结构方式是一个线程用于程序 运行 并修改 UI 中的,通常称为 UI 线程,以及您没有正常使用方式的第二个线程,它会自动呈现 UI,通常称为呈现或合成线程。

这里你需要知道的关键点是,如果你在 BeginInvoke() 之后立即用大型操作(如数据库读取或大型计算)停止 UI 线程,那么你将阻止 UI 线程从 运行 执行这些命令,直到您允许它调用下一个操作。 BeginInvoke() 只是将下一次允许调度程序执行的操作排队 - 调度程序不会中断当前正在执行的操作。将优先级设置为 Input 可确保它在其他优先级较低的工作之前得到处理,但仍不会导致它中断您当前的方法。
如果您改为调用 Invoke(),您将中断工作以要求调度员执行操作,然后 return 完成后您正在做的事情。

虽然这比您当前获得的行为更可取,但这不是您打算使用调度程序的方式,并且仍然会导致您的应用在完成长时间后显示 'frozen'手术。为避免这种情况,最简单的做法是 运行 任务中的长操作,使用 async/await 关键字和任务并行库。

Stephen Cleary 有一个很棒的博客,其中涵盖了很多与此相关的主题。他的介绍post(追溯到关键字的介绍)是 here。 如果您在这方面有更多问题,我鼓励您浏览他的博客 - 他是解释该领域的主要专家之一,并且涵盖了您 运行 遇到的大部分问题。


进一步阅读:
What's the difference between Invoke() and BeginInvoke()?
WPF Threading Model

不幸的是,在 WPF 中更改光标不像在 WinForms 中那样简单。我记得自己一直在努力解决这个问题,直到我偶然发现了以下解决方案。这不是我自己想出来的,我会尝试找到来源以在应有的地方给予信任。

using System;
using System.Collections.Generic;
using System.Windows.Input;

namespace MyNamespace
{
    public class OverrideCursor : IDisposable
    {
        static Stack<Cursor> s_Stack = new Stack<Cursor>();

        public OverrideCursor(Cursor changeToCursor = null)
        {
            if (changeToCursor == null)
                changeToCursor = Cursors.Wait;

            s_Stack.Push(changeToCursor);

            if (Mouse.OverrideCursor != changeToCursor)
                Mouse.OverrideCursor = changeToCursor;
        }

        public void Dispose()
        {
            s_Stack.Pop();
            var cursor = _stack.Count > 0 ? _stack.Peek() : null;
            if (Mouse.OverrideCursor != cursor)
                Mouse.OverrideCursor = cursor;

        }
    }
}

现在这个一次性 class 可以在项目的任何地方使用来临时更改光标。

using (new OverrideCursor())
{
    //your code 
}

通过将光标作为构造函数的参数传递,这会将光标更改为您想要的任何内容,或者默认情况下不使用 Cursors.Wait。 对于执行 using 块内的任何代码所需的时间,光标将被更改,然后恢复正常。
您也可以在没有使用块的情况下启动 class 的对象来无限期地设置它,但是您不应该忘记在完成后调用 Dispose()

编辑: 来源: