Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: [iOS] [Android] Fix set bitmap stream after delay not update Image - set bitmap URI not update ImageBrush #8370

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,40 @@ public void Image_Source_Nullify()
ImageAssert.AreEqual(beforeLoad, afterClear, physicalRect, tolerance: PixelTolerance.Exclusive(1));
}

[Test]
[AutoRetry]
public void BitmapImage_is_SetSource_After_Delay()
{
Run("Uno.UI.Samples.UITests.Image.ImageSourceDelay");

var SUT = _app.Marked("imgControl");
var txt = _app.Marked("txtStatus");
var btn1 = _app.Marked("btnLoadBmp1");
var btn2 = _app.Marked("btnLoadBmp2");

_app.WaitForElement(SUT, null, TimeSpan.FromSeconds(10),null, null);
_app.WaitForElement(txt);

_app.WaitForElement(btn1);
_app.WaitForElement(btn2);

_app.FastTap(btn1);

_app.WaitForText(txt, "Bmp1");

var screenRect = _app.GetPhysicalRect(SUT);

using var before = TakeScreenshot("Before");

_app.FastTap(btn2);

_app.WaitForText(txt, "Bmp2");

using var after = TakeScreenshot("After");

ImageAssert.AreNotEqual(before, after, screenRect);
}

private void WaitForBitmapOrSvgLoaded()
{
var isLoaded = _app.Marked("isLoaded");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using SamplesApp.UITests.TestFramework;
using Uno.UITest.Helpers;
using Uno.UITest.Helpers.Queries;

namespace SamplesApp.UITests.Windows_UI_Xaml_Media.ImageBrushTests
{
[TestFixture]
public partial class ImageBrush_Tests : SampleControlUITestBase
{
[Test]
[AutoRetry]
[ActivePlatforms(Platform.Android, Platform.iOS)]
public void When_ImageBrush_Source_URI_Changes()
{
Run("Uno.UI.Samples.UITests.ImageBrushTestControl.ImageBrushChangingURI");

var border = _app.Marked("brCont");
var txt = _app.Marked("txtStatus");

_app.WaitForElement(border);
_app.WaitForElement(txt);

var screenRect = _app.GetPhysicalRect(border);

using var before = TakeScreenshot("Before", ignoreInSnapshotCompare: true);

_app.FastTap("btnImage1");

_app.WaitForText("txtStatus", "Changed");

using var after = TakeScreenshot("After");

ImageAssert.AreNotEqual(before, after, screenRect);
}
}
}
14 changes: 14 additions & 0 deletions src/SamplesApp/UITests.Shared/UITests.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\ImageTests\ImageSourceDelay.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\PasswordBoxTests\PasswordBox_AutoFill.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down Expand Up @@ -4161,6 +4165,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\ImageBrushTests\ImageBrushChangingURI.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\ImageBrushTests\ImageBrushShapeStretchesAlignments.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down Expand Up @@ -6164,6 +6172,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\ImageTests\ImageAlignment2541.xaml.cs">
<DependentUpon>ImageAlignment2541.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\ImageTests\ImageSourceDelay.xaml.cs">
<DependentUpon>ImageSourceDelay.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Controls\ImageTests\ImageSourceUrlMsAppDataScheme.xaml.cs">
<DependentUpon>ImageSourceUrlMsAppDataScheme.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -7439,6 +7450,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\GradientBrushTests\LinearGradientBrush_Opacity.xaml.cs">
<DependentUpon>LinearGradientBrush_Opacity.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\ImageBrushTests\ImageBrushChangingURI.xaml.cs">
<DependentUpon>ImageBrushChangingURI.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media\ImageBrushTests\ImageBrushShapeStretchesAlignments.xaml.cs">
<DependentUpon>ImageBrushShapeStretchesAlignments.xaml</DependentUpon>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<UserControl
x:Class="Uno.UI.Samples.UITests.Image.ImageSourceDelay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Samples.UITests.Image"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<StackPanel>

<Button x:Name="btnLoadBmp1" Click="btnLoadBmp1_Click">Load Image 1</Button>
<Button x:Name="btnLoadBmp2" Click="btnLoadBmp2_Click">Load Image 2</Button>
<TextBlock x:Name="txtStatus"></TextBlock>

<Image x:Name="imgControl" Height="50" />


</StackPanel>

</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Uno.UI.Samples.Controls;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

namespace Uno.UI.Samples.UITests.Image
{
[SampleControlInfo("Image", "ImageSourceDelay")]
public sealed partial class ImageSourceDelay : UserControl
{
public ImageSourceDelay()
{
this.InitializeComponent();
}

private void btnLoadBmp1_Click(object sender, RoutedEventArgs e)
{
imgControl.Source = GetBitmap("ms-appx:///Assets/search.png");
txtStatus.Text = "Bmp1";
}

private void btnLoadBmp2_Click(object sender, RoutedEventArgs e)
{
imgControl.Source = GetBitmap("ms-appx:///Assets/cart.png");
txtStatus.Text = "Bmp2";
}

private BitmapImage GetBitmap(string fname)
{
var bmp = new BitmapImage();
LoadImage();
return bmp;

async void LoadImage()
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(fname));
using (var fs = await file.OpenStreamForReadAsync())
{
await Task.Delay(100);
await bmp.SetSourceAsync(fs.AsRandomAccessStream());
}

}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<UserControl
x:Class="Uno.UI.Samples.UITests.ImageBrushTestControl.ImageBrushChangingURI"
xmlns:controls="using:Uno.UI.Samples.Controls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="Uno.UI.Samples.UITests.ImageBrushTestControl"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="using:Uno.UI.Samples.Controls"
xmlns:ios="http://uno.ui/ios"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:android="http://uno.ui/android"
mc:Ignorable="d ios android"
d:DesignHeight="2000"
d:DesignWidth="400">

<StackPanel>
<Button x:Name="btnImage1" HorizontalAlignment="Center" Margin="8" Click="OnButton1">Image 1</Button>
<Button x:Name="btnImage2" HorizontalAlignment="Center" Margin="8" Click="OnButton2">Image 2</Button>
<TextBlock x:Name="txtStatus"></TextBlock>
<Border Width="48" Height="48" CornerRadius="8" x:Name="brCont">
<Border.Background>
<ImageBrush Stretch="None" x:Name="brush">
<ImageBrush.ImageSource>
<BitmapImage UriSource="{x:Bind TileContent, Mode=OneWay}" DecodePixelType="Logical" />
</ImageBrush.ImageSource>
</ImageBrush>
</Border.Background>
</Border>
</StackPanel>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Uno.UI.Samples.Controls;
using Uno.UI.Samples.UITests.ImageTests.Models;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace Uno.UI.Samples.UITests.ImageBrushTestControl
{
[SampleControlInfo("ImageBrushTestControl", "ImageBrushChangingURI")]
public sealed partial class ImageBrushChangingURI : UserControl
{
public static readonly DependencyProperty TileContentProperty = DependencyProperty.Register(nameof(TileContent), typeof(Uri), typeof(ImageBrushChangingURI), new PropertyMetadata(new Uri("https://cdn.pixabay.com/photo/2020/03/09/17/51/narcis-4916584_960_720.jpg")));

public Uri TileContent
{
get { return (Uri)GetValue(TileContentProperty); }
set { SetValue(TileContentProperty, value); }
}

public ImageBrushChangingURI()
{
this.InitializeComponent();

TileContent = new Uri("ms-appx:///Assets/rect.png");
}

private void OnButton1(object sender, RoutedEventArgs e)
{
TileContent = new Uri("ms-appx:///Assets/cart.png");
txtStatus.Text = "Changed";
}
private void OnButton2(object sender, RoutedEventArgs e)
{
TileContent = new Uri("ms-appx:///Assets/rect.png");
txtStatus.Text = "Changed";
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ public void UpdateLayer(
return;
}

var imageHasChanged = newState.BackgroundImageSource != previousLayoutState?.BackgroundImageSource;
var shouldDisposeEagerly = imageHasChanged || newState.BackgroundImageSource == null;
var shouldDisposeEagerly = newState.BackgroundImageSource == null;
if (shouldDisposeEagerly)
{
// Clear previous value anyway in order to make sure the previous values are unset before the new ones.
Expand Down Expand Up @@ -494,6 +493,8 @@ private class LayoutState : IEquatable<LayoutState>
public readonly Thickness Padding;
public readonly Color? BackgroundFallbackColor;

public readonly long? StateVersion;

public LayoutState(Windows.Foundation.Rect area, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, Thickness padding)
{
Area = area;
Expand All @@ -506,6 +507,8 @@ public LayoutState(Windows.Foundation.Rect area, Brush background, Thickness bor
var imageBrushBackground = Background as ImageBrush;
BackgroundImageSource = imageBrushBackground?.ImageSource;

StateVersion = BackgroundImageSource?.StateVersion;

BackgroundColor = (Background as SolidColorBrush)?.Color;
BorderBrushColor = (BorderBrush as SolidColorBrush)?.Color;

Expand All @@ -515,6 +518,7 @@ public LayoutState(Windows.Foundation.Rect area, Brush background, Thickness bor
public bool Equals(LayoutState other)
{
return other != null
&& other.StateVersion == StateVersion
&& other.Area == Area
&& other.Background == Background
&& other.BackgroundImageSource == BackgroundImageSource
Expand Down
7 changes: 3 additions & 4 deletions src/Uno.UI/UI/Xaml/Controls/Image/Image.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ private void OnSourceChanged(ImageSource newValue, bool forceReload = false)
}
else if (newValue is WriteableBitmap wb)
{
wb.Invalidated += OnInvalidated;
_sourceDisposable.Disposable = Disposable.Create(() => wb.Invalidated -= OnInvalidated);
newValue.InvalidateSource += OnInvalidateSource;
_sourceDisposable.Disposable = Disposable.Create(() => newValue.InvalidateSource -= OnInvalidateSource);

void OnInvalidated(object sdn, EventArgs args)
void OnInvalidateSource(object sdn, EventArgs args)
{
_openedSource = null;
TryOpenImage();
Expand Down Expand Up @@ -138,7 +138,6 @@ void OnInvalidated(object sdn, EventArgs args)

_sourceDisposable.Disposable = compositeDisposable;
}

TryOpenImage(forceReload);
}

Expand Down
33 changes: 9 additions & 24 deletions src/Uno.UI/UI/Xaml/Media/Brush.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,33 +90,18 @@ internal static IDisposable AssignAndObserveBrush(Brush b, ColorSetterHandler co
}
else if (b is ImageBrush imageBrush && imageBrushCallback != null)
{
var disposables = new CompositeDisposable(5);
var disposables = new CompositeDisposable(6);
This conversation was marked as resolved.
Show resolved Hide resolved
imageBrushCallback();

void ImageChanged()
{
imageBrushCallback();
}

imageBrush.RegisterDisposablePropertyChangedCallback(
ImageBrush.ImageSourceProperty,
(_, __) => imageBrushCallback()
).DisposeWith(disposables);

imageBrush.RegisterDisposablePropertyChangedCallback(
ImageBrush.StretchProperty,
(_, __) => imageBrushCallback()
).DisposeWith(disposables);

imageBrush.RegisterDisposablePropertyChangedCallback(
ImageBrush.AlignmentXProperty,
(_, __) => imageBrushCallback()
).DisposeWith(disposables);

imageBrush.RegisterDisposablePropertyChangedCallback(
ImageBrush.AlignmentYProperty,
(_, __) => imageBrushCallback()
).DisposeWith(disposables);
imageBrush.ImageChanged += ImageChanged;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes overlap the contents of #12234 by @MartinZikmund, where we want to remove subscriptions and events in general (they're more costly than using method overrides). What do you think, @MartinZikmund?

Disposable.Create(() => imageBrush.ImageChanged -= ImageChanged)
.DisposeWith(disposables);

imageBrush.RegisterDisposablePropertyChangedCallback(
ImageBrush.RelativeTransformProperty,
(_, __) => imageBrushCallback()
).DisposeWith(disposables);

return disposables;
}
Expand Down
Loading