Assert.Equal(picbox.ErrorImage, ((PictureBox)picbox).Image);
}
+
+ [WinFormsFact]
+ public async Task SetImageFromAsync_OutdatedTest()
+ {
+ using var picbox = new OTPictureBox();
+
+ // 1回目
+ var tcs1 = new TaskCompletionSource<MemoryImage>();
+ var setImageTask1 = picbox.SetImageFromTask(() => tcs1.Task);
+
+ // 2回目
+ var tcs2 = new TaskCompletionSource<MemoryImage>();
+ var setImageTask2 = picbox.SetImageFromTask(() => tcs2.Task);
+
+ Assert.Same(picbox.InitialImage, ((PictureBox)picbox).Image);
+
+ // 2回目のタスクが先に完了する
+ using var image2 = TestUtils.CreateDummyImage();
+ tcs2.SetResult(image2);
+ await setImageTask2;
+ Assert.Same(image2, picbox.Image);
+
+ // 1回目のタスクが完了したとしても、最後に呼んだ SetImageFromTask の画像を表示し続ける
+ using var image1 = TestUtils.CreateDummyImage();
+ tcs1.SetResult(image1);
+ await setImageTask1;
+ Assert.Same(image2, picbox.Image);
+ }
+
+ [WinFormsFact]
+ public async Task SetImageFromAsync_OutdatedByImageSetterTest()
+ {
+ using var picbox = new OTPictureBox();
+
+ // 1回目
+ var tcs1 = new TaskCompletionSource<MemoryImage>();
+ var setImageTask1 = picbox.SetImageFromTask(() => tcs1.Task);
+
+ // 2回目 (set_Image による同期的な更新)
+ using var image2 = TestUtils.CreateDummyImage();
+ picbox.Image = image2;
+ Assert.Same(image2, picbox.Image);
+
+ // 1回目のタスクが完了したとしても、最後にセットされた Image の画像を表示し続ける
+ using var image1 = TestUtils.CreateDummyImage();
+ tcs1.SetResult(image1);
+ await setImageTask1;
+ Assert.Same(image2, picbox.Image);
+ }
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new MemoryImage? Image
{
+ get => this.ImageInternal;
+ set
+ {
+ this.ImageInternal = value;
+
+ // Image を直接更新した場合も SetImageFromTask による更新をキャンセルした扱いにする
+ Interlocked.Increment(ref this.currentImageTaskId);
+ }
+ }
+
+ private MemoryImage? ImageInternal
+ {
get => this.memoryImage;
set
{
var image = await Task.Run(imageTask);
if (id == this.currentImageTaskId)
- this.Image = image;
+ this.ImageInternal = image;
}
catch (Exception)
{