2017-06-14 50 views
5

我有一个WinForms项目,该项目是几年前的,并已改装与异步事件处理程序:的WinForms窗口更改尺寸,当它遇到一个异步调用

private async void dgvNewOrders_CellClick(object sender, DataGridViewCellEventArgs e) 

在此方法是一个异步调用:

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

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

目前,为了调试问题,GetProjectTemplateFile方法包括单纯的

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

没有什么差别GetProjectTemplateFile是否执行异步操作与否。

如果我将异步调用注释为GetProjectTemplateFile,那么程序将按预期方式运行,而不会发生任何维度跳转,即使CellClick事件中还存在其他异步调用。

我试着在异步调用中追加.ConfigureAwait(true),这没什么区别。也不会与.GetAwaiter().GetResult()同步运行呼叫。

任何人都可以解释为什么窗口的尺寸正在改变这种特殊的异步调用,和/或如何防止这种情况发生?

更新
作为每一个请求,这里是一个代码示例,其引起的解释行为。我可以看到这里没有什么不寻常的事情发生,但我向你保证,这段代码引起了解释的行为。

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 
} 

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

  • 窗口的FormBorderStyle是“FixedToolWindow”
  • 该窗口在启动方法
  • AutoSize =假给出一个明确的宽度
  • AutoSizeMode = GrowOnly
  • The其中它被上发展起来的计算机不具有Windows 10 1703 (造物主)更新,其中有新的缩放逻辑
  • 如果GetprojectTemplateFile方法异步,已签名public ProjectTemplateFile GetProjecttemplateFile(...)那么就没有问题。这个问题似乎只在方法调用是异步的时候才存在 - 即使我把它作为阻塞调用。

更新2:
我发现特定的代码线(S),其导致此问题:

MessageBox.Show(...); 

内异步调用,GetProjectTemplateFile,调用API,然后检查回应:

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

如果我注释掉的MessageBox.Show(...)呼叫,则一切正常,不结垢proble毫秒,尺寸没有跳跃。

但是,当MessageBox.Show(...)调用就地发生时会出现问题。

此外,API响应200(OK),所以MessageBox代码甚至没有被使用。我的猜测是JIT编译器认为它是一种可能性,所以它重新呈现表单?

此外,重要的是,此代码不在窗体的代码隐藏中,它在一个类中,窗体在其构造函数中被赋予一个实例。

+2

请发布一个完整的,最小的样本,将重新创建你所看到的行为。包括任何可能相关的东西,你使用的是什么框架,操作系统等等。如果'async'真正随机地改变了表单的大小,那么至少可以调查一下。 – JSteward

+0

感谢您的更新,但我无法重现您所看到的内容。这里是我使用的代码:[dotnet Fiddle](https://dotnetfiddle.net/6Sn4cj) – JSteward

+0

即使使用.NET 4.6? – awj

回答

3

我想你是从System.Windows命名空间使用MessageBox,从PresentationFramework.dll引用,而不是System.Windows.Forms命名空间?

// 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代替。

我发现,每当任何WPF的目标dll被加载到内存中,DPI自动调节得到重置。特定函数甚至不需要实际调用 - 只要父函数被调用,dll就会被加载。

我有相同的问题,只是有System.Windows.Input.Keyboard.IsKeyToggled(),它加载PresentationCore.dll。以为我也很生气......

+0

是的,您是对的。对不起,我几个月前发现了这个,但从未更新OP。 – awj