替换自定义的 DoEvents 函数

huangapple go评论72阅读模式
英文:

Replacing a Custom DoEvents-Function

问题

以下是您要翻译的内容:

"I've been recently introduced to a project that uses WPF to visualize some work. The application uses some custom windows to display a popup window. There is a bug in the application where this custom popup window will not go away when clicking 'OK,' or rather it seems to re-appear immediately.

From what I can tell, the issue might be due to a custom DoEvents function based on the infamous DoEvents in VB6. I'm having trouble implementing a better solution for this because this DoEvents locks the user into the custom popup window but does not block the main thread, and my attempt at an async solution failed.

This is the DoEvents implementation:

[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);

Thread.Sleep(10);

}

public static object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}

And this is the function that uses it (simplified):

public static DialogResult Show(string view, string caption)
{
if (dialogIsOpen)
return DialogResult.Cancel;
dialogIsOpen = true;

// Instantiates the view and sets it in the region.
MyApplication.OpenView(view, caption);

object? result = default;
while ((result = MyApplication.GetValue('MyResult') == null)
    MyApplication.DoEvents();

// Clears the region.
MyApplication.ResetView();

dialogIsOpen = false;
return result is DialogResult ? (DialogResult)result : DialogResult.Cancel;

}

The instantiated popup view will write the value 'MyResult' when the user confirms the popup.

I tried implementing the same logic using Task, but it ended up freezing my application (and not showing the popup at all).

public static DialogResult Show(string view, string caption)
{
if (dialogIsOpen)
return DialogResult.Cancel;
dialogIsOpen = true;

// Instantiates the view and sets it in the region.
MyApplication.OpenView(view, caption);

var task = Task.Run(async () =>
{
    object? result = default;
    while ((result = MyApplication.GetValue('MyResult') == null)
        await Task.Delay(10);
    return result;
});
object? result = task.Result;

// Clears the region.
MyApplication.ResetView();

dialogIsOpen = false;
return result is DialogResult ? (DialogResult)result : DialogResult.Cancel;

}

I think the problem is that the main thread waits for the async code to finish (and blocks user input). I lack some multitasking experience, so I don't know how to fix this."

英文:

I've been recently introduced to a project that uses WPF to visualize some work. The application uses some custom windows to display a popup window. There is a bug in the application where this custom popup window will not go away when clicking "OK", or rather it seems to re-appear immediately.

From what I can tell, the issue might be due to a custom DoEvents function based on the infamous DoEvents in VB6. I'm having trouble implementing a better solution for this, because this DoEvents locks the user into the custom popup window, but does not block the main thread and my attempt at an async solution failed.

This is the DoEvents implementation:

[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);

    Thread.Sleep(10);
}

public static object ExitFrame(object f)
{
    ((DispatcherFrame)f).Continue = false;
    return null;
}

And this is the function that uses it (simplified):

public static DialogResult Show(string view, string caption)
{
    if (dialogIsOpen)
        return DialogResult.Cancel;
    dialogIsOpen = true;

    // Instantiates the view and sets it in the region.
    MyApplication.OpenView(view, caption);

    object? result = default;
    while ((result = MyApplication.GetValue("MyResult") == null)
        MyApplication.DoEvents();

    // Clears the region.
    MyApplication.ResetView();

    dialogIsOpen = false;
    return result is DialogResult ? (DialogResult)result : DialogResult.Cancel;
}

The instantiated popup view will write the value "MyResult", when the user confirms the popup.

I tried implementing the same logic using Task, but it ended up freezing my application (and not showing the popup at all).

public static DialogResult Show(string view, string caption)
{
    if (dialogIsOpen)
        return DialogResult.Cancel;
    dialogIsOpen = true;

    // Instantiates the view and sets it in the region.
    MyApplication.OpenView(view, caption);

    var task = Task.Run(async () =>
    {
        object? result = default;
        while ((result = MyApplication.GetValue("MyResult") == null)
            await Task.Delay(10);
        return result;
    });
    object? result = task.Result;

    // Clears the region.
    MyApplication.ResetView();

    dialogIsOpen = false;
    return result is DialogResult ? (DialogResult)result : DialogResult.Cancel;
}

I think the problem is that the main thread waits for the async code to finish (and blocks user input). I lack some multitasking experience so I don't know how to fix this.

答案1

得分: 2

DoEvents的使用(也许是首要问题)是为了避免使用适当的多线程。

正确的解决方案应该是使用回调,或异步函数,或订阅事件。

例如,不要创建一个等待某个值被填充的循环-
你可以创建一个事件,并在完成时引发它。

这样你的代码就不会"等待"并阻塞线程。

英文:

The usage of DoEvents (maybe in the first place) was done to avoid using proper multi-threading.

The right solution would be using callbacks, or async functions, or to subscribe to events.

for example, instead of creating a loop which is waiting for some value to be filled-
you can create an event and raise it when fulfilled.

this way your code won't be "waiting" and holding the thread blocked

huangapple
  • 本文由 发表于 2023年6月6日 14:01:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76411802.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定