C# Begin Invoke未运行
Im使用C# Begin Invoke未运行,c#,wpf,multithreading,invoke,dispatcher,C#,Wpf,Multithreading,Invoke,Dispatcher,Im使用System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input,新操作(()=>…)刷新wpf图形 它在我的另一个函数中非常有效,但在我的SQL delete函数中它不会被触发/执行 我用System.Windows.Forms.Application.DoEvents();尝试了它,但它没有任何作用 Set_Loading_Changed() { System.Windows.
System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input,新操作(()=>…
)刷新wpf图形
它在我的另一个函数中非常有效,但在我的SQL delete函数中它不会被触发/执行
我用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()
{
...
设置_加载_更改();
使用(OLEDB连接ODC=新OLEDB连接(“…”)
{
foreach(DataGrid_Anzeige.SelectedItems.OfType()中的变量selectedRow)
{
sSQL_语句=“…”;
ODC.Open();
OleDbCommand ODCmd=新的OleDbCommand(sSQL_语句,ODC);
ODCmd.ExecuteNonQuery();
ODC.Close();
编辑:
我插入了我的Set\u Load\u Changed()
函数的完整部分,希望你能从这些信息中得到线索
我主要是在我的搜索线程(
Task.Factory.StartNew(()=>{…}));
)中使用它,所以它必须是DispatcherPriority.Input
如果你想在Set\u Loading\u Changed()
中执行任何操作,在连接到数据库之前,你应该调用Invoke
而不是BeginInvoke
:
Set_Loading_Changed()
{
System.Windows.Application.Current.Dispatcher.Invoke(...);
}
由于误解了WPF线程系统,您遇到了一个常见问题。WPF的结构方式是,一个线程用于程序运行和修改UI,通常称为UI线程,另一个线程用于自动呈现UI,通常称为呈现或合成正在加载线程。
这里您需要知道的关键点是,如果您在
BeginInvoke()
之后立即使用大型操作(如数据库读取或大型计算)暂停UI线程,那么您将阻止UI线程运行这些命令,直到您允许它调用下一个操作。BeginInvoke()
只需将下一次允许调度程序执行的操作排队-调度程序不会中断当前正在执行的操作。将优先级设置为Input
可确保它将在其他优先级较低的工作之前处理,但仍不会导致它中断您当前的方法。如果您改为调用
Invoke()
,则会中断您的工作,要求调度程序执行操作,然后在操作完成后返回您正在执行的操作。虽然这比您当前获得的行为更可取,但这不是您打算使用dispatcher的方式,并且在完成长操作时仍会导致您的应用程序显示为“冻结”。要避免这种情况,最简单的方法是在任务中运行长操作,使用async/Wait关键字和Task Parallel Libra里。
斯蒂芬·克利里(Stephen Cleary)有一个很好的博客,涵盖了许多与此相关的主题。他的介绍性文章(可以追溯到关键字的介绍)是。 如果你在这个领域有更多的问题,我会鼓励你浏览他的博客——他是解释这个领域的主要专家之一,涵盖了你遇到的大部分问题
进一步阅读:
不幸的是,在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块内的任何代码所需的时间,光标将在之后变回正常状态。
您也可以在不使用using块的情况下启动类的对象来无限期地设置它,但在完成时不要忘记调用Dispose()
编辑:来源:你在BeginInvoke里面做什么?你怎么知道它没有运行?试着将优先级更改为正常。@mm8因为它在另外两个需要输入优先级的函数中运行良好。给我一点时间,我编辑这篇文章。你想更改设置吗要在SQL之前执行,或者您的问题是什么?请尝试调用Invoke而不是BeginInvoke。这应该可以按编写的方式工作。我猜您是在代码中的其他位置重置光标,或者在应用光标更新之前继续阻止UI线程。请尝试调用Mouse.UpdateCursor()
设置OverrideCursor
后立即执行。如果这没有帮助,请在代码中找到覆盖光标的每个位置,设置断点,然后查看是否在某个地方意外清除光标。
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
}