开始调用未运行

Posted

技术标签:

【中文标题】开始调用未运行【英文标题】:Begin Invoke is not running 【发布时间】:2018-04-06 14:08:48 【问题描述】:

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

它在我的其他函数中非常有效,但在我的 SQL 删除函数中它不会被触发/执行。

我用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(() =&gt; ... ));) 中使用它,所以它必须是 DispatcherPriority.Input

【问题讨论】:

你在 BeginInvoke 里面做什么?你怎么知道它没有运行?尝试将优先级更改为正常。 @mm8 因为它在我需要输入优先级的其他 2 个功能中运行良好。给我一秒钟我编辑帖子。 您希望 Set_Loading_Changed() 在您的 SQL 之前 执行还是您的问题是什么? 尝试调用 Invoke 而不是 BeginInvoke。 应该按书面规定工作。我的猜测是您正在代码中的其他位置重置光标,或者在应用光标更新之前继续阻止 UI 线程。在设置OverrideCursor 后立即尝试调用Mouse.UpdateCursor()。如果这没有帮助,请在代码中找到覆盖光标的每个位置,设置断点,然后查看是否意外清除了某个地方的光标。 【参考方案1】:

您遇到了误解 WPF 线程系统的常见问题。 WPF 的结构方式是使用一个线程让程序在其中运行和修改 UI,通常称为 UI 线程,以及您没有正常使用方式的第二个线程,它会自动渲染 UI,通常称为渲染或合成线程。 您需要了解的关键点是,如果您在 BeginInvoke() 之后立即停止 UI 线程进行大型操作(如数据库读取或大型计算),那么您将阻止 UI 线程运行这些命令,直到您允许它调用下一个动作。 BeginInvoke() 只是将下次允许调度程序执行的操作排队 - 调度程序不会中断当前正在执行的操作。将优先级设置为 Input 可确保在其他较低优先级的工作之前处理它,但仍不会导致它中断您当前的方法。 如果您改为调用Invoke(),您将中断您的工作,要求调度员执行操作,然后在完成后返回您正在执行的操作。虽然这比您的行为更可取目前,这不是您打算使用调度程序的方式,并且仍然会导致您的应用程序在完成长时间操作时出现“冻结”。为避免这种情况,最简单的做法是在任务中运行长操作,使用 async/await 关键字和任务并行库。 Stephen Cleary 有一个出色的博客,其中涵盖了许多与此相关的主题。他的介绍性帖子(可追溯到关键字的介绍)是 here。 如果您在该领域有更多问题,我鼓励您浏览他的博客 - 他是解释该领域的领先专家之一,并且涵盖了您遇到的大部分问题。

延伸阅读:What's the difference between Invoke() and BeginInvoke()?WPF Threading Model

【讨论】:

【参考方案2】:

不幸的是,在 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;

        
    

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

using (new OverrideCursor())

    //your code 

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

编辑:来源:https://***.com/a/675686/4579864

【讨论】:

【参考方案3】:

如果你想在Set_Loading_Changed()做任何你正在做的事情在你连接到数据库之前,你应该调用Invoke而不是BeginInvoke

Set_Loading_Changed()

    System.Windows.Application.Current.Dispatcher.Invoke(...);

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

【讨论】:

以上是关于开始调用未运行的主要内容,如果未能解决你的问题,请参考以下文章

Angular Fire Functions 调用但未运行

运行 AWS sam 本地调用时 Python 未找到模块

代码运行时未调用 Excel VBA 功能区 getEnabled

调试时未调用推送通知扩展

applicationDidFinishLaunching 未运行

Oracle Scheduler proc 未在下一次开始时间之前完成