From 1b81ebd4036ed4ddcf31c6981e9404b02eda703f Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Mon, 25 Nov 2024 20:27:57 +0300 Subject: [PATCH 1/3] fix random crash accessing disposed LoadedImageSource --- src/Engine/Draw/Images/LoadedImageSource.cs | 52 ++++++++++++--------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Engine/Draw/Images/LoadedImageSource.cs b/src/Engine/Draw/Images/LoadedImageSource.cs index 7e6c240..d7ac804 100644 --- a/src/Engine/Draw/Images/LoadedImageSource.cs +++ b/src/Engine/Draw/Images/LoadedImageSource.cs @@ -115,25 +115,28 @@ public SKBitmap Bitmap get => _bitmap; set { - _bitmap = value; - if (_bitmap == null) + if (!IsDisposed) { - if (_image == null) + _bitmap = value; + if (_bitmap == null) { - _height = 0; - _width = 0; + if (_image == null) + { + _height = 0; + _width = 0; + } + else + { + _height = _image.Height; + _width = _image.Width; + } } else { - _height = _image.Height; - _width = _image.Width; + _height = _bitmap.Height; + _width = _bitmap.Width; } } - else - { - _height = _bitmap.Height; - _width = _bitmap.Width; - } } } @@ -142,21 +145,24 @@ public SKImage Image get => _image; set { - _image = value; - if (_image == null) + if (!IsDisposed) { - if (_bitmap == null) + _image = value; + if (_image == null) { - _height = 0; - _width = 0; + if (_bitmap == null) + { + _height = 0; + _width = 0; + } } - } - else - { - if (_bitmap == null) + else { - _height = _image.Height; - _width = _image.Width; + if (_bitmap == null) + { + _height = _image.Height; + _width = _image.Width; + } } } } From 6e87e483b2fdf4b302bbd8f63d218c1aa5c74477 Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Mon, 25 Nov 2024 20:28:21 +0300 Subject: [PATCH 2/3] format --- README.md | 2 +- .../Shaders/MultiRippleWithTouchEffect.cs | 5 +- .../Sandbox/Views/MainPageShaderRipples.xaml | 141 +++++++++--------- 3 files changed, 73 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 14ba927..b0e69b2 100644 --- a/README.md +++ b/README.md @@ -373,7 +373,7 @@ if set they will override the specific value from `Margin`, and the result would Even more, sometimes you might want to bind your code to `AddMarginTop`, `AddMarginLeft`, `AddMarginRight`, `AddMarginBottom`.. When designing custom controls please use `Margins` property to read the final margin value. -##### BindingCotext propagation in layout +##### BindingContext propagation in layout When a parent has children attached it sets their binding content to its own by calling `SetInheritedBindingContext` of the child ONLY if child's BindingContext is actually null. So when the Parent property of the child gets set to null this child BindingContext is set to null too. diff --git a/src/samples/Sandbox/Views/Controls/Shaders/MultiRippleWithTouchEffect.cs b/src/samples/Sandbox/Views/Controls/Shaders/MultiRippleWithTouchEffect.cs index 4b778c0..b8a7049 100644 --- a/src/samples/Sandbox/Views/Controls/Shaders/MultiRippleWithTouchEffect.cs +++ b/src/samples/Sandbox/Views/Controls/Shaders/MultiRippleWithTouchEffect.cs @@ -3,7 +3,8 @@ namespace Sandbox.Views.Controls; -public class MultiRippleWithTouchEffect : ShaderDoubleTexturesEffect, IStateEffect, ISkiaGestureProcessor +public class MultiRippleWithTouchEffect : ShaderDoubleTexturesEffect, + IStateEffect, ISkiaGestureProcessor { public MultiRippleWithTouchEffect() { @@ -139,4 +140,4 @@ await Parent.AnimateRangeAsync((v) => } #endregion -} \ No newline at end of file +} diff --git a/src/samples/Sandbox/Views/MainPageShaderRipples.xaml b/src/samples/Sandbox/Views/MainPageShaderRipples.xaml index 6a45f03..ea6bb8e 100644 --- a/src/samples/Sandbox/Views/MainPageShaderRipples.xaml +++ b/src/samples/Sandbox/Views/MainPageShaderRipples.xaml @@ -6,105 +6,102 @@ xmlns:controls="clr-namespace:Sandbox.Views.Controls" xmlns:demo="clr-namespace:Sandbox" xmlns:draw="http://schemas.appomobi.com/drawnUi/2023/draw" - xmlns:gestures="clr-namespace:AppoMobi.Maui.Gestures;assembly=AppoMobi.Maui.Gestures" - xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:views="clr-namespace:Sandbox.Views" x:Name="ThisPage" x:DataType="demo:MainPageViewModel"> - - - - + - - - - - - - - - + - --> + + + + + + - + VerticalOptions="Fill"> + + - + BackgroundColor="Blue" + HorizontalOptions="Fill" + Tag="Content" + Type="Column"> + - - - - + HeightRequest="350" + HorizontalOptions="Fill"> + + + + + + + - - + - - - - + + - + - + + + - + From 189056488fd98e6e6b572585102a291a37e7e479 Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Mon, 25 Nov 2024 23:21:15 +0300 Subject: [PATCH 3/3] 1.2.9.6 * HotFix for SkiaCarousel always setting index at 0 upon initialization. * HotFix for random crash accessing disposed LoadedImageSource. --- README.md | 71 ++++++++++++++----- dev/github_uploadnugets.bat | 4 +- dev/nuget_uploadnugets.bat | 4 +- .../DrawnUi.Maui.Camera.csproj | 2 +- .../DrawnUi.Maui.Game.csproj | 2 +- .../src/DrawnUi.Maui.MapsUi.csproj | 2 +- .../DrawnUi.Maui.Rive.csproj | 2 +- .../DrawnUi.MauiGraphics.csproj | 2 +- src/Directory.Build.props | 4 +- src/Engine/Controls/Carousel/SkiaCarousel.cs | 13 +++- .../Draw/Layout/SkiaLayout.ViewsAdapter.cs | 2 +- src/Engine/Draw/Layout/SkiaLayout.cs | 25 +++---- src/Engine/Draw/SkiaShape.cs | 1 - src/Engine/Views/DrawnView.cs | 3 + src/samples/Sandbox/MainPage.xaml | 1 - .../Sandbox/Views/MainPageMauiGraphics.xaml | 14 ++-- .../Sandbox/Views/MainPageShaderRipples.xaml | 3 +- 17 files changed, 100 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index b0e69b2..1ac3948 100644 --- a/README.md +++ b/README.md @@ -88,24 +88,12 @@ ___Please star ⭐ if you like it, helps very much!___ * Perspective2 -## Demo Apps - -* This repo includes a Sandbox project for some custom controls, with playground examples, custom controls, maps etc -* More creating custom controls examples inside the [Engine Demo](https://github.com/taublast/AppoMobi.Maui.DrawnUi.Demo) 🤩 __Updated with latest nuget!__ -* A [dynamic arcade game](https://github.com/taublast/AppoMobi.Maui.DrawnUi.SpaceShooter) drawn with this engine, uses preview nuget with SkiaSharp v3. -* A [drawn CollectionView demo](https://github.com/taublast/SurfAppCompareDrawn) where you could see how simple and profitable it is to convert an existing recycled cells list into a drawn one -* [Shaders Carousel Demo](https://github.com/taublast/ShadersCarousel/) featuring SkiaSharp v3 capabilities -* For production published apps list - scroll to bottom! - - [ShaderEffect.webm](https://github.com/taublast/DrawnUi.Maui/assets/25801194/47c97290-e16b-4928-bfa4-8b29fb0ff8e1) - -V3 preview: subclassed `SkiaShaderEffect`, implementing `ISkiaGestureProcessor`, `IStateEffect` and `IPostRendererEffect` when compiled for SkiaSharp v3 preview. - ## What's New -### Nuget 1.2.9.5 +### Nuget 1.2.9.6 for SkiaSharp 2.88.9-preview.2.2 - +* HotFix for SkiaCarousel always setting index at 0 upon initialization. +* HotFix for random crash accessing disposed LoadedImageSource. * [HotFix](https://github.com/taublast/DrawnUi.Maui/issues/136) for loading images from StreamImageSource * SkiaShape new Types: Polygon and Line. New property for their Points: Smooth (0-1) to smooth angles. * Shapes demo page inside SandBox project. @@ -116,6 +104,23 @@ for SkiaSharp 2.88.9-preview.2.2 * Fixed controls sometimes not invalidated when canvas suface size changes * Other fixes. +## About + +[A small article](https://taublast.github.io/posts/MauiJuly/) about the library and why it was created + +## Demo Apps + +* This repo includes a Sandbox project for some custom controls, with playground examples, custom controls, maps etc +* More creating custom controls examples inside the [Engine Demo](https://github.com/taublast/AppoMobi.Maui.DrawnUi.Demo) 🤩 __Updated with latest nuget!__ +* A [dynamic arcade game](https://github.com/taublast/AppoMobi.Maui.DrawnUi.SpaceShooter) drawn with this engine, uses preview nuget with SkiaSharp v3. +* A [drawn CollectionView demo](https://github.com/taublast/SurfAppCompareDrawn) where you could see how simple and profitable it is to convert an existing recycled cells list into a drawn one +* [Shaders Carousel Demo](https://github.com/taublast/ShadersCarousel/) featuring SkiaSharp v3 capabilities +* For production published apps list - scroll to bottom! + + [ShaderEffect.webm](https://github.com/taublast/DrawnUi.Maui/assets/25801194/47c97290-e16b-4928-bfa4-8b29fb0ff8e1) + +V3 preview: subclassed `SkiaShaderEffect`, implementing `ISkiaGestureProcessor`, `IStateEffect` and `IPostRendererEffect` when compiled for SkiaSharp v3 preview. + ## Development Notes * All files to be consumed (images etc) must be placed inside the MAUI app Resources/Raw folder, subfolders allowed. If you need to load from the native app folder use prefix "file://". @@ -162,10 +167,42 @@ As you can see in this example the Maui view `Canvas` will adapt its size to dra #### Code behind ```csharp - _todo_ + Canvas = new Canvas() + { + Gestures = GesturesMode.Enabled, + HardwareAcceleration = HardwareAccelerationMode.Enabled, + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + BackgroundColor = Colors.Black, + Content = new SkiaLayout() + { + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + Children = new List() + { + + new SkiaShape() + { + BackgroundColor = Colors.DodgerBlue, + CornerRadius = 16, + WidthRequest = 150, + HeightRequest = 150, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Content = new SkiaLabel() + { + TextColor = Colors.White, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Text="Oyee" + } + } + } + } + }; ``` -Please check the demo app, it contains many examples of usage. +Please check the Sandbox and Demo apps, they contain many examples of usage. #### Important differences between DrawnUI and Xamarin.Forms/Maui layouts: diff --git a/dev/github_uploadnugets.bat b/dev/github_uploadnugets.bat index cdcd1ce..11226b7 100644 --- a/dev/github_uploadnugets.bat +++ b/dev/github_uploadnugets.bat @@ -13,8 +13,8 @@ REM Define the source directory for the packages set "source_dir=E:\Nugets" REM Define the list of file masks for the packages -set "mask[1]=DrawnUi.Maui*.1.2.9.5*.nupkg" -set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.5*.*nupkg" +set "mask[1]=DrawnUi.Maui*.1.2.9.6*.nupkg" +set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.6*.*nupkg" set "mask_count=2" REM Loop through each file mask diff --git a/dev/nuget_uploadnugets.bat b/dev/nuget_uploadnugets.bat index b0467cb..ba35ed1 100644 --- a/dev/nuget_uploadnugets.bat +++ b/dev/nuget_uploadnugets.bat @@ -13,8 +13,8 @@ REM Define the source directory for the packages set "source_dir=E:\Nugets" REM Define the list of file masks for the packages -set "mask[1]=DrawnUi.Maui*.1.2.9.5*.nupkg" -set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.5*.*nupkg" +set "mask[1]=DrawnUi.Maui*.1.2.9.6*.nupkg" +set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.6*.*nupkg" set "mask_count=2" REM Loop through each file mask diff --git a/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj b/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj index cde8347..bd33213 100644 --- a/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj +++ b/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj @@ -44,7 +44,7 @@ - + \ No newline at end of file diff --git a/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj b/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj index ba0300b..6dcf808 100644 --- a/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj +++ b/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj @@ -42,7 +42,7 @@ - + diff --git a/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj b/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj index fe38839..b9b0675 100644 --- a/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj +++ b/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj @@ -54,7 +54,7 @@ - + diff --git a/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj b/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj index 826398b..57b26e5 100644 --- a/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj +++ b/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj b/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj index 81eeec6..58c2834 100644 --- a/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj +++ b/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj @@ -41,7 +41,7 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9e1fd5a..109d773 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,13 +5,13 @@ Using SkiaSharp 2.xx. Checkout the DrawnUi Sandbox project for usage example. - 1.2.9.5 + 1.2.9.6 $(DefineConstants);SKIA3 Using SkiaSharp 3-preview. New handlers, SKSL, WinUI hardware acceleration etc.. - 1.3.54.5-pre + 1.3.55.1-pre \ No newline at end of file diff --git a/src/Engine/Controls/Carousel/SkiaCarousel.cs b/src/Engine/Controls/Carousel/SkiaCarousel.cs index 4eeeca0..4437e91 100644 --- a/src/Engine/Controls/Carousel/SkiaCarousel.cs +++ b/src/Engine/Controls/Carousel/SkiaCarousel.cs @@ -447,8 +447,16 @@ public override object CreateContentFromTemplate() //} + private bool _itemsSourceChangedNeedResetIndex; + private bool _loaded; + + public override void OnItemSourceChanged() { + _itemsSourceChangedNeedResetIndex = _loaded; + + _loaded = true; + base.OnItemSourceChanged(); AdaptChildren(); @@ -877,7 +885,7 @@ public virtual void InitializeChildren() CurrentSnap = new(-1, -1); - if (SnapPoints.Any())// && (SelectedIndex < 0 || SelectedIndex > snapPoints.Count - 1)) + if (SnapPoints.Any() && (_itemsSourceChangedNeedResetIndex || SelectedIndex < 0 || SelectedIndex > snapPoints.Count - 1)) { SelectedIndex = 0; } @@ -886,6 +894,7 @@ public virtual void InitializeChildren() ApplyIndex(true); } + _itemsSourceChangedNeedResetIndex = false; OnChildrenInitialized(); } @@ -1149,6 +1158,8 @@ public virtual bool IsAtEnd protected virtual void OnSelectedIndexChanged(int index) { + _itemsSourceChangedNeedResetIndex = false; + SelectedIndexChanged?.Invoke(this, index); //forced to use ui-tread for maui not to randomly crash diff --git a/src/Engine/Draw/Layout/SkiaLayout.ViewsAdapter.cs b/src/Engine/Draw/Layout/SkiaLayout.ViewsAdapter.cs index 63740d3..e4181b3 100644 --- a/src/Engine/Draw/Layout/SkiaLayout.ViewsAdapter.cs +++ b/src/Engine/Draw/Layout/SkiaLayout.ViewsAdapter.cs @@ -357,7 +357,7 @@ async Task InitializeFull(bool measure) { lock (_lockTemplates) { - lock (_parent.LockMeasure) + //lock (_parent.LockMeasure) was needed testing two-threaded rendering { TemplesInvalidating = false; diff --git a/src/Engine/Draw/Layout/SkiaLayout.cs b/src/Engine/Draw/Layout/SkiaLayout.cs index acaef44..ec35b81 100644 --- a/src/Engine/Draw/Layout/SkiaLayout.cs +++ b/src/Engine/Draw/Layout/SkiaLayout.cs @@ -216,7 +216,7 @@ public SkiaLayout() { ChildrenFactory = new(this); - PostponeInvalidation(nameof(OnItemSourceChanged), OnItemSourceChanged); + PostponeInvalidation(nameof(ResetItemsSource), ResetItemsSource); //OnItemSourceChanged(); } @@ -1116,7 +1116,7 @@ public LayoutType Type nameof(InitializeTemplatesInBackgroundDelay), typeof(int), typeof(SkiaLayout), - 0, propertyChanged: ItemsSourcePropertyChanged); + 0, propertyChanged: NeedUpdateItemsSource); /// /// Whether should initialize templates in background instead of blocking UI thread, default is 0. @@ -1136,7 +1136,7 @@ public int InitializeTemplatesInBackgroundDelay typeof(ItemSizingStrategy), typeof(SkiaLayout), ItemSizingStrategy.MeasureFirstItem, - propertyChanged: ItemsSourcePropertyChanged); + propertyChanged: NeedUpdateItemsSource); public ItemSizingStrategy ItemSizingStrategy { @@ -1147,7 +1147,7 @@ public ItemSizingStrategy ItemSizingStrategy public static readonly BindableProperty ItemTemplatePoolSizeProperty = BindableProperty.Create(nameof(ItemTemplatePoolSize), typeof(int), typeof(SkiaLayout), - -1, propertyChanged: ItemsSourcePropertyChanged); + -1, propertyChanged: NeedUpdateItemsSource); /// /// Default is -1, the number od template instances will not be less than data collection count. You can manually set to to a specific number to fill your viewport etc. Beware that if you set this to a number that will not be enough to fill the viewport binding contexts will contasntly be changing triggering screen update. /// @@ -1227,29 +1227,26 @@ private static void NeedUpdateItemsSource(BindableObject bindable, object oldval //skiaControl.PostponeInvalidation(nameof(UpdateItemsSource), skiaControl.UpdateItemsSource); //skiaControl.Update(); - skiaControl.OnItemSourceChanged(); - } - - void UpdateItemsSource() - { - OnItemSourceChanged(); - - Invalidate(); + skiaControl.ResetItemsSource(); } public override void OnItemTemplateChanged() { //PostponeInvalidation(nameof(OnItemSourceChanged), OnItemSourceChanged); - OnItemSourceChanged(); + ResetItemsSource(); } public bool ApplyNewItemsSource { get; set; } public virtual void OnItemSourceChanged() + { + ResetItemsSource(); + } + + public virtual void ResetItemsSource() { //if (!string.IsNullOrEmpty(Tag)) // Debug.WriteLine($"OnItemSourceChanged {Tag} {IsTemplated} {IsMeasuring}"); - if (!IsTemplated || !BindingContextWasSet && ItemsSource == null) //do not create items from templates until the context was changed properly to avoid bugs { return; diff --git a/src/Engine/Draw/SkiaShape.cs b/src/Engine/Draw/SkiaShape.cs index 4b60148..f37892f 100644 --- a/src/Engine/Draw/SkiaShape.cs +++ b/src/Engine/Draw/SkiaShape.cs @@ -694,7 +694,6 @@ void PaintStroke(SKPaint paint) } else ctx.Canvas.DrawRect(outRect, paint); - break; case ShapeType.Circle: diff --git a/src/Engine/Views/DrawnView.cs b/src/Engine/Views/DrawnView.cs index 1284f01..310843a 100644 --- a/src/Engine/Views/DrawnView.cs +++ b/src/Engine/Views/DrawnView.cs @@ -1659,10 +1659,13 @@ public async Task ProcessOffscreenCacheRenderingAsync() var action = command.Control.GetOffscreenRenderingAction(); action?.Invoke(); + //command.Control.Repaint(); + if (_offscreenCacheRenderingQueue.Count > 0) command = _offscreenCacheRenderingQueue.Dequeue(); else break; + } catch (Exception e) { diff --git a/src/samples/Sandbox/MainPage.xaml b/src/samples/Sandbox/MainPage.xaml index 59546a6..5130bca 100644 --- a/src/samples/Sandbox/MainPage.xaml +++ b/src/samples/Sandbox/MainPage.xaml @@ -13,7 +13,6 @@ BackgroundColor="#000000"> diff --git a/src/samples/Sandbox/Views/MainPageMauiGraphics.xaml b/src/samples/Sandbox/Views/MainPageMauiGraphics.xaml index 6a8d2f8..3e7ef1f 100644 --- a/src/samples/Sandbox/Views/MainPageMauiGraphics.xaml +++ b/src/samples/Sandbox/Views/MainPageMauiGraphics.xaml @@ -3,14 +3,14 @@ x:Class="Sandbox.Views.MainPageMauiGraphics" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" + xmlns:aloha="clr-namespace:Sandbox.Views.Aloha" + xmlns:controls="clr-namespace:Sandbox.Views.Controls" xmlns:demo="clr-namespace:Sandbox" xmlns:draw="http://schemas.appomobi.com/drawnUi/2023/draw" xmlns:gestures="clr-namespace:AppoMobi.Maui.Gestures;assembly=AppoMobi.Maui.Gestures" + xmlns:mauiGraphics="clr-namespace:DrawnUi.MauiGraphics;assembly=DrawnUi.MauiGraphics" xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:views="clr-namespace:Sandbox.Views" - xmlns:aloha="clr-namespace:Sandbox.Views.Aloha" - xmlns:controls="clr-namespace:Sandbox.Views.Controls" - xmlns:mauiGraphics="clr-namespace:DrawnUi.MauiGraphics;assembly=DrawnUi.MauiGraphics" x:Name="ThisPage" x:DataType="demo:MainPageViewModel"> @@ -36,7 +36,7 @@ HorizontalOptions="Fill" Tag="Content" VerticalOptions="Fill" /> - + - - - + + + --> - +