Skip to content

Commit e5670ae

Browse files
authored
fix(Image): view.Background.ImageSource is not always valid OnLoad (microsoft#761)
Getting null reference exceptions due to a condition where the ImageSource is not always set on the ImageBrush. Instead, gathering the image metadata directly from the OnLoad event.
1 parent 4b656c2 commit e5670ae

File tree

6 files changed

+75
-35
lines changed

6 files changed

+75
-35
lines changed

ReactWindows/ReactNative/Modules/Image/BitmapImageHelpers.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ public static async Task<IRandomAccessStream> GetStreamAsync(string uri)
4949
}
5050
}
5151

52-
public static IObservable<ImageLoadStatus> GetStreamLoadObservable(this BitmapImage image)
52+
public static IObservable<ImageStatusEventData> GetStreamLoadObservable(this BitmapImage image)
5353
{
5454
return image.GetOpenedObservable()
5555
.Merge(image.GetFailedObservable(), Scheduler.Default)
56-
.StartWith(ImageLoadStatus.OnLoadStart);
56+
.StartWith(new ImageStatusEventData(ImageLoadStatus.OnLoadStart));
5757
}
5858

59-
public static IObservable<ImageLoadStatus> GetUriLoadObservable(this BitmapImage image)
59+
public static IObservable<ImageStatusEventData> GetUriLoadObservable(this BitmapImage image)
6060
{
6161
return Observable.Merge(
6262
Scheduler.Default,
@@ -65,34 +65,50 @@ public static IObservable<ImageLoadStatus> GetUriLoadObservable(this BitmapImage
6565
image.GetFailedObservable());
6666
}
6767

68-
private static IObservable<ImageLoadStatus> GetOpenedObservable(this BitmapImage image)
68+
private static IObservable<ImageStatusEventData> GetOpenedObservable(this BitmapImage image)
6969
{
7070
return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(
7171
h => image.ImageOpened += h,
7272
h => image.ImageOpened -= h)
73-
.Select(_ => ImageLoadStatus.OnLoad)
73+
.Select(args =>
74+
{
75+
var bitmapImage = args.Sender as BitmapImage;
76+
if (bitmapImage != null)
77+
{
78+
return new ImageStatusEventData(
79+
ImageLoadStatus.OnLoad,
80+
new ImageMetadata(
81+
image.UriSource?.AbsoluteUri,
82+
image.PixelWidth,
83+
image.PixelHeight));
84+
}
85+
else
86+
{
87+
return new ImageStatusEventData(ImageLoadStatus.OnLoad);
88+
}
89+
})
7490
.Take(1)
75-
.Concat(Observable.Return(ImageLoadStatus.OnLoadEnd));
91+
.Concat(Observable.Return(new ImageStatusEventData(ImageLoadStatus.OnLoadEnd)));
7692
}
7793

78-
private static IObservable<ImageLoadStatus> GetFailedObservable(this BitmapImage image)
94+
private static IObservable<ImageStatusEventData> GetFailedObservable(this BitmapImage image)
7995
{
8096
return Observable.FromEventPattern<ExceptionRoutedEventHandler, ExceptionRoutedEventArgs>(
8197
h => image.ImageFailed += h,
8298
h => image.ImageFailed -= h)
83-
.Select<EventPattern<ExceptionRoutedEventArgs>, ImageLoadStatus>(pattern =>
99+
.Select<EventPattern<ExceptionRoutedEventArgs>, ImageStatusEventData>(pattern =>
84100
{
85101
throw new InvalidOperationException(pattern.EventArgs.ErrorMessage);
86102
});
87103
}
88104

89-
private static IObservable<ImageLoadStatus> GetDownloadingObservable(this BitmapImage image)
105+
private static IObservable<ImageStatusEventData> GetDownloadingObservable(this BitmapImage image)
90106
{
91107
return Observable.FromEventPattern<DownloadProgressEventHandler, DownloadProgressEventArgs>(
92108
h => image.DownloadProgress += h,
93109
h => image.DownloadProgress -= h)
94110
.Take(1)
95-
.Select(_ => ImageLoadStatus.OnLoadStart);
111+
.Select(_ => new ImageStatusEventData(ImageLoadStatus.OnLoadStart));
96112
}
97113
}
98114
}

ReactWindows/ReactNative/Modules/Image/ImageLoaderModule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void getSize(string uriString, IPromise promise)
4141
{
4242
var bitmapImage = new BitmapImage();
4343
var loadQuery = bitmapImage.GetStreamLoadObservable()
44-
.Where(status => status == ImageLoadStatus.OnLoadEnd)
44+
.Where(status => status.LoadStatus == ImageLoadStatus.OnLoadEnd)
4545
.FirstAsync()
4646
.Replay(1);
4747

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace ReactNative.Modules.Image
2+
{
3+
struct ImageMetadata
4+
{
5+
public ImageMetadata(string uri, int width, int height)
6+
{
7+
Uri = uri;
8+
Width = width;
9+
Height = height;
10+
}
11+
12+
public string Uri { get; }
13+
14+
public int Width { get; }
15+
16+
public int Height { get; }
17+
}
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace ReactNative.Modules.Image
2+
{
3+
struct ImageStatusEventData
4+
{
5+
public ImageStatusEventData(ImageLoadStatus loadStatus)
6+
: this(loadStatus, default(ImageMetadata))
7+
{
8+
}
9+
10+
public ImageStatusEventData(ImageLoadStatus loadStatus, ImageMetadata metadata)
11+
{
12+
LoadStatus = loadStatus;
13+
Metadata = metadata;
14+
}
15+
16+
public ImageLoadStatus LoadStatus { get; }
17+
18+
public ImageMetadata Metadata { get; }
19+
}
20+
}

ReactWindows/ReactNative/ReactNative.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@
145145
<Compile Include="Modules\I18N\I18NModule.cs" />
146146
<Compile Include="Modules\I18N\I18NUtil.cs" />
147147
<Compile Include="Modules\Image\ImageLoadStatus.cs" />
148+
<Compile Include="Modules\Image\ImageMetadata.cs" />
149+
<Compile Include="Modules\Image\ImageStatusEventData.cs" />
148150
<Compile Include="Modules\Launch\LauncherModule.cs" />
149151
<Compile Include="Modules\Location\LocationModule.cs" />
150152
<Compile Include="Modules\NetInfo\DefaultNetworkInformation.cs" />

ReactWindows/ReactNative/Views/Image/ReactImageManager.cs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -253,35 +253,19 @@ private void OnImageFailed(Border view)
253253
ReactImageLoadEvent.OnLoadEnd));
254254
}
255255

256-
private void OnImageStatusUpdate(Border view, ImageLoadStatus status)
256+
private void OnImageStatusUpdate(Border view, ImageStatusEventData status)
257257
{
258258
var eventDispatcher = view.GetReactContext()
259259
.GetNativeModule<UIManagerModule>()
260260
.EventDispatcher;
261261

262-
if (status == ImageLoadStatus.OnLoad)
263-
{
264-
var bitmapImage = GetBitmapImage(view);
265-
eventDispatcher.DispatchEvent(
266-
new ReactImageLoadEvent(
267-
view.GetTag(),
268-
(int)status,
269-
bitmapImage.UriSource.AbsolutePath,
270-
bitmapImage.PixelWidth,
271-
bitmapImage.PixelHeight));
272-
}
273-
else
274-
{
275-
eventDispatcher.DispatchEvent(
276-
new ReactImageLoadEvent(
277-
view.GetTag(),
278-
(int)status));
279-
}
280-
}
281-
282-
private BitmapImage GetBitmapImage(Border view)
283-
{
284-
return (BitmapImage)((ImageBrush)view.Background).ImageSource;
262+
eventDispatcher.DispatchEvent(
263+
new ReactImageLoadEvent(
264+
view.GetTag(),
265+
(int)status.LoadStatus,
266+
status.Metadata.Uri,
267+
status.Metadata.Width,
268+
status.Metadata.Height));
285269
}
286270

287271
/// <summary>

0 commit comments

Comments
 (0)