C# async dispatcher operation not recognized variable 自启动以来已更改

C# async dispatcher operation not recognising variable has changed since it started

我正在尝试实现一种方法,当用户将鼠标光标置于组件中时,该方法将在 WPF 中触发 UI 事件。

行为应该是:

1)鼠标光标进入组件,调用方法mouseEnter

2) 1 秒计时器开始

3) 如果光标还在组件中,则触发事件(本例为打开扩展器)。

最初,这是使用 Thread 完成的,但现在使用 Dispatcher.

异步执行

当光标进入组件时,一个名为mouseInbool 被设置为true。 当光标离开组件时,mouseIn 设置为 false。

问题是,如果用户将光标放入组件中,然后在 1 秒计时器结束之前将其移出组件,delegate 仍然认为 mouseIn 为真,即使我已经确认一旦光标离开它就会将其设置为 false。

void mouseEnter(object sender, MouseEventArgs e) {
    mouseIn = true;
    Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => {
        Thread.Sleep(1000);
        if (mouseIn) {
            exp.IsExpanded = true;
        }
    }
}

void mouseLeave(object sender, MouseEventArgs e) {
    mouseIn = false;
}

async delegate 通常只保存外部变量启动时的状态吗? 如果是这样,是否有办法强制它重新检查值,或者如果失败,是否有更好的方法来实现此行为?

非常感谢。

您将 Action 安排在 UI 线程上然后阻塞它(尽管您确实使用 BeginInvoke 将其异步排队)并使用 Thread.Sleep 的事实给出mouseLeave 事件处理程序被调用的机会很小。

您可以使用 Task.Delay 获得完全不阻塞消息循环的解决方案。一旦达到 await,它将把控制权交还给 UI 消息循环,并且一旦延迟结束,将在 UI 线程上安排继续:

async void mouseEnter(object sender, MouseEventArgs e)
{
    mouseIn = true;
    await Task.Delay(1000);

    if (mouseIn) 
    {
        exp.IsExpanded = true;
    }
}

void mouseLeave(object sender, MouseEventArgs e) 
{
    mouseIn = false;
}

mouseIn 变量只有一个副本,代表看到的是同一个变量。问题是你的 mouseLeave 事件没有被调用,因为你的委托中有 Thread.Sleep(1000) 调用。

Dispatcher.BeginInvoke 将在 UI 线程上调用您的操作。然后通过 Thread.Sleep 调用阻塞 UI 线程 1 秒。当 UI 线程处于休眠状态时,它不会响应用户输入,因此不会记录鼠标移动。而不是 Thread.Sleep 使用 async/awaitTask.Delay 这不会阻塞 UI 线程。