WinForms窗口遇到异步调用时会更改尺寸 [英] WinForms window changes dimensions when it encounters an async call

查看:55
本文介绍了WinForms窗口遇到异步调用时会更改尺寸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WinForms项目,该项目已经存在数年了,并且已经使用异步事件处理程序进行了改装:

I have a WinForms project which is several years old and has been retro-fitted with async event-handlers:

private async void dgvNewOrders_CellClick(object sender, DataGridViewCellEventArgs e)

此方法内部是一个异步调用:

Inside this method is an async call:

var projectTemplate = await GetProjectTemplateFile(companyId, sourceLang, targetLang);

当程序在正常分辨率的屏幕上运行时,它将按预期运行.但是,在高DPI屏幕上运行时,窗口的尺寸以及所有子控件的尺寸一遇到内部异步调用,就会跳到一半的尺寸.好像程序突然以兼容模式运行,或者缩放已被禁用.

When the program runs on a normal resolution screen, it runs as expected. However, when run on a high-DPI screen the window's dimensions - as well as those of all child controls - jump to half-size as soon as it encounters that inner async call. It's as if the program is suddenly run in a compatibility mode or the scaling has been disabled.

当前,为了调试该问题, GetProjectTemplateFile 方法仅由以下组成:

Currently, in an effort to debug the problem, the GetProjectTemplateFile method consists simply of

private async Task<ProjectTemplateFile> GetProjectTemplateFile(long companyId, string sourceLanguage, string targetLanguage)
{
    return null;
}

GetProjectTemplateFile 是否执行异步操作都没有区别.

It makes no difference whether GetProjectTemplateFile performs an async operation or not.

如果我注释掉对 GetProjectTemplateFile 的异步调用,那么即使在 CellClick 事件.

If I comment-out that async call to GetProjectTemplateFile then the program runs as expected without any jump in dimensions, even though there are still other async calls made in the CellClick event.

我尝试将 .ConfigureAwait(true)附加到异步调用中,这没有什么区别.也不与 .GetAwaiter().GetResult()同步运行呼叫.

I've tried appending .ConfigureAwait(true) to the async call, which makes no difference. Nor does running the call synchronously with .GetAwaiter().GetResult().

有人可以解释为什么此特定异步调用会改变窗口的尺寸,和/或如何防止这种情况发生?

Can anyone explain why the window's dimensions are changing with this particular async call, and/or how to prevent this from happening?

更新
根据要求,这是一个代码样本,它引起了解释的行为.我看不到这里发生的异常事件,但我向您保证,此代码正在引起解释的行为.

Update
As per a request, here is a code sample which elicits the explained behaviour. There's nothing unusual happening here that I can see but I assure you, this very code is causing the explained behaviour.

private async void dgvNewOrders_CellClick(object sender, DataGridViewCellEventArgs e)
{
    var result = await _templateInteraction.GetProjectTemplateFile(1,
                                                                   "en-US",
                                                                   "de-CH");
    return;
}

public class TemplateInteraction : ITemplateInteraction
{
    public async Task<ProjectTemplateFile> GetProjectTemplateFile(long companyId, string sourceLanguage, string targetLanguage)
    {
        return null;

        // elided code
    }

    // other methods
}

一些其他可能相关的信息:

Some other information which might be relevant:

  • 窗口的 FormBorderStyle 是"FixedToolWindow"
  • 在启动方法中,窗口具有明确的宽度
  • AutoSize = False
  • AutoSizeMode = GrowOnly
  • 正在开发的计算机没有Windows 10 1703(创作者)更新具有新的缩放逻辑
  • 如果 GetprojectTemplateFile 方法是异步方式,则 ie 具有签名 public ProjectTemplateFile GetProjecttemplateFile(...)那没有问题仅当方法调用异步时,即使我将其设为阻塞调用,此问题似乎也仍然存在.
  • The FormBorderStyle of the window is "FixedToolWindow"
  • The window is given an explicit width in a startup method
  • AutoSize = False
  • AutoSizeMode = GrowOnly
  • The computer which it's being developed on does not have the Windows 10 1703 (Creator's) update which has new scaling logic
  • If the GetprojectTemplateFile method is not async, i.e. has signature public ProjectTemplateFile GetProjecttemplateFile(...) then there is no problem. This problem appears to exist only when the method call is async - even if I make it a blocking call.

更新2:
我已经找到导致此问题的特定代码行:

UPDATE 2:
I've found the specific line(s) of code which cause this problem:

MessageBox.Show(...);

内部异步调用 GetProjectTemplateFile 会调用API,然后检查响应:

The inner async call, GetProjectTemplateFile, calls an API and then checks the response:

var responseMessage = await client.GetAsync(uri);
if (!responseMessage.IsSuccessStatusCode)
{
    MessageBox.Show(...);
    return null;
}

如果我注释掉 MessageBox.Show(...)调用,则一切正常,没有缩放问题,尺寸没有跳跃.

If I comment-out the MessageBox.Show(...) call then everything is normal, no scaling problems, no jump in dimensions.

但是当 MessageBox.Show(...)调用就位时会发生问题.

But the problem occurs when the MessageBox.Show(...) call is in-place.

此外,API的响应为200(确定),因此甚至没有使用MessageBox代码.我的猜测是JIT编译器将其视为一种可能性,所以...它重新呈现了表单?

Furthermore, the API responds with a 200 (OK) so the MessageBox code isn't even being used. My guess is that the JIT compiler sees it as a possibility so... it re-renders the form?

此外,重要的是,此代码不在表单的代码背后,而是在类中,该类在其构造函数中为其提供了实例.

Also, importantly, this code is not in the form's code-behind, it's in a class which the form is given an instance of in its constructor.

推荐答案

我猜您正在使用System.Windows命名空间中的MessageBox,而不是System.Windows.Forms命名空间?

I guess you are using MessageBox from System.Windows namespace, referenced from PresentationFramework.dll, instead of System.Windows.Forms namespace?

// Causes DPI scaling problems:
System.Windows.MessageBox.Show() // loads WPF version from PresentationFramework.dll

// no DPI scaling issues:
System.Windows.Forms.MessageBox.Show() // uses standard winforms messagebox

因此,请尝试使用标准的MessageBox代替.

So try using the standard MessageBox instead.

我发现,只要将任何以WPF为目标的dll加载到内存中,DPI自动缩放就将重置.甚至不需要实际调用该特定函数-调用父函数后即会立即加载dll.

I've found that whenever any WPF-targeted dll gets loaded into memory, the DPI autoscaling gets reset. The specific function doesn't even need to be actually called - the dll's are loaded as soon as the parent function is called.

我只有安装加​​载PresentationCore.dll的System.Windows.Input.Keyboard.IsKeyToggled()时遇到了同样的问题.以为我也发疯了...

I had same problem by just having System.Windows.Input.Keyboard.IsKeyToggled(), which loaded PresentationCore.dll. Thought I was going mad as well...

这篇关于WinForms窗口遇到异步调用时会更改尺寸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆