WinForms window 在遇到异步调用时更改维度
WinForms window changes dimensions when it encounters an async call
我有一个已有数年历史的 WinForms 项目,并且已使用异步事件处理程序进行改造:
private async void dgvNewOrders_CellClick(object sender, DataGridViewCellEventArgs e)
此方法内部是一个异步调用:
var projectTemplate = await GetProjectTemplateFile(companyId, sourceLang, targetLang);
当程序 运行 在正常分辨率屏幕上运行时,它 运行 会按预期运行。但是,当 运行 在高 DPI 屏幕上时,window 的尺寸 - 以及所有子控件的尺寸 - 一旦遇到内部异步调用就会跳到一半大小。好像程序突然 运行 处于兼容模式或缩放已被禁用。
目前,为了调试问题,GetProjectTemplateFile
方法只包含
private async Task<ProjectTemplateFile> GetProjectTemplateFile(long companyId, string sourceLanguage, string targetLanguage)
{
return null;
}
GetProjectTemplateFile
是否执行异步操作没有区别。
如果我注释掉对 GetProjectTemplateFile
的异步调用,那么程序 运行 将按预期进行,没有任何尺寸跳跃,即使 [=20] 中仍有其他异步调用=] 事件.
我试过将 .ConfigureAwait(true)
附加到异步调用,这没有任何区别。 运行 也不会与 .GetAwaiter().GetResult()
同步调用。
任何人都可以解释为什么 window 的维度随着这个特定的异步调用而改变,and/or 如何防止这种情况发生?
更新
根据请求,这里是一个代码示例,它引发了解释的行为。我可以看到这里没有发生任何不寻常的事情,但我向你保证,正是这段代码导致了所解释的行为。
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
}
其他一些可能相关的信息:
- window的
FormBorderStyle
是"FixedToolWindow"
- window在启动方法中给出了明确的宽度
AutoSize
= 假
AutoSizeMode
= 仅增长
- 正在开发的计算机没有 Windows 10 1703
(创建者的)更新具有新的缩放逻辑
- 如果
GetprojectTemplateFile
方法不是异步,即有签名public ProjectTemplateFile GetProjecttemplateFile(...)
那么就没有问题.此问题似乎仅在方法调用为异步时才存在 - 即使我将其设为阻塞调用。
更新 2:
我找到了导致此问题的特定代码行:
MessageBox.Show(...);
内部异步调用 GetProjectTemplateFile
,调用 API 然后检查响应:
var responseMessage = await client.GetAsync(uri);
if (!responseMessage.IsSuccessStatusCode)
{
MessageBox.Show(...);
return null;
}
如果我注释掉 MessageBox.Show(...)
调用,那么一切正常,没有缩放问题,也没有尺寸跳跃。
但是当 MessageBox.Show(...)
调用到位时出现问题。
此外,API 以 200(OK)响应,因此甚至没有使用 MessageBox 代码。我的猜测是 JIT 编译器将其视为一种可能性,所以...它会重新呈现表单?
此外,重要的是,这段代码不在表单的代码隐藏中,它在 class 中,表单在其构造函数中给出了一个实例。
我猜您使用的是 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。还以为我要疯了...
我有一个已有数年历史的 WinForms 项目,并且已使用异步事件处理程序进行改造:
private async void dgvNewOrders_CellClick(object sender, DataGridViewCellEventArgs e)
此方法内部是一个异步调用:
var projectTemplate = await GetProjectTemplateFile(companyId, sourceLang, targetLang);
当程序 运行 在正常分辨率屏幕上运行时,它 运行 会按预期运行。但是,当 运行 在高 DPI 屏幕上时,window 的尺寸 - 以及所有子控件的尺寸 - 一旦遇到内部异步调用就会跳到一半大小。好像程序突然 运行 处于兼容模式或缩放已被禁用。
目前,为了调试问题,GetProjectTemplateFile
方法只包含
private async Task<ProjectTemplateFile> GetProjectTemplateFile(long companyId, string sourceLanguage, string targetLanguage)
{
return null;
}
GetProjectTemplateFile
是否执行异步操作没有区别。
如果我注释掉对 GetProjectTemplateFile
的异步调用,那么程序 运行 将按预期进行,没有任何尺寸跳跃,即使 [=20] 中仍有其他异步调用=] 事件.
我试过将 .ConfigureAwait(true)
附加到异步调用,这没有任何区别。 运行 也不会与 .GetAwaiter().GetResult()
同步调用。
任何人都可以解释为什么 window 的维度随着这个特定的异步调用而改变,and/or 如何防止这种情况发生?
更新
根据请求,这里是一个代码示例,它引发了解释的行为。我可以看到这里没有发生任何不寻常的事情,但我向你保证,正是这段代码导致了所解释的行为。
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
}
其他一些可能相关的信息:
- window的
FormBorderStyle
是"FixedToolWindow" - window在启动方法中给出了明确的宽度
AutoSize
= 假AutoSizeMode
= 仅增长- 正在开发的计算机没有 Windows 10 1703 (创建者的)更新具有新的缩放逻辑
- 如果
GetprojectTemplateFile
方法不是异步,即有签名public ProjectTemplateFile GetProjecttemplateFile(...)
那么就没有问题.此问题似乎仅在方法调用为异步时才存在 - 即使我将其设为阻塞调用。
更新 2:
我找到了导致此问题的特定代码行:
MessageBox.Show(...);
内部异步调用 GetProjectTemplateFile
,调用 API 然后检查响应:
var responseMessage = await client.GetAsync(uri);
if (!responseMessage.IsSuccessStatusCode)
{
MessageBox.Show(...);
return null;
}
如果我注释掉 MessageBox.Show(...)
调用,那么一切正常,没有缩放问题,也没有尺寸跳跃。
但是当 MessageBox.Show(...)
调用到位时出现问题。
此外,API 以 200(OK)响应,因此甚至没有使用 MessageBox 代码。我的猜测是 JIT 编译器将其视为一种可能性,所以...它会重新呈现表单?
此外,重要的是,这段代码不在表单的代码隐藏中,它在 class 中,表单在其构造函数中给出了一个实例。
我猜您使用的是 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。还以为我要疯了...