awj*_*awj 5 c# scaling highdpi winforms async-await
我有一个几年前的WinForms项目,并且已经改装了异步事件处理程序:
private async void dgvNewOrders_CellClick(object sender, DataGridViewCellEventArgs e)
Run Code Online (Sandbox Code Playgroud)
在这个方法里面是一个异步调用:
var projectTemplate = await GetProjectTemplateFile(companyId, sourceLang, targetLang);
Run Code Online (Sandbox Code Playgroud)
当程序在普通分辨率屏幕上运行时,它会按预期运行.但是,当在高DPI屏幕上运行时,窗口的尺寸 - 以及所有子控件的尺寸 - 一旦遇到内部异步调用,就会跳到一半大小.就像程序突然以兼容模式运行或者已禁用缩放一样.
目前,为了调试问题,该GetProjectTemplateFile方法仅包括
private async Task<ProjectTemplateFile> GetProjectTemplateFile(long companyId, string sourceLanguage, string targetLanguage)
{
return null;
}
Run Code Online (Sandbox Code Playgroud)
无论是否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
}
Run Code Online (Sandbox Code Playgroud)
其他一些可能相关的信息:
FormBorderStyle窗口是"FixedToolWindow"AutoSize =假AutoSizeMode = GrowOnlyGetprojectTemplateFile方法不是异步,即具有签名public ProjectTemplateFile GetProjecttemplateFile(...)则没有问题.仅当方法调用是异步时,此问题似乎才存在 - 即使我将其设置为阻塞调用.更新2:
我找到了导致此问题的特定代码行:
MessageBox.Show(...);
Run Code Online (Sandbox Code Playgroud)
内部异步调用,GetProjectTemplateFile调用API然后检查响应:
var responseMessage = await client.GetAsync(uri);
if (!responseMessage.IsSuccessStatusCode)
{
MessageBox.Show(...);
return null;
}
Run Code Online (Sandbox Code Playgroud)
如果我注释掉MessageBox.Show(...)调用,则一切正常,没有缩放问题,没有尺寸跳跃.
但是当MessageBox.Show(...)呼叫到位时会出现问题.
此外,API以200(OK)响应,因此甚至没有使用MessageBox代码.我的猜测是JIT编译器认为它是一种可能性......它重新呈现表单?
此外,重要的是,这个代码不是代码隐藏的形式,它在一个类中,表单在其构造函数中被赋予了一个实例.
我猜您正在使用 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
Run Code Online (Sandbox Code Playgroud)
因此,请尝试改用标准 MessageBox。
我发现每当任何以 WPF 为目标的 dll 加载到内存中时,DPI 自动缩放都会重置。甚至不需要实际调用特定的函数——只要调用父函数,就会加载 dll。
我只使用 System.Windows.Input.Keyboard.IsKeyToggled() 就遇到了同样的问题,它加载了 PresentationCore.dll。还以为我要疯了……
| 归档时间: |
|
| 查看次数: |
168 次 |
| 最近记录: |