Skip to content

Commit 5d3675b

Browse files
Merge pull request #4020 from RosarioPulella/imageEx-test
ImageEx: test and fix setting Source
2 parents 9ff59ac + 830a878 commit 5d3675b

File tree

5 files changed

+103
-5
lines changed

5 files changed

+103
-5
lines changed

Microsoft.Toolkit.Uwp.UI.Controls.Core/ImageEx/ImageExBase.Source.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ private void AttachSource(ImageSource source)
8888
{
8989
VisualStateManager.GoToState(this, UnloadedState, true);
9090
}
91+
else if (source is BitmapSource { PixelHeight: > 0, PixelWidth: > 0 })
92+
{
93+
VisualStateManager.GoToState(this, LoadedState, true);
94+
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
95+
}
9196
}
9297

9398
private async void SetSource(object source)
@@ -124,8 +129,8 @@ private async void SetSource(object source)
124129
var url = source as string ?? source.ToString();
125130
if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri))
126131
{
127-
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new UriFormatException("Invalid uri specified.")));
128132
VisualStateManager.GoToState(this, FailedState, true);
133+
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new UriFormatException("Invalid uri specified.")));
129134
return;
130135
}
131136
}
@@ -145,8 +150,8 @@ private async void SetSource(object source)
145150
}
146151
catch (Exception e)
147152
{
148-
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));
149153
VisualStateManager.GoToState(this, FailedState, true);
154+
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));
150155
}
151156
}
152157

@@ -232,4 +237,4 @@ protected virtual Task<ImageSource> ProvideCachedResourceAsync(Uri imageUri, Can
232237
return Task.FromResult((ImageSource)new BitmapImage(imageUri));
233238
}
234239
}
235-
}
240+
}

Microsoft.Toolkit.Uwp.UI.Controls.Core/ImageEx/ImageExBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ protected override void OnApplyTemplate()
166166
/// <param name="e">Event Arguments</param>
167167
protected virtual void OnImageOpened(object sender, RoutedEventArgs e)
168168
{
169-
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
170169
VisualStateManager.GoToState(this, LoadedState, true);
170+
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
171171
}
172172

173173
/// <summary>
@@ -177,8 +177,8 @@ protected virtual void OnImageOpened(object sender, RoutedEventArgs e)
177177
/// <param name="e">Event Arguments</param>
178178
protected virtual void OnImageFailed(object sender, ExceptionRoutedEventArgs e)
179179
{
180-
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new Exception(e.ErrorMessage)));
181180
VisualStateManager.GoToState(this, FailedState, true);
181+
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new Exception(e.ErrorMessage)));
182182
}
183183

184184
private void ImageExBase_LayoutUpdated(object sender, object e)
291 Bytes
Loading
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.Toolkit.Uwp;
6+
using Microsoft.Toolkit.Uwp.UI;
7+
using Microsoft.Toolkit.Uwp.UI.Controls;
8+
using Microsoft.VisualStudio.TestTools.UnitTesting;
9+
using System;
10+
using System.IO;
11+
using System.Linq;
12+
using System.Reflection;
13+
using System.Threading.Tasks;
14+
using Windows.UI.Xaml;
15+
using Windows.UI.Xaml.Controls;
16+
using Windows.UI.Xaml.Media.Imaging;
17+
18+
namespace UnitTests.UWP.UI.Controls
19+
{
20+
[TestClass]
21+
public class Test_ImageEx : VisualUITestBase
22+
{
23+
private const string ImageString = "data:image/png;base64,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";
24+
25+
[TestMethod]
26+
public async Task SetSourceToOpenedBitmapImage()
27+
{
28+
await App.DispatcherQueue.EnqueueAsync(async () =>
29+
{
30+
var bitmapImage = new BitmapImage();
31+
32+
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(@"UnitTests.UWP.Assets.StoreLogo.embeded.png");
33+
using var memStream = new MemoryStream();
34+
await stream.CopyToAsync(memStream);
35+
memStream.Seek(0, SeekOrigin.Begin);
36+
await bitmapImage.SetSourceAsync(memStream.AsRandomAccessStream());
37+
38+
var imageLoader = new ImageEx();
39+
40+
await SetTestContentAsync(imageLoader);
41+
42+
Assert.AreEqual("Unloaded", GetCurrentState(imageLoader));
43+
44+
var imageOpendedCallCount = 0;
45+
46+
imageLoader.ImageExOpened += (s, e) =>
47+
{
48+
imageOpendedCallCount++;
49+
Assert.AreEqual("Loaded", GetCurrentState(imageLoader));
50+
};
51+
52+
imageLoader.Source = bitmapImage;
53+
54+
Assert.AreEqual(1, imageOpendedCallCount, "{0} should only be called once", nameof(ImageEx.ImageExOpened));
55+
});
56+
}
57+
58+
[TestMethod]
59+
[DataRow(ImageString)]
60+
[DataRow(@"ms-appx:///Assets/StoreLogo.png")]
61+
public async Task SetSourceToUri(string uri)
62+
{
63+
await App.DispatcherQueue.EnqueueAsync(async () =>
64+
{
65+
var imageLoader = new ImageEx();
66+
67+
await SetTestContentAsync(imageLoader);
68+
69+
Assert.AreEqual("Unloaded", GetCurrentState(imageLoader));
70+
71+
var imageOpendedCallCount = 0;
72+
imageLoader.ImageExOpened += (s, e) =>
73+
{
74+
imageOpendedCallCount++;
75+
Assert.AreEqual("Loaded", GetCurrentState(imageLoader));
76+
};
77+
78+
imageLoader.Source = new Uri(uri);
79+
80+
// TODO (2021.05.11): Test in a more deterministic way.
81+
// Setting source causes some async code to trigger and
82+
// we have no way to await or handle its complementation regardless of the result.
83+
await Task.Delay(1000);
84+
Assert.AreEqual(1, imageOpendedCallCount, "{0} should only be called once", nameof(ImageEx.ImageExOpened));
85+
});
86+
}
87+
88+
private static string GetCurrentState(ImageEx image)
89+
=> VisualStateManager.GetVisualStateGroups(image.FindDescendant<Grid>()).First(g => g.Name == "CommonStates").CurrentState.Name;
90+
}
91+
}

UnitTests/UnitTests.UWP/UnitTests.UWP.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@
201201
<Compile Include="UI\Collection\Test_IncrementalLoadingCollection.cs" />
202202
<Compile Include="UI\Controls\Test_Carousel.cs" />
203203
<Compile Include="UI\Controls\Test_BladeView.cs" />
204+
<Compile Include="UI\Controls\Test_ImageEx.cs" />
204205
<Compile Include="UI\Controls\Test_RadialGauge.cs" />
205206
<Compile Include="UI\Controls\Test_TextToolbar_Localization.cs" />
206207
<Compile Include="UI\Controls\Test_InfiniteCanvas_Regression.cs" />
@@ -241,6 +242,7 @@
241242
</ItemGroup>
242243
<ItemGroup>
243244
<Content Include="Assets\Samples\lorem.txt" />
245+
<EmbeddedResource Include="Assets\StoreLogo.embeded.png" />
244246
<Content Include="Properties\UnitTestApp.rd.xml" />
245247
<Content Include="Assets\LockScreenLogo.scale-200.png" />
246248
<Content Include="Assets\SplashScreen.scale-200.png" />

0 commit comments

Comments
 (0)