数年前の 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
= 成長のみ- 開発中のコンピューターには、新しいスケーリング ロジックを備えた Windows 10 1703 (Creator's) 更新プログラムがありません。
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 コンパイラーはそれを可能性として認識しているので、フォームを再レンダリングしますか?
また、重要なことに、このコードはフォームの分離コードではなく、コンストラクターでフォームのインスタンスが与えられるクラスにあります。