From 4cfdf62cfb289b7c70ba958e647cc69d05d8f808 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Mon, 20 Sep 2021 16:51:19 -0500 Subject: [PATCH 01/22] - Generalize Image Loader Code --- .../Core/HandlerImpl/Button/Button.Impl.cs | 23 ++++--- .../ImageButton/ImageButton.Impl.cs | 30 +++++++++ src/Controls/src/Core/ImageButton.cs | 2 +- src/Core/src/CommandMapper.cs | 11 +-- src/Core/src/Core/IButton.cs | 2 +- src/Core/src/Core/IImageButton.cs | 9 +++ src/Core/src/Core/IText.cs | 2 +- src/Core/src/Core/ITextStyle.cs | 2 +- .../Handlers/Button/ButtonHandler.Android.cs | 59 +++++++--------- .../Handlers/Button/ButtonHandler.Standard.cs | 16 +++-- .../Handlers/Button/ButtonHandler.Windows.cs | 43 ++++++++---- src/Core/src/Handlers/Button/ButtonHandler.cs | 47 ++++++++++--- .../src/Handlers/Button/ButtonHandler.iOS.cs | 67 +++++++++---------- .../src/Handlers/Button/IButtonHandler.cs | 27 ++++++++ src/Core/src/Handlers/Image/IImageHandler.cs | 19 ++++++ .../Handlers/Image/ImageHandler.Android.cs | 54 ++++++++------- .../Handlers/Image/ImageHandler.Standard.cs | 15 +++-- .../Handlers/Image/ImageHandler.Windows.cs | 47 ++++++------- src/Core/src/Handlers/Image/ImageHandler.cs | 42 +++++++++--- .../src/Handlers/Image/ImageHandler.iOS.cs | 32 ++++----- .../ImageButton/ImageButtonHandler.Android.cs | 23 +++++++ .../ImageButtonHandler.Standard.cs | 13 ++++ .../ImageButton/ImageButtonHandler.cs | 40 +++++++++++ .../ImageSourceServiceResultManager.cs | 2 +- .../src/Platform/Android/ButtonExtensions.cs | 3 - .../Android/ImageSourcePartWrapper.cs | 17 ++--- .../Platform/Android/ImageViewExtensions.cs | 10 --- .../Platform/Android/TextViewExtensions.cs | 2 +- .../src/Platform/ElementHandlerExtensions.cs | 10 +-- .../src/Platform/ImageSourcePartWrapper.cs | 35 +++++----- .../Standard/ImageSourcePartWrapper.cs | 21 ++++++ .../src/Platform/Windows/ButtonExtensions.cs | 15 +---- .../src/Platform/Windows/ControlExtensions.cs | 9 +++ .../Windows/ImageSourcePartWrapper.cs | 28 ++++++++ .../Platform/Windows/ImageViewExtensions.cs | 20 ++++-- .../Platform/Windows/TextBlockExtensions.cs | 6 +- src/Core/src/Platform/iOS/ButtonExtensions.cs | 6 +- .../Platform/iOS/ImageSourcePartWrapper.cs | 16 ++--- .../src/Platform/iOS/ImageViewExtensions.cs | 10 ++- src/Core/src/Platform/iOS/LabelExtensions.cs | 2 +- src/Core/src/Platform/iOS/MauiImageView.cs | 2 +- src/Core/src/Platform/iOS/MauiLabel.cs | 2 +- src/Core/src/PropertyMapper.cs | 58 ++++++++++++---- 43 files changed, 603 insertions(+), 296 deletions(-) create mode 100644 src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs create mode 100644 src/Core/src/Core/IImageButton.cs create mode 100644 src/Core/src/Handlers/Button/IButtonHandler.cs create mode 100644 src/Core/src/Handlers/Image/IImageHandler.cs create mode 100644 src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs create mode 100644 src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs create mode 100644 src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs create mode 100644 src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs create mode 100644 src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs diff --git a/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs b/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs index f692cbb2d5b2..e937b8d43b7e 100644 --- a/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs @@ -4,13 +4,13 @@ namespace Microsoft.Maui.Controls { - public partial class Button : IButton + public partial class Button : IButton, IText, IImageSourcePart { public new static void RemapForControls() { // IButton does not include the ContentType property, so we map it here to handle Image Positioning - IPropertyMapper ControlsButtonMapper = new PropertyMapper(ButtonHandler.ButtonMapper) + IPropertyMapper ControlsButtonMapper = new PropertyMapper(ButtonMapper.Mapper) { [nameof(ContentLayout)] = MapContentLayout, #if __IOS__ @@ -18,12 +18,16 @@ public partial class Button : IButton #endif }; - ButtonHandler.ButtonMapper = ControlsButtonMapper; + ButtonMapper.Mapper = ControlsButtonMapper; } - public static void MapContentLayout(ButtonHandler handler, Button button) + public static void MapContentLayout(IButtonHandler handler, Button button) { - handler.NativeView.UpdateContentLayout(button); +#if __IOS__ + (handler.NativeView as UIKit.UIButton)?.UpdateContentLayout(button); +#elif __ANDROID__ + (handler.NativeView as Google.Android.Material.Button.MaterialButton)?.UpdateContentLayout(button); +#endif } void IButton.Clicked() @@ -41,12 +45,15 @@ void IButton.Released() (this as IButtonController).SendReleased(); } - void IButton.ImageSourceLoaded() + IImageSource IImageSourcePart.Source => ImageSource; + + void IImageSourcePart.UpdateIsLoading(bool isLoading) { - Handler?.UpdateValue(nameof(ContentLayout)); + if (!isLoading) + Handler?.UpdateValue(nameof(ContentLayout)); } - IImageSource IButton.ImageSource => ImageSource; + bool IImageSourcePart.IsAnimationPlaying => false; Font ITextStyle.Font => (Font)GetValue(FontElement.FontProperty); } diff --git a/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs b/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs new file mode 100644 index 000000000000..9adbe8b6eec2 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Maui.Controls +{ + public partial class ImageButton : IImageButton + { + IImageSource IImageSourcePart.Source => Source; + + void IImageSourcePart.UpdateIsLoading(bool isLoading) { } + + bool IImageSourcePart.IsAnimationPlaying => false; + + void IButton.Clicked() + { + (this as IButtonController).SendClicked(); + } + + void IButton.Pressed() + { + (this as IButtonController).SendPressed(); + } + + void IButton.Released() + { + (this as IButtonController).SendReleased(); + } + } +} diff --git a/src/Controls/src/Core/ImageButton.cs b/src/Controls/src/Core/ImageButton.cs index 9bae5e038b53..41327ba33c05 100644 --- a/src/Controls/src/Core/ImageButton.cs +++ b/src/Controls/src/Core/ImageButton.cs @@ -8,7 +8,7 @@ namespace Microsoft.Maui.Controls { - public class ImageButton : View, IImageController, IElementConfiguration, IBorderElement, IButtonController, IViewController, IPaddingElement, IButtonElement, IImageElement + public partial class ImageButton : View, IImageController, IElementConfiguration, IBorderElement, IButtonController, IViewController, IPaddingElement, IButtonElement, IImageElement { const int DefaultCornerRadius = -1; diff --git a/src/Core/src/CommandMapper.cs b/src/Core/src/CommandMapper.cs index e19b5eb5a64e..1cd36924255d 100644 --- a/src/Core/src/CommandMapper.cs +++ b/src/Core/src/CommandMapper.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Command = System.Action; +using Command = System.Action; namespace Microsoft.Maui { @@ -24,7 +24,7 @@ private protected virtual void SetPropertyCore(string key, Command action) _mapper[key] = action; } - private protected virtual void InvokeCore(string key, IElementHandler viewHandler, IElement virtualView, object? args) + private protected virtual void InvokeCore(string key, object viewHandler, IElement virtualView, object? args) { var action = GetCommandCore(key); action?.Invoke(viewHandler, virtualView, args); @@ -60,7 +60,6 @@ public CommandMapper? Chained public class CommandMapper : CommandMapper where TVirtualView : IElement - where TViewHandler : IElementHandler { public CommandMapper() { @@ -76,7 +75,11 @@ public CommandMapper(CommandMapper chained) get { var action = GetCommandCore(key) ?? throw new IndexOutOfRangeException($"Unable to find mapping for '{nameof(key)}'."); - return new Action((h, v, o) => action.Invoke(h, v, o)); + return new Action((h, v, o) => + { + if (h is TViewHandler viewHandler) + action.Invoke(viewHandler, v, o); + }); } set => Add(key, value); } diff --git a/src/Core/src/Core/IButton.cs b/src/Core/src/Core/IButton.cs index 491734f8ade9..806df94359e2 100644 --- a/src/Core/src/Core/IButton.cs +++ b/src/Core/src/Core/IButton.cs @@ -3,7 +3,7 @@ namespace Microsoft.Maui /// /// Represents a View that reacts to touch events. /// - public interface IButton : IView, IText, IPadding + public interface IButton : IView, IPadding { /// /// Allows you to display a bitmap image on the Button. diff --git a/src/Core/src/Core/IImageButton.cs b/src/Core/src/Core/IImageButton.cs new file mode 100644 index 000000000000..819ad46582ff --- /dev/null +++ b/src/Core/src/Core/IImageButton.cs @@ -0,0 +1,9 @@ +namespace Microsoft.Maui +{ + /// + /// Represents a View that reacts to touch events. + /// + public interface IImageButton : IButton, IImage + { + } +} \ No newline at end of file diff --git a/src/Core/src/Core/IText.cs b/src/Core/src/Core/IText.cs index 194fe7003354..963ee83ebdf3 100644 --- a/src/Core/src/Core/IText.cs +++ b/src/Core/src/Core/IText.cs @@ -3,7 +3,7 @@ namespace Microsoft.Maui /// /// Provides functionality to be able to customize Text. /// - public interface IText : ITextStyle + public interface IText : ITextStyle, IElement { /// /// Gets the text. diff --git a/src/Core/src/Core/ITextStyle.cs b/src/Core/src/Core/ITextStyle.cs index f9356ffdbc4d..55f05760e89b 100644 --- a/src/Core/src/Core/ITextStyle.cs +++ b/src/Core/src/Core/ITextStyle.cs @@ -5,7 +5,7 @@ namespace Microsoft.Maui /// /// Provides functionality to be able to customize the appearance of text. /// - public interface ITextStyle + public interface ITextStyle : IElement { /// /// Gets the text color. diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Android.cs b/src/Core/src/Handlers/Button/ButtonHandler.Android.cs index abc1b44006c0..73856ba69c3a 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Android.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Android.cs @@ -18,14 +18,9 @@ public partial class ButtonHandler : ViewHandler { static Thickness? DefaultPadding; static Drawable? DefaultBackground; - ImageSourcePartWrapper? _imageSourcePartWrapper; - ButtonClickListener ClickListener { get; } = new ButtonClickListener(); - ButtonTouchListener TouchListener { get; } = new ButtonTouchListener(); - - ImageSourcePartWrapper ImageSourcePartWrapper => - _imageSourcePartWrapper ??= new ImageSourcePartWrapper( - this, (h) => h.VirtualView.ImageSource, null, null, OnSetImageSourceDrawable); + public ButtonClickListener ClickListener { get; } = new ButtonClickListener(); + public ButtonTouchListener TouchListener { get; } = new ButtonTouchListener(); static ColorStateList? _transparentColorStateList; @@ -72,56 +67,61 @@ protected override void DisconnectHandler(MaterialButton nativeView) TouchListener.Handler = null; nativeView.SetOnTouchListener(null); - _sourceManager.Reset(); + ImageSourceLoader.Reset(); base.DisconnectHandler(nativeView); } // This is a Android-specific mapping - public static void MapBackground(ButtonHandler handler, IButton button) + public static void MapBackground(IButtonHandler handler, IButton button) { - handler.NativeView?.UpdateBackground(button, DefaultBackground); + handler.TypedNativeView?.UpdateBackground(button, DefaultBackground); } - public static void MapText(ButtonHandler handler, IButton button) + public static void MapText(IButtonHandler handler, IText button) { - handler.NativeView?.UpdateText(button); + handler.TypedNativeView?.UpdateTextPlainText(button); } - public static void MapTextColor(ButtonHandler handler, IButton button) + public static void MapTextColor(IButtonHandler handler, ITextStyle button) { - handler.NativeView?.UpdateTextColor(button); + handler.TypedNativeView?.UpdateTextColor(button); } - public static void MapCharacterSpacing(ButtonHandler handler, IButton button) + public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { - handler.NativeView?.UpdateCharacterSpacing(button); + handler.TypedNativeView?.UpdateCharacterSpacing(button); } - public static void MapFont(ButtonHandler handler, IButton button) + public static void MapFont(IButtonHandler handler, ITextStyle button) { var fontManager = handler.GetRequiredService(); - handler.NativeView?.UpdateFont(button, fontManager); + handler.TypedNativeView?.UpdateFont(button, fontManager); } - public static void MapPadding(ButtonHandler handler, IButton button) + public static void MapPadding(IButtonHandler handler, IButton button) { - handler.NativeView?.UpdatePadding(button, DefaultPadding); + handler.TypedNativeView?.UpdatePadding(button, DefaultPadding); } - public static void MapImageSource(ButtonHandler handler, IButton image) => + public static void MapImageSource(IButtonHandler handler, IButton image) => MapImageSourceAsync(handler, image).FireAndForget(handler); - public static Task MapImageSourceAsync(ButtonHandler handler, IButton image) + public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) { if (image.ImageSource == null) { - handler.OnSetImageSourceDrawable(null); return Task.CompletedTask; } - return handler.ImageSourcePartWrapper.UpdateImageSource(); + return handler.ImageSourceLoader.UpdateImageSourceAsync(); + } + + void OnSetImageSource(Drawable? obj) + { + NativeView.Icon = obj; + VirtualView?.ImageSourceLoaded(); } bool NeedsExactMeasure() @@ -176,13 +176,6 @@ int MakeMeasureSpecExact(double size) return MeasureSpecMode.Exactly.MakeMeasureSpec(deviceSize); } - - void OnSetImageSourceDrawable(Drawable? obj) - { - NativeView.Icon = obj; - VirtualView?.ImageSourceLoaded(); - } - bool OnTouch(IButton? button, AView? v, MotionEvent? e) { switch (e?.ActionMasked) @@ -203,7 +196,7 @@ void OnClick(IButton? button, AView? v) button?.Clicked(); } - class ButtonClickListener : Java.Lang.Object, AView.IOnClickListener + public class ButtonClickListener : Java.Lang.Object, AView.IOnClickListener { public ButtonHandler? Handler { get; set; } @@ -213,7 +206,7 @@ public void OnClick(AView? v) } } - class ButtonTouchListener : Java.Lang.Object, AView.IOnTouchListener + public class ButtonTouchListener : Java.Lang.Object, AView.IOnTouchListener { public ButtonHandler? Handler { get; set; } diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Standard.cs b/src/Core/src/Handlers/Button/ButtonHandler.Standard.cs index 4d0f2c2d63eb..f1159458ffce 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Standard.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Standard.cs @@ -6,11 +6,15 @@ public partial class ButtonHandler : ViewHandler { protected override object CreateNativeView() => throw new NotImplementedException(); - public static void MapText(ButtonHandler handler, IButton button) { } - public static void MapTextColor(ButtonHandler handler, IButton button) { } - public static void MapCharacterSpacing(ButtonHandler handler, IButton button) { } - public static void MapFont(ButtonHandler handler, IButton button) { } - public static void MapPadding(ButtonHandler handler, IButton button) { } - public static void MapImageSource(ButtonHandler handler, IButton image) { } + public static void MapText(IButtonHandler handler, IText button) { } + public static void MapTextColor(IButtonHandler handler, ITextStyle button) { } + public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { } + public static void MapFont(IButtonHandler handler, ITextStyle button) { } + public static void MapPadding(IButtonHandler handler, IButton button) { } + public static void MapImageSource(IButtonHandler handler, IButton image) { } + void OnSetImageSource(object? obj) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs b/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs index 9fa028dbeff8..de6262fd29c7 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs @@ -1,5 +1,7 @@ #nullable enable +using System.Threading.Tasks; using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; namespace Microsoft.Maui.Handlers { @@ -42,39 +44,54 @@ protected override void DisconnectHandler(MauiButton nativeView) } // This is a Windows-specific mapping - public static void MapBackground(ButtonHandler handler, IButton button) + public static void MapBackground(IButtonHandler handler, IButton button) { - handler.NativeView?.UpdateBackground(button, DefaultBackground); + handler.TypedNativeView?.UpdateBackground(button, DefaultBackground); } - public static void MapText(ButtonHandler handler, IButton button) + public static void MapText(IButtonHandler handler, IText button) { - handler.NativeView?.UpdateText(button); + handler.TypedNativeView?.UpdateText(button); } - public static void MapTextColor(ButtonHandler handler, IButton button) + public static void MapTextColor(IButtonHandler handler, ITextStyle button) { - handler.NativeView?.UpdateTextColor(button, DefaultForeground); + handler.TypedNativeView?.UpdateTextColor(button, DefaultForeground); } - public static void MapCharacterSpacing(ButtonHandler handler, IButton button) + public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { - handler.NativeView?.UpdateCharacterSpacing(button.CharacterSpacing); + handler.TypedNativeView?.UpdateCharacterSpacing(button.CharacterSpacing); } - public static void MapFont(ButtonHandler handler, IButton button) + public static void MapFont(IButtonHandler handler, ITextStyle button) { var fontManager = handler.GetRequiredService(); - handler.NativeView?.UpdateFont(button, fontManager); + handler.TypedNativeView?.UpdateFont(button, fontManager); } - public static void MapPadding(ButtonHandler handler, IButton button) + public static void MapPadding(IButtonHandler handler, IButton button) { - handler.NativeView?.UpdatePadding(button, DefaultPadding); + handler.TypedNativeView?.UpdatePadding(button, DefaultPadding); } - public static void MapImageSource(ButtonHandler handler, IButton image) { } + public static void MapImageSource(IButtonHandler handler, IButton image) => + MapImageSourceAsync(handler, image).FireAndForget(handler); + + public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) + { + if (image.ImageSource == null) + { + return Task.CompletedTask; + } + + return handler.ImageSourceLoader.UpdateImageSourceAsync(); + } + + void OnSetImageSource(ImageSource? obj) + { + } void OnClick(object sender, UI.Xaml.RoutedEventArgs e) { diff --git a/src/Core/src/Handlers/Button/ButtonHandler.cs b/src/Core/src/Handlers/Button/ButtonHandler.cs index 776ae55a1917..1d07902a83b3 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.cs @@ -1,28 +1,55 @@ -#nullable enable +#if __IOS__ || MACCATALYST +using NativeView = UIKit.UIButton; +#elif MONOANDROID +using NativeView = Google.Android.Material.Button.MaterialButton; +#elif WINDOWS +using NativeView = Microsoft.Maui.MauiButton; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeView = System.Object; +#endif + namespace Microsoft.Maui.Handlers { - public partial class ButtonHandler + public partial class ButtonHandler : IButtonHandler { - readonly ImageSourceServiceResultManager _sourceManager = new ImageSourceServiceResultManager(); + ImageSourcePartLoader? _imageSourcePartLoader; + public ImageSourcePartLoader ImageSourceLoader => + _imageSourcePartLoader ??= new ImageSourcePartLoader(this, + () => VirtualView.ImageSource, + () => false, + (isLoading) => (VirtualView as IImage)?.UpdateIsLoading(isLoading), + OnSetImageSource); - public static IPropertyMapper ButtonMapper = new PropertyMapper(ViewHandler.ViewMapper) + public static IPropertyMapper TextStyleMapper = new PropertyMapper(ViewHandler.ViewMapper) + { + [nameof(ITextStyle.CharacterSpacing)] = MapCharacterSpacing, + [nameof(ITextStyle.Font)] = MapFont, + [nameof(ITextStyle.TextColor)] = MapTextColor, + }; + + public static IPropertyMapper TextMapper = new PropertyMapper(TextStyleMapper) + { + [nameof(IText.Text)] = MapText, + }; + + public static IPropertyMapper Mapper = new PropertyMapper(TextMapper) { [nameof(IButton.Background)] = MapBackground, - [nameof(IButton.CharacterSpacing)] = MapCharacterSpacing, - [nameof(IButton.Font)] = MapFont, [nameof(IButton.Padding)] = MapPadding, - [nameof(IButton.Text)] = MapText, - [nameof(IButton.TextColor)] = MapTextColor, [nameof(IButton.ImageSource)] = MapImageSource }; - public ButtonHandler() : base(ButtonMapper) + public ButtonHandler() : base(Mapper) { } - public ButtonHandler(IPropertyMapper? mapper = null) : base(mapper ?? ButtonMapper) + public ButtonHandler(IPropertyMapper? mapper = null) : base(mapper ?? Mapper) { } + + IButton IButtonHandler.TypedVirtualView => VirtualView; + + NativeView IButtonHandler.TypedNativeView => NativeView; } } diff --git a/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs b/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs index 7273c0d64e46..1cf466d4dd56 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs @@ -14,10 +14,10 @@ public partial class ButtonHandler : ViewHandler static UIColor? ButtonTextColorDefaultDisabled; static UIColor? ButtonTextColorDefaultHighlighted; static UIColor? ButtonTextColorDefaultNormal; - ImageSourcePartWrapper? _imageSourcePartWrapper; - ImageSourcePartWrapper ImageSourcePartWrapper => - _imageSourcePartWrapper ??= new ImageSourcePartWrapper( - this, (h) => h.VirtualView.ImageSource, null, null, OnSetImageSourceDrawable); + //ImageSourcePartWrapper? _imageSourcePartWrapper; + //ImageSourcePartWrapper ImageSourcePartWrapper => + // _imageSourcePartWrapper ??= new ImageSourcePartWrapper( + // this, (h) => h.VirtualView.ImageSource, null, null, OnSetImageSourceDrawable); protected override UIButton CreateNativeView() { @@ -50,68 +50,67 @@ void SetupDefaults(UIButton nativeView) ButtonTextColorDefaultDisabled = nativeView.TitleColor(UIControlState.Disabled); } - private void OnSetImageSourceDrawable(UIImage? image) + public static void MapText(IButtonHandler handler, IText button) { - if (image != null) - { - NativeView.SetImage(image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal); - } - else - { - NativeView.SetImage(null, UIControlState.Normal); - } - - VirtualView.ImageSourceLoaded(); - } - - public static void MapText(ButtonHandler handler, IButton button) - { - handler.NativeView?.UpdateText(button); + handler.TypedNativeView?.UpdateText(button); // Any text update requires that we update any attributed string formatting MapFormatting(handler, button); } - public static void MapTextColor(ButtonHandler handler, IButton button) + public static void MapTextColor(IButtonHandler handler, ITextStyle button) { - handler.NativeView?.UpdateTextColor(button, ButtonTextColorDefaultNormal, ButtonTextColorDefaultHighlighted, ButtonTextColorDefaultDisabled); + handler.TypedNativeView?.UpdateTextColor(button, ButtonTextColorDefaultNormal, ButtonTextColorDefaultHighlighted, ButtonTextColorDefaultDisabled); } - public static void MapCharacterSpacing(ButtonHandler handler, IButton button) + public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { - handler.NativeView?.UpdateCharacterSpacing(button); + handler.TypedNativeView?.UpdateCharacterSpacing(button); } - public static void MapPadding(ButtonHandler handler, IButton button) + public static void MapPadding(IButtonHandler handler, IButton button) { - handler.NativeView?.UpdatePadding(button); + handler.TypedNativeView?.UpdatePadding(button); } - public static void MapFont(ButtonHandler handler, IButton button) + public static void MapFont(IButtonHandler handler, ITextStyle button) { var fontManager = handler.GetRequiredService(); - handler.NativeView?.UpdateFont(button, fontManager); + handler.TypedNativeView?.UpdateFont(button, fontManager); } - public static void MapFormatting(ButtonHandler handler, IButton button) + public static void MapFormatting(IButtonHandler handler, IText button) { // Update all of the attributed text formatting properties - handler.NativeView?.UpdateCharacterSpacing(button); + handler.TypedNativeView?.UpdateCharacterSpacing(button); + } + + void OnSetImageSource(UIImage? image) + { + if (image != null) + { + NativeView.SetImage(image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal); + } + else + { + NativeView.SetImage(null, UIControlState.Normal); + } + + VirtualView.ImageSourceLoaded(); } - public static void MapImageSource(ButtonHandler handler, IButton image) => + public static void MapImageSource(IButtonHandler handler, IButton image) => MapImageSourceAsync(handler, image).FireAndForget(handler); - public static Task MapImageSourceAsync(ButtonHandler handler, IButton image) + public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) { if (image.ImageSource == null) { - handler.OnSetImageSourceDrawable(null); return Task.CompletedTask; } - return handler.ImageSourcePartWrapper.UpdateImageSource(); + return handler.ImageSourceLoader.UpdateImageSourceAsync(); } static void SetControlPropertiesFromProxy(UIButton nativeView) diff --git a/src/Core/src/Handlers/Button/IButtonHandler.cs b/src/Core/src/Handlers/Button/IButtonHandler.cs new file mode 100644 index 000000000000..9e8ce2743c06 --- /dev/null +++ b/src/Core/src/Handlers/Button/IButtonHandler.cs @@ -0,0 +1,27 @@ +#if __IOS__ || MACCATALYST +using NativeView = UIKit.UIButton; +#elif MONOANDROID +using NativeView = Google.Android.Material.Button.MaterialButton; +#elif WINDOWS +using NativeView = Microsoft.Maui.MauiButton; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeView = System.Object; +#endif + +namespace Microsoft.Maui.Handlers +{ + public partial interface IButtonHandler : IViewHandler + { + IButton TypedVirtualView { get; } + NativeView TypedNativeView { get; } + ImageSourcePartLoader ImageSourceLoader { get; } + + +#if __ANDROID__ + // These are a little odd here but Android doesn't let you retrieve these from a control + ButtonHandler.ButtonClickListener ClickListener { get; } + ButtonHandler.ButtonTouchListener TouchListener { get; } +#endif + + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/IImageHandler.cs b/src/Core/src/Handlers/Image/IImageHandler.cs new file mode 100644 index 000000000000..41da517406f0 --- /dev/null +++ b/src/Core/src/Handlers/Image/IImageHandler.cs @@ -0,0 +1,19 @@ +#if __IOS__ || MACCATALYST +using NativeView = UIKit.UIImageView; +#elif MONOANDROID +using NativeView = Android.Widget.ImageView; +#elif WINDOWS +using NativeView = Microsoft.UI.Xaml.Controls.Image; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeView = System.Object; +#endif + +namespace Microsoft.Maui.Handlers +{ + public partial interface IImageHandler : IViewHandler + { + IImage TypedVirtualView { get; } + ImageSourcePartLoader SourceLoader { get; } + NativeView TypedNativeView { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.Android.cs b/src/Core/src/Handlers/Image/ImageHandler.Android.cs index f057fa779cbd..8018dfd63e78 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Android.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Android.cs @@ -1,52 +1,54 @@ #nullable enable using System.Threading.Tasks; +using Android.Graphics.Drawables; using Android.Widget; using AndroidX.AppCompat.Widget; namespace Microsoft.Maui.Handlers { - public partial class ImageHandler : ViewHandler + public partial interface IImageHandler : IViewHandler { - protected override ImageView CreateNativeView() => new AppCompatImageView(Context); - - protected override void DisconnectHandler(ImageView nativeView) - { - base.DisconnectHandler(nativeView); - - _sourceManager.Reset(); - } - - public override bool NeedsContainer => - VirtualView?.Background != null || - base.NeedsContainer; + } - public static void MapBackground(ImageHandler handler, IImage image) + public partial class ImageHandler : ViewHandler + { + public static void MapBackground(IImageHandler handler, IImage image) { handler.UpdateValue(nameof(IViewHandler.ContainerView)); handler.GetWrappedNativeView()?.UpdateBackground(image); } - public static void MapAspect(ImageHandler handler, IImage image) => - handler.NativeView?.UpdateAspect(image); + public static void MapAspect(IImageHandler handler, IImage image) => + handler.TypedNativeView?.UpdateAspect(image); - public static void MapIsAnimationPlaying(ImageHandler handler, IImage image) => - handler.NativeView?.UpdateIsAnimationPlaying(image); + public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) => + handler.TypedNativeView?.UpdateIsAnimationPlaying(image); - public static void MapSource(ImageHandler handler, IImage image) => + public static void MapSource(IImageHandler handler, IImage image) => MapSourceAsync(handler, image).FireAndForget(handler); - public static async Task MapSourceAsync(ImageHandler handler, IImage image) + public static Task MapSourceAsync(IImageHandler handler, IImage image) { - if (handler.NativeView == null) - return; + handler.TypedNativeView.Clear(); + return handler.SourceLoader.UpdateImageSourceAsync(); + } - var token = handler._sourceManager.BeginLoad(); + void OnSetImageSource(Drawable? obj) + { + NativeView.SetImageDrawable(obj); + } - var provider = handler.GetRequiredService(); - var result = await handler.NativeView.UpdateSourceAsync(image, provider, token); + protected override ImageView CreateNativeView() => new AppCompatImageView(Context); - handler._sourceManager.CompleteLoad(result); + protected override void DisconnectHandler(ImageView nativeView) + { + base.DisconnectHandler(nativeView); + SourceLoader.Reset(); } + + public override bool NeedsContainer => + VirtualView?.Background != null || + base.NeedsContainer; } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.Standard.cs b/src/Core/src/Handlers/Image/ImageHandler.Standard.cs index 61d6cfb9cf39..d3455ebb769f 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Standard.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Standard.cs @@ -1,14 +1,17 @@ -#nullable enable -using System; +using System; namespace Microsoft.Maui.Handlers { public partial class ImageHandler : ViewHandler { protected override object CreateNativeView() => throw new NotImplementedException(); - - public static void MapAspect(ImageHandler handler, IImage image) { } - public static void MapIsAnimationPlaying(ImageHandler handler, IImage image) { } - public static void MapSource(ImageHandler handler, IImage image) { } + public static void MapAspect(IImageHandler handler, IImage image) { } + public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) { } + public static void MapSource(IImageHandler handler, IImage image) { } + + void OnSetImageSource(object? obj) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.Windows.cs b/src/Core/src/Handlers/Image/ImageHandler.Windows.cs index c7e6939f4a97..b9e884adffd4 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Windows.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Windows.cs @@ -1,21 +1,19 @@ -#nullable enable -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using WImage = Microsoft.UI.Xaml.Controls.Image; namespace Microsoft.Maui.Handlers { public partial class ImageHandler : ViewHandler { - double _lastScale = 0.0; - protected override Image CreateNativeView() => new Image(); protected override void ConnectHandler(Image nativeView) { base.ConnectHandler(nativeView); - _lastScale = 0.0; nativeView.Loaded += OnNativeViewLoaded; nativeView.Unloaded += OnNativeViewUnloaded; } @@ -27,51 +25,50 @@ protected override void DisconnectHandler(Image nativeView) if (nativeView.XamlRoot != null) nativeView.XamlRoot.Changed -= OnXamlRootChanged; - _lastScale = 0.0; nativeView.Loaded -= OnNativeViewLoaded; nativeView.Unloaded -= OnNativeViewUnloaded; - _sourceManager.Reset(); + SourceLoader.Reset(); } public override bool NeedsContainer => VirtualView?.Background != null || base.NeedsContainer; - public static void MapBackground(ImageHandler handler, IImage image) + public static void MapBackground(IImageHandler handler, IImage image) { handler.UpdateValue(nameof(IViewHandler.ContainerView)); handler.GetWrappedNativeView()?.UpdateBackground(image); } - public static void MapAspect(ImageHandler handler, IImage image) => - handler.NativeView?.UpdateAspect(image); + public static void MapAspect(IImageHandler handler, IImage image) => + handler.TypedNativeView?.UpdateAspect(image); - public static void MapIsAnimationPlaying(ImageHandler handler, IImage image) => - handler.NativeView?.UpdateIsAnimationPlaying(image); + public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) => + handler.TypedNativeView?.UpdateIsAnimationPlaying(image); - public static void MapSource(ImageHandler handler, IImage image) => + public static void MapSource(IImageHandler handler, IImage image) => MapSourceAsync(handler, image).FireAndForget(handler); - public static async Task MapSourceAsync(ImageHandler handler, IImage image) + public static Task MapSourceAsync(IImageHandler handler, IImage image) { if (handler.NativeView == null) - return; - - var token = handler._sourceManager.BeginLoad(); + return Task.CompletedTask; - var provider = handler.GetRequiredService(); - var result = await handler.NativeView.UpdateSourceAsync(image, provider, token); + handler.TypedNativeView.Clear(); + return handler.SourceLoader.UpdateImageSourceAsync(); + } - handler._sourceManager.CompleteLoad(result); + void OnSetImageSource(ImageSource? obj) + { + NativeView.UpdateSource(obj, VirtualView); } void OnNativeViewLoaded(object sender = null!, RoutedEventArgs e = null!) { if (NativeView?.XamlRoot != null) { - _lastScale = NativeView.XamlRoot.RasterizationScale; NativeView.XamlRoot.Changed += OnXamlRootChanged; } } @@ -84,13 +81,7 @@ void OnNativeViewUnloaded(object sender = null!, RoutedEventArgs e = null!) void OnXamlRootChanged(XamlRoot sender, XamlRootChangedEventArgs args) { - if (_lastScale == sender.RasterizationScale) - return; - - _lastScale = sender.RasterizationScale; - - if (_sourceManager.IsResolutionDependent) - UpdateValue(nameof(IImage.Source)); + UpdateValue(nameof(IImage.Source)); } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.cs b/src/Core/src/Handlers/Image/ImageHandler.cs index c9bd9209e0db..85435b2139ba 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.cs @@ -1,27 +1,53 @@ -#nullable enable -using System; +using System; using System.Threading; +#if __IOS__ || MACCATALYST +using NativeView = UIKit.UIImageView; +#elif MONOANDROID +using NativeView = Android.Widget.ImageView; +#elif WINDOWS +using NativeView = Microsoft.UI.Xaml.Controls.Image; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeView = System.Object; +#endif namespace Microsoft.Maui.Handlers { - public partial class ImageHandler + public partial class ImageHandler : IImageHandler { - readonly ImageSourceServiceResultManager _sourceManager = new ImageSourceServiceResultManager(); - - public static IPropertyMapper ImageMapper = new PropertyMapper(ViewHandler.ViewMapper) + public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) { +#if __ANDROID__ [nameof(IImage.Background)] = MapBackground, +#endif [nameof(IImage.Aspect)] = MapAspect, [nameof(IImage.IsAnimationPlaying)] = MapIsAnimationPlaying, [nameof(IImage.Source)] = MapSource, }; - public ImageHandler() : base(ImageMapper) + public new static CommandMapper CommandMapper = new(ViewHandler.ViewCommandMapper) + { + }; + + ImageSourcePartLoader? _imageSourcePartLoader; + public ImageSourcePartLoader SourceLoader => + _imageSourcePartLoader ??= new ImageSourcePartLoader(this, + () => VirtualView.Source, + () => VirtualView.IsAnimationPlaying, + (isLoading) => (VirtualView as IImage)?.UpdateIsLoading(isLoading), + OnSetImageSource); + + public ImageHandler() : base(Mapper) { } - public ImageHandler(IPropertyMapper mapper) : base(mapper ?? ImageMapper) + public ImageHandler(IPropertyMapper mapper) : base(mapper ?? Mapper) { } + + + // TODO MAUI: Should we remove all shadowing? + IImage IImageHandler.TypedVirtualView => VirtualView; + + NativeView IImageHandler.TypedNativeView => NativeView; } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.iOS.cs b/src/Core/src/Handlers/Image/ImageHandler.iOS.cs index 54aadd99ac29..c7e941b8a19b 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.iOS.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.iOS.cs @@ -25,46 +25,46 @@ protected override void DisconnectHandler(UIImageView nativeView) if (NativeView is MauiImageView imageView) imageView.WindowChanged -= OnWindowChanged; - _sourceManager.Reset(); + SourceLoader.Reset(); } public override bool NeedsContainer => VirtualView?.Background != null || base.NeedsContainer; - public static void MapBackground(ImageHandler handler, IImage image) + public static void MapBackground(IImageHandler handler, IImage image) { handler.UpdateValue(nameof(IViewHandler.ContainerView)); handler.GetWrappedNativeView()?.UpdateBackground(image); } - public static void MapAspect(ImageHandler handler, IImage image) => - handler.NativeView?.UpdateAspect(image); + public static void MapAspect(IImageHandler handler, IImage image) => + handler.TypedNativeView?.UpdateAspect(image); - public static void MapIsAnimationPlaying(ImageHandler handler, IImage image) => - handler.NativeView?.UpdateIsAnimationPlaying(image); + public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) => + handler.TypedNativeView?.UpdateIsAnimationPlaying(image); - public static void MapSource(ImageHandler handler, IImage image) => + public static void MapSource(IImageHandler handler, IImage image) => MapSourceAsync(handler, image).FireAndForget(handler); - public static async Task MapSourceAsync(ImageHandler handler, IImage image) + public static Task MapSourceAsync(IImageHandler handler, IImage image) { if (handler.NativeView == null) - return; + return Task.CompletedTask; - var token = handler._sourceManager.BeginLoad(); - - var provider = handler.GetRequiredService(); - var result = await handler.NativeView.UpdateSourceAsync(image, provider, token); + handler.TypedNativeView.Clear(); + return handler.SourceLoader.UpdateImageSourceAsync(); + } - handler._sourceManager.CompleteLoad(result); + void OnSetImageSource(UIImage? obj) + { + NativeView.UpdateSource(obj, VirtualView); } void OnWindowChanged(object? sender, EventArgs e) { - if (_sourceManager.IsResolutionDependent) - UpdateValue(nameof(IImage.Source)); + UpdateValue(nameof(IImage.Source)); } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs new file mode 100644 index 000000000000..decfa16c1c5b --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs @@ -0,0 +1,23 @@ +//using System; +//using System.Collections.Generic; +//using System.Text; +//using Android.Views; +//using Android.Widget; +//using AndroidX.AppCompat.Widget; + +//namespace Microsoft.Maui.Handlers +//{ +// public partial class ImageButtonHandler : ViewHandler, IImageButtonHandler +// { +// ImageView IImageHandler.NativeView => this.NativeView; + +// ButtonHandler.ButtonClickListener IButtonHandler.ClickListener { get; } = new ButtonHandler.ButtonClickListener(); + +// ButtonHandler.ButtonTouchListener IButtonHandler.TouchListener { get; } = new ButtonHandler.ButtonTouchListener(); + +// protected override AppCompatImageButton CreateNativeView() +// { +// return new AppCompatImageButton(Context); +// } +// } +//} diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs new file mode 100644 index 000000000000..44410230fb73 --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs @@ -0,0 +1,13 @@ +//using System; + +//namespace Microsoft.Maui.Handlers +//{ +// public static partial class ImageButtonMapper +// { +// } + +// public sealed partial class ImageButtonHandler : ViewHandler +// { +// protected override object CreateNativeView() => throw new NotImplementedException(); +// } +//} \ No newline at end of file diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs new file mode 100644 index 000000000000..f8c13afea948 --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs @@ -0,0 +1,40 @@ +//using System; +//using System.Collections.Generic; +//using System.Text; + +//namespace Microsoft.Maui.Handlers +//{ +// public partial interface IImageButtonHandler : IViewHandler, IButtonHandler, IImageHandler +// { +// public new IImageButton VirtualView { get; } +// } + +// public static partial class ImageButtonMapper +// { +// public static IPropertyMapper Mapper = +// new PropertyMapper(ViewHandler.ViewMapper, ButtonMapper.Mapper, ImageMapper.Mapper) +// { +// }; + +// public static CommandMapper ImageButtonCommandMapper = new(ButtonMapper.CommandMapper) +// { +// }; +// } + +// public partial class ImageButtonHandler : IImageButtonHandler +// { +// IButton IButtonHandler.VirtualView => this.VirtualView; + +// IImage IImageHandler.VirtualView => this.VirtualView; + +// ImageSourceServiceResultManager IImageHandler.SourceManager { get; } = new ImageSourceServiceResultManager(); + +// public ImageButtonHandler() : base(ImageMapper.Mapper) +// { +// } + +// public ImageButtonHandler(IPropertyMapper mapper) : base(mapper ?? ImageButtonMapper.Mapper) +// { +// } +// } +//} diff --git a/src/Core/src/ImageSources/ImageSourceServiceResultManager.cs b/src/Core/src/ImageSources/ImageSourceServiceResultManager.cs index b69fd9e6b23d..c481d9f0b88b 100644 --- a/src/Core/src/ImageSources/ImageSourceServiceResultManager.cs +++ b/src/Core/src/ImageSources/ImageSourceServiceResultManager.cs @@ -4,7 +4,7 @@ namespace Microsoft.Maui.Handlers { - class ImageSourceServiceResultManager + public class ImageSourceServiceResultManager { CancellationTokenSource? _sourceCancellation; IDisposable? _sourceResult; diff --git a/src/Core/src/Platform/Android/ButtonExtensions.cs b/src/Core/src/Platform/Android/ButtonExtensions.cs index 85de66189c55..ba8540de3631 100644 --- a/src/Core/src/Platform/Android/ButtonExtensions.cs +++ b/src/Core/src/Platform/Android/ButtonExtensions.cs @@ -10,9 +10,6 @@ namespace Microsoft.Maui { public static class ButtonExtensions { - public static void UpdateText(this AppCompatButton appCompatButton, IButton button) => - appCompatButton.Text = button.Text; - public static void UpdatePadding(this AppCompatButton appCompatButton, IButton button, Thickness? defaultPadding = null) { var context = appCompatButton.Context; diff --git a/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs index acd904c1601f..4ecfc218bc00 100644 --- a/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs @@ -8,25 +8,20 @@ namespace Microsoft.Maui { - internal partial class ImageSourcePartWrapper : IImageSourcePart - where T : ElementHandler + public partial class ImageSourcePartLoader : IImageSourcePart { Action? SetImage { get; } View? NativeView => Handler.NativeView as View; - public ImageSourcePartWrapper( - T handler, - Func getSource, - Func? getIsAnimationPlaying, + public ImageSourcePartLoader( + IElementHandler handler, + Func getSource, + Func? getIsAnimationPlaying, Action? setIsLoading, - Action setDrawable) + Action setDrawable) : this(handler, getSource, getIsAnimationPlaying, setIsLoading) { - GetSource = getSource; - GetIsAnimationPlaying = getIsAnimationPlaying; - SetIsLoading = setIsLoading; SetImage = setDrawable; - Handler = handler; } } } diff --git a/src/Core/src/Platform/Android/ImageViewExtensions.cs b/src/Core/src/Platform/Android/ImageViewExtensions.cs index d9a32ad7d596..06b748e62b9a 100644 --- a/src/Core/src/Platform/Android/ImageViewExtensions.cs +++ b/src/Core/src/Platform/Android/ImageViewExtensions.cs @@ -45,16 +45,6 @@ public static void UpdateIsAnimationPlaying(this Drawable? drawable, IImageSourc } } - public static Task?> UpdateSourceAsync( - this ImageView imageView, - IImageSourcePart image, - IImageSourceServiceProvider services, - CancellationToken cancellationToken = default) - { - imageView.Clear(); - return image.UpdateSourceAsync(imageView, services, (d) => imageView.SetImageDrawable(d), cancellationToken); - } - internal static async Task?> UpdateSourceAsync( this IImageSourcePart image, View destinationContext, diff --git a/src/Core/src/Platform/Android/TextViewExtensions.cs b/src/Core/src/Platform/Android/TextViewExtensions.cs index c46ed74be453..578208a10a56 100644 --- a/src/Core/src/Platform/Android/TextViewExtensions.cs +++ b/src/Core/src/Platform/Android/TextViewExtensions.cs @@ -11,7 +11,7 @@ namespace Microsoft.Maui { public static class TextViewExtensions { - public static void UpdateTextPlainText(this TextView textView, ILabel label) + public static void UpdateTextPlainText(this TextView textView, IText label) { textView.Text = label.Text; } diff --git a/src/Core/src/Platform/ElementHandlerExtensions.cs b/src/Core/src/Platform/ElementHandlerExtensions.cs index a047507ad17c..351e639a5614 100644 --- a/src/Core/src/Platform/ElementHandlerExtensions.cs +++ b/src/Core/src/Platform/ElementHandlerExtensions.cs @@ -8,7 +8,7 @@ namespace Microsoft.Maui { static class ElementHandlerExtensions { - public static IServiceProvider GetServiceProvider(this ElementHandler handler) + public static IServiceProvider GetServiceProvider(this IElementHandler handler) { var context = handler.MauiContext ?? throw new InvalidOperationException($"Unable to find the context. The {nameof(ElementHandler.MauiContext)} property should have been set by the host."); @@ -19,7 +19,7 @@ public static IServiceProvider GetServiceProvider(this ElementHandler handler) return services; } - public static T? GetService(this ElementHandler handler, Type type) + public static T? GetService(this IElementHandler handler, Type type) { var services = handler.GetServiceProvider(); @@ -28,7 +28,7 @@ public static IServiceProvider GetServiceProvider(this ElementHandler handler) return (T?)service; } - public static T? GetService(this ElementHandler handler) + public static T? GetService(this IElementHandler handler) { var services = handler.GetServiceProvider(); @@ -37,7 +37,7 @@ public static IServiceProvider GetServiceProvider(this ElementHandler handler) return service; } - public static T GetRequiredService(this ElementHandler handler, Type type) + public static T GetRequiredService(this IElementHandler handler, Type type) where T : notnull { var services = handler.GetServiceProvider(); @@ -47,7 +47,7 @@ public static T GetRequiredService(this ElementHandler handler, Type type) return (T)service; } - public static T GetRequiredService(this ElementHandler handler) + public static T GetRequiredService(this IElementHandler handler) where T : notnull { var services = handler.GetServiceProvider(); diff --git a/src/Core/src/Platform/ImageSourcePartWrapper.cs b/src/Core/src/Platform/ImageSourcePartWrapper.cs index 61da87d7ff25..2170469e5381 100644 --- a/src/Core/src/Platform/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/ImageSourcePartWrapper.cs @@ -6,40 +6,41 @@ namespace Microsoft.Maui { - internal partial class ImageSourcePartWrapper : IImageSourcePart - where T : ElementHandler + public partial class ImageSourcePartLoader : IImageSourcePart { public ImageSourceServiceResultManager SourceManager { get; } = new ImageSourceServiceResultManager(); - Func? GetSource { get; } + Func? GetSource { get; } - Func? GetIsAnimationPlaying { get; } + Func? GetIsAnimationPlaying { get; } Action? SetIsLoading { get; } - T Handler { get; } + IElementHandler Handler { get; } - private ImageSourcePartWrapper( - T handler, - Func getSource, - Func? getIsAnimationPlaying, + internal ImageSourcePartLoader( + IElementHandler handler, + Func getSource, + Func? getIsAnimationPlaying, Action? setIsLoading) { - GetSource = getSource; - GetIsAnimationPlaying = getIsAnimationPlaying; - SetIsLoading = setIsLoading; Handler = handler; } - public IImageSource? Source => GetSource?.Invoke(Handler); + public void Reset() + { + SourceManager.Reset(); + } + + IImageSource? IImageSourcePart.Source => GetSource?.Invoke(); - public bool IsAnimationPlaying => GetIsAnimationPlaying?.Invoke(Handler) ?? false; + bool IImageSourcePart.IsAnimationPlaying => GetIsAnimationPlaying?.Invoke() ?? false; - public void UpdateIsLoading(bool isLoading) => SetIsLoading?.Invoke(isLoading); + void IImageSourcePart.UpdateIsLoading(bool isLoading) => SetIsLoading?.Invoke(isLoading); - public async Task UpdateImageSource() + public async Task UpdateImageSourceAsync() { -#if __IOS__ || __ANDROID__ +#if __IOS__ || __ANDROID__ || WINDOWS if (NativeView != null) { var token = this.SourceManager.BeginLoad(); diff --git a/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs new file mode 100644 index 000000000000..8d4421226d2f --- /dev/null +++ b/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui +{ + public partial class ImageSourcePartLoader + { + public ImageSourcePartLoader( + IElementHandler handler, + Func getSource, + Func? getIsAnimationPlaying, + Action? setIsLoading, + Action setImage) + : this(handler, getSource, getIsAnimationPlaying, setIsLoading) + { + } + } +} diff --git a/src/Core/src/Platform/Windows/ButtonExtensions.cs b/src/Core/src/Platform/Windows/ButtonExtensions.cs index 5cb046b06537..3988863763c1 100644 --- a/src/Core/src/Platform/Windows/ButtonExtensions.cs +++ b/src/Core/src/Platform/Windows/ButtonExtensions.cs @@ -3,22 +3,13 @@ namespace Microsoft.Maui { public static class ButtonExtensions { - public static void UpdateBackground(this MauiButton nativeButton, IButton button, UI.Xaml.Media.Brush? defaultBrush = null) => - nativeButton.UpdateBackground(button.Background, defaultBrush); - - public static void UpdateText(this MauiButton nativeButton, IButton button) => + public static void UpdateText(this MauiButton nativeButton, IText button) => nativeButton.Content = button.Text; - public static void UpdateTextColor(this MauiButton nativeButton, IButton button, UI.Xaml.Media.Brush? defaultBrush = null) => + public static void UpdateTextColor(this MauiButton nativeButton, ITextStyle button, UI.Xaml.Media.Brush? defaultBrush = null) => nativeButton.UpdateForegroundColor(button.TextColor, defaultBrush); - public static void UpdateCharacterSpacing(this MauiButton nativeButton, IButton button) => + public static void UpdateCharacterSpacing(this MauiButton nativeButton, ITextStyle button) => nativeButton.UpdateCharacterSpacing((int)button.CharacterSpacing); - - public static void UpdatePadding(this MauiButton nativeButton, IButton button, UI.Xaml.Thickness? defaultThickness = null) => - nativeButton.UpdatePadding(button.Padding, defaultThickness); - - public static void UpdateFont(this MauiButton nativeButton, IButton button, IFontManager fontManager) => - nativeButton.UpdateFont(button.Font, fontManager); } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/ControlExtensions.cs b/src/Core/src/Platform/Windows/ControlExtensions.cs index e75f4cd4edb8..3d8f65c54ce0 100644 --- a/src/Core/src/Platform/Windows/ControlExtensions.cs +++ b/src/Core/src/Platform/Windows/ControlExtensions.cs @@ -6,6 +6,9 @@ namespace Microsoft.Maui { public static class ControlExtensions { + public static void UpdateFont(this Control nativeButton, ITextStyle textStyle, IFontManager fontManager) => + nativeButton.UpdateFont(textStyle.Font, fontManager); + public static void UpdateFont(this Control nativeControl, Font font, IFontManager fontManager) { nativeControl.FontSize = fontManager.GetFontSize(font); @@ -18,6 +21,9 @@ public static void UpdateFont(this Control nativeControl, Font font, IFontManage public static void UpdateIsEnabled(this Control nativeControl, bool isEnabled) => nativeControl.IsEnabled = isEnabled; + public static void UpdateBackground(this Control nativeControl, IView view, UI.Xaml.Media.Brush? defaultBrush = null) => + nativeControl.UpdateBackground(view.Background, defaultBrush); + public static void UpdateBackground(this Control nativeControl, Paint? paint, UI.Xaml.Media.Brush? defaultBrush = null) => nativeControl.UpdateProperty(Control.BackgroundProperty, paint.IsNullOrEmpty() ? defaultBrush : paint?.ToNative()); @@ -30,6 +36,9 @@ public static void UpdateBackground(this Panel nativeControl, Paint? paint, UI.X public static void UpdateForegroundColor(this Control nativeControl, Color color, UI.Xaml.Media.Brush? defaultBrush = null) => nativeControl.Foreground = color?.ToNative() ?? defaultBrush ?? nativeControl.Foreground; + public static void UpdatePadding(this Control nativeControl, IPadding padding, UI.Xaml.Thickness? defaultThickness = null) => + nativeControl.UpdatePadding(padding.Padding, defaultThickness); + public static void UpdatePadding(this Control nativeControl, Thickness padding, UI.Xaml.Thickness? defaultThickness = null) { // TODO: have a way to reset the padding diff --git a/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs new file mode 100644 index 000000000000..fa449887368b --- /dev/null +++ b/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Handlers; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; + +namespace Microsoft.Maui +{ + public partial class ImageSourcePartLoader + { + Action? SetImage { get; } + + FrameworkElement? NativeView => Handler.NativeView as FrameworkElement; + + public ImageSourcePartLoader( + IElementHandler handler, + Func getSource, + Func? getIsAnimationPlaying, + Action? setIsLoading, + Action setImage) + : this(handler, getSource, getIsAnimationPlaying, setIsLoading) + { + SetImage = setImage; + } + } +} diff --git a/src/Core/src/Platform/Windows/ImageViewExtensions.cs b/src/Core/src/Platform/Windows/ImageViewExtensions.cs index b570de087e39..50019f7e1386 100644 --- a/src/Core/src/Platform/Windows/ImageViewExtensions.cs +++ b/src/Core/src/Platform/Windows/ImageViewExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media.Imaging; using Windows.Foundation.Metadata; using WImage = Microsoft.UI.Xaml.Controls.Image; @@ -54,10 +55,19 @@ public static void UpdateIsAnimationPlaying(this WImage imageView, IImageSourceP } } - public static async Task?> UpdateSourceAsync(this WImage imageView, IImageSourcePart image, IImageSourceServiceProvider services, CancellationToken cancellationToken = default) + public static void UpdateSource(this WImage imageView, WImageSource? uIImage, IImageSourcePart image) { - imageView.Clear(); + imageView.Source = uIImage; + imageView.UpdateIsAnimationPlaying(image); + } + public static async Task?> UpdateSourceAsync( + this IImageSourcePart image, + FrameworkElement destinationContext, + IImageSourceServiceProvider services, + Action setImage, + CancellationToken cancellationToken = default) + { image.UpdateIsLoading(false); var imageSource = image.Source; @@ -73,7 +83,7 @@ public static void UpdateIsAnimationPlaying(this WImage imageView, IImageSourceP { var service = services.GetRequiredImageSourceService(imageSource); - var scale = imageView.XamlRoot?.RasterizationScale ?? 1; + var scale = destinationContext.XamlRoot?.RasterizationScale ?? 1; var result = await service.GetImageSourceAsync(imageSource, (float)scale, cancellationToken); var uiImage = result?.Value; @@ -82,9 +92,7 @@ public static void UpdateIsAnimationPlaying(this WImage imageView, IImageSourceP // only set the image if we are still on the same one if (applied) { - imageView.Source = uiImage; - - imageView.UpdateIsAnimationPlaying(image); + setImage(uiImage); } events?.LoadingCompleted(applied); diff --git a/src/Core/src/Platform/Windows/TextBlockExtensions.cs b/src/Core/src/Platform/Windows/TextBlockExtensions.cs index aa67ef18ce5e..c1b6c554ec30 100644 --- a/src/Core/src/Platform/Windows/TextBlockExtensions.cs +++ b/src/Core/src/Platform/Windows/TextBlockExtensions.cs @@ -26,13 +26,13 @@ public static void UpdateText(this TextBlock nativeControl, ILabel label) nativeControl.UpdateTextPlainText(label); } - public static void UpdateTextColor(this TextBlock nativeControl, IText text) => + public static void UpdateTextColor(this TextBlock nativeControl, ITextStyle text) => nativeControl.UpdateProperty(TextBlock.ForegroundProperty, text.TextColor); public static void UpdatePadding(this TextBlock nativeControl, ILabel label) => nativeControl.UpdateProperty(TextBlock.PaddingProperty, label.Padding.ToNative()); - public static void UpdateCharacterSpacing(this TextBlock nativeControl, ILabel label) + public static void UpdateCharacterSpacing(this TextBlock nativeControl, ITextStyle label) { nativeControl.CharacterSpacing = label.CharacterSpacing.ToEm(); } @@ -173,7 +173,7 @@ public static void UpdateLineBreakMode(this TextBlock nativeControl, ILabel labe internal static void DetermineTruncatedTextWrapping(this TextBlock textBlock) => textBlock.TextWrapping = textBlock.MaxLines > 1 ? TextWrapping.Wrap : TextWrapping.NoWrap; - internal static void UpdateTextPlainText(this TextBlock nativeControl, ILabel label) + internal static void UpdateTextPlainText(this TextBlock nativeControl, IText label) { nativeControl.Text = label.Text; } diff --git a/src/Core/src/Platform/iOS/ButtonExtensions.cs b/src/Core/src/Platform/iOS/ButtonExtensions.cs index 4413eb439e53..565c06bbde36 100644 --- a/src/Core/src/Platform/iOS/ButtonExtensions.cs +++ b/src/Core/src/Platform/iOS/ButtonExtensions.cs @@ -7,13 +7,13 @@ namespace Microsoft.Maui { public static class ButtonExtensions { - public static void UpdateText(this UIButton nativeButton, IButton button) => + public static void UpdateText(this UIButton nativeButton, IText button) => nativeButton.SetTitle(button.Text, UIControlState.Normal); - public static void UpdateTextColor(this UIButton nativeButton, IButton button) => + public static void UpdateTextColor(this UIButton nativeButton, ITextStyle button) => nativeButton.UpdateTextColor(button); - public static void UpdateTextColor(this UIButton nativeButton, IButton button, UIColor? buttonTextColorDefaultNormal, UIColor? buttonTextColorDefaultHighlighted, UIColor? buttonTextColorDefaultDisabled) + public static void UpdateTextColor(this UIButton nativeButton, ITextStyle button, UIColor? buttonTextColorDefaultNormal, UIColor? buttonTextColorDefaultHighlighted, UIColor? buttonTextColorDefaultDisabled) { if (button.TextColor == null) { diff --git a/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs b/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs index fbc0fb7e3960..2b29a6b3c003 100644 --- a/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs @@ -7,25 +7,21 @@ namespace Microsoft.Maui { - internal partial class ImageSourcePartWrapper : IImageSourcePart - where T : ElementHandler + public partial class ImageSourcePartLoader { Action? SetImage { get; } UIView? NativeView => Handler.NativeView as UIView; - public ImageSourcePartWrapper( - T handler, - Func getSource, - Func? getIsAnimationPlaying, + public ImageSourcePartLoader( + IElementHandler handler, + Func getSource, + Func? getIsAnimationPlaying, Action? setIsLoading, Action setImage) + : this(handler, getSource, getIsAnimationPlaying, setIsLoading) { - GetSource = getSource; - GetIsAnimationPlaying = getIsAnimationPlaying; - SetIsLoading = setIsLoading; SetImage = setImage; - Handler = handler; } } } diff --git a/src/Core/src/Platform/iOS/ImageViewExtensions.cs b/src/Core/src/Platform/iOS/ImageViewExtensions.cs index 6d362b18b5a7..e5430d1c1dd5 100644 --- a/src/Core/src/Platform/iOS/ImageViewExtensions.cs +++ b/src/Core/src/Platform/iOS/ImageViewExtensions.cs @@ -31,6 +31,13 @@ public static void UpdateIsAnimationPlaying(this UIImageView imageView, IImageSo imageView.StopAnimating(); } } + + public static void UpdateSource(this UIImageView imageView, UIImage? uIImage, IImageSourcePart image) + { + imageView.Image = uIImage; + imageView.UpdateIsAnimationPlaying(image); + } + public static Task?> UpdateSourceAsync( this UIImageView imageView, IImageSourcePart image, @@ -40,8 +47,7 @@ public static void UpdateIsAnimationPlaying(this UIImageView imageView, IImageSo imageView.Clear(); return image.UpdateSourceAsync(imageView, services, (uiImage) => { - imageView.Image = uiImage; - imageView.UpdateIsAnimationPlaying(image); + imageView.UpdateSource(uiImage, image); }, cancellationToken); } diff --git a/src/Core/src/Platform/iOS/LabelExtensions.cs b/src/Core/src/Platform/iOS/LabelExtensions.cs index b8cf82a1acf5..ad79f9e4538d 100644 --- a/src/Core/src/Platform/iOS/LabelExtensions.cs +++ b/src/Core/src/Platform/iOS/LabelExtensions.cs @@ -86,7 +86,7 @@ internal static void UpdateTextHtml(this UILabel nativeLabel, ILabel label) nativeLabel.AttributedText = new NSAttributedString(text, attr, ref nsError); } - internal static void UpdateTextPlainText(this UILabel nativeLabel, ILabel label) + internal static void UpdateTextPlainText(this UILabel nativeLabel, IText label) { nativeLabel.Text = label.Text; } diff --git a/src/Core/src/Platform/iOS/MauiImageView.cs b/src/Core/src/Platform/iOS/MauiImageView.cs index 0d2ed510f14d..841ee99e7537 100644 --- a/src/Core/src/Platform/iOS/MauiImageView.cs +++ b/src/Core/src/Platform/iOS/MauiImageView.cs @@ -2,7 +2,7 @@ using CoreGraphics; using UIKit; -namespace Microsoft.Maui.Platform.iOS +namespace Microsoft.Maui { public class MauiImageView : UIImageView { diff --git a/src/Core/src/Platform/iOS/MauiLabel.cs b/src/Core/src/Platform/iOS/MauiLabel.cs index e6fea8f8953b..dd68c1835f9e 100644 --- a/src/Core/src/Platform/iOS/MauiLabel.cs +++ b/src/Core/src/Platform/iOS/MauiLabel.cs @@ -3,7 +3,7 @@ using CoreGraphics; using UIKit; -namespace Microsoft.Maui.Platform.iOS +namespace Microsoft.Maui { public class MauiLabel : UILabel { diff --git a/src/Core/src/PropertyMapper.cs b/src/Core/src/PropertyMapper.cs index c5a9d8d57bf4..a71479df2f45 100644 --- a/src/Core/src/PropertyMapper.cs +++ b/src/Core/src/PropertyMapper.cs @@ -6,8 +6,8 @@ namespace Microsoft.Maui { public abstract class PropertyMapper : IPropertyMapper { - readonly Dictionary> _mapper = new(); - + readonly Dictionary> _mapper = new(); + readonly IPropertyMapper[]? _propertyMappers; IPropertyMapper? _chained; // Keep a distinct list of the keys so we don't run any duplicate (overridden) updates more than once @@ -22,30 +22,53 @@ public PropertyMapper(IPropertyMapper chained) { Chained = chained; } + + public PropertyMapper(IPropertyMapper chained, params IPropertyMapper[] propertyMappers) + { + Chained = chained; + _propertyMappers = propertyMappers; + } - protected virtual void SetPropertyCore(string key, Action action) + protected virtual void SetPropertyCore(string key, Action action) { _mapper[key] = action; ClearKeyCache(); } - protected virtual void UpdatePropertyCore(string key, IElementHandler viewHandler, IElement virtualView) + protected virtual void UpdatePropertyCore(string key, object viewHandler, IElement virtualView) { var action = GetProperty(key); action?.Invoke(viewHandler, virtualView); } - public virtual Action? GetProperty(string key) + public virtual Action? GetProperty(string key) { if (_mapper.TryGetValue(key, out var action)) return action; else if (Chained is not null) + { + // TODO MAUI make this less messy + // currently just doing this to get a point across + // we'll probably create something called "compositeMapper : PropertyMapper" + + if (_propertyMappers != null) + { + foreach(var mapper in _propertyMappers) + { + var thing = mapper.GetProperty(key); + if (thing != null) + { + return thing; + } + } + } return Chained.GetProperty(key); + } else return null; } - public void UpdateProperty(IElementHandler viewHandler, IElement? virtualView, string property) + public void UpdateProperty(object viewHandler, IElement? virtualView, string property) { if (virtualView == null) return; @@ -53,7 +76,7 @@ public void UpdateProperty(IElementHandler viewHandler, IElement? virtualView, s UpdatePropertyCore(property, viewHandler, virtualView); } - public void UpdateProperties(IElementHandler viewHandler, IElement? virtualView) + public void UpdateProperties(object viewHandler, IElement? virtualView) { if (virtualView == null) return; @@ -109,25 +132,23 @@ public IEnumerable GetKeys() public interface IPropertyMapper { - Action? GetProperty(string key); + Action? GetProperty(string key); IEnumerable GetKeys(); - void UpdateProperties(IElementHandler elementHandler, IElement virtualView); + void UpdateProperties(object elementHandler, IElement virtualView); - void UpdateProperty(IElementHandler elementHandler, IElement virtualView, string property); + void UpdateProperty(object elementHandler, IElement virtualView, string property); } public interface IPropertyMapper : IPropertyMapper where TVirtualView : IElement - where TViewHandler : IElementHandler { void Add(string key, Action action); } public class PropertyMapper : PropertyMapper, IPropertyMapper where TVirtualView : IElement - where TViewHandler : IElementHandler { public PropertyMapper() { @@ -138,12 +159,23 @@ public PropertyMapper(IPropertyMapper chained) { } + public PropertyMapper(IPropertyMapper chained, params IPropertyMapper[] propertyMappers) + : base(chained, propertyMappers) + { + } + public Action this[string key] { get { var action = GetProperty(key) ?? throw new IndexOutOfRangeException($"Unable to find mapping for '{nameof(key)}'."); - return new Action((h, v) => action.Invoke(h, v)); + return new Action((h, v) => + { + if (h is TViewHandler viewHandler) + action.Invoke(viewHandler, v); + + throw new InvalidOperationException($"{h} can't be cast to type {typeof(TViewHandler)}"); + }); } set => Add(key, value); } From f1f6b273d4d45d3ade0dbe04575eb57017939795 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 21 Sep 2021 09:17:26 -0500 Subject: [PATCH 02/22] - additional --- .../Controls.Sample/Pages/MainPage.xaml | 2 +- .../Core/HandlerImpl/Button/Button.Impl.cs | 47 ++++++++++++------- .../ImageButton/ImageButton.Impl.cs | 10 +++- src/Core/src/Core/IButton.cs | 2 +- src/Core/src/Handlers/Button/ButtonHandler.cs | 6 +-- src/Core/src/Handlers/Image/ImageHandler.cs | 6 +-- .../Android/ImageSourcePartWrapper.cs | 8 ++-- .../src/Platform/ImageSourcePartWrapper.cs | 46 ++++++++++-------- .../Standard/ImageSourcePartWrapper.cs | 6 +-- .../Windows/ImageSourcePartWrapper.cs | 6 +-- .../Platform/iOS/ImageSourcePartWrapper.cs | 6 +-- 11 files changed, 77 insertions(+), 68 deletions(-) diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml b/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml index 3feab3be4394..2cc0ea36ae2f 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml @@ -60,7 +60,7 @@ RowDefinitions="150, *, Auto" RowSpacing="0"> - diff --git a/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs b/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs index e937b8d43b7e..4df37b61dceb 100644 --- a/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/Button/Button.Impl.cs @@ -4,13 +4,13 @@ namespace Microsoft.Maui.Controls { - public partial class Button : IButton, IText, IImageSourcePart + public partial class Button : IButton, IText { public new static void RemapForControls() { // IButton does not include the ContentType property, so we map it here to handle Image Positioning - IPropertyMapper ControlsButtonMapper = new PropertyMapper(ButtonMapper.Mapper) + IPropertyMapper ControlsButtonMapper = new PropertyMapper(ButtonHandler.Mapper) { [nameof(ContentLayout)] = MapContentLayout, #if __IOS__ @@ -18,16 +18,12 @@ public partial class Button : IButton, IText, IImageSourcePart #endif }; - ButtonMapper.Mapper = ControlsButtonMapper; + ButtonHandler.Mapper = ControlsButtonMapper; } - public static void MapContentLayout(IButtonHandler handler, Button button) + public static void MapContentLayout(ButtonHandler handler, Button button) { -#if __IOS__ - (handler.NativeView as UIKit.UIButton)?.UpdateContentLayout(button); -#elif __ANDROID__ - (handler.NativeView as Google.Android.Material.Button.MaterialButton)?.UpdateContentLayout(button); -#endif + handler.NativeView.UpdateContentLayout(button); } void IButton.Clicked() @@ -45,16 +41,33 @@ void IButton.Released() (this as IButtonController).SendReleased(); } - IImageSource IImageSourcePart.Source => ImageSource; - - void IImageSourcePart.UpdateIsLoading(bool isLoading) + void IButton.ImageSourceLoaded() { - if (!isLoading) - Handler?.UpdateValue(nameof(ContentLayout)); + Handler?.UpdateValue(nameof(ContentLayout)); } - bool IImageSourcePart.IsAnimationPlaying => false; - Font ITextStyle.Font => (Font)GetValue(FontElement.FontProperty); + + ButtonImageSourcePart _buttonImageSourcePart; + IImageSourcePart IButton.ImageSource => _buttonImageSourcePart ??= new ButtonImageSourcePart(this); + + class ButtonImageSourcePart : IImageSourcePart + { + readonly Button _button; + + public IImageSource Source => _button.ImageSource; + + public bool IsAnimationPlaying => false; + + public void UpdateIsLoading(bool isLoading) + { + + } + + public ButtonImageSourcePart(Button button) + { + _button = button; + } + } } -} +} \ No newline at end of file diff --git a/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs b/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs index 9adbe8b6eec2..1460677bb0ad 100644 --- a/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/ImageButton/ImageButton.Impl.cs @@ -6,12 +6,12 @@ namespace Microsoft.Maui.Controls { public partial class ImageButton : IImageButton { - IImageSource IImageSourcePart.Source => Source; - void IImageSourcePart.UpdateIsLoading(bool isLoading) { } bool IImageSourcePart.IsAnimationPlaying => false; + IImageSource IImageSourcePart.Source => Source; + void IButton.Clicked() { (this as IButtonController).SendClicked(); @@ -26,5 +26,11 @@ void IButton.Released() { (this as IButtonController).SendReleased(); } + + void IButton.ImageSourceLoaded() + { + } + + IImageSourcePart IButton.ImageSource => this; } } diff --git a/src/Core/src/Core/IButton.cs b/src/Core/src/Core/IButton.cs index 806df94359e2..d2d515f245ce 100644 --- a/src/Core/src/Core/IButton.cs +++ b/src/Core/src/Core/IButton.cs @@ -8,7 +8,7 @@ public interface IButton : IView, IPadding /// /// Allows you to display a bitmap image on the Button. /// - IImageSource? ImageSource { get; } + IImageSourcePart? ImageSource { get; } void ImageSourceLoaded(); diff --git a/src/Core/src/Handlers/Button/ButtonHandler.cs b/src/Core/src/Handlers/Button/ButtonHandler.cs index 1d07902a83b3..130f2b312cbb 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.cs @@ -14,11 +14,7 @@ public partial class ButtonHandler : IButtonHandler { ImageSourcePartLoader? _imageSourcePartLoader; public ImageSourcePartLoader ImageSourceLoader => - _imageSourcePartLoader ??= new ImageSourcePartLoader(this, - () => VirtualView.ImageSource, - () => false, - (isLoading) => (VirtualView as IImage)?.UpdateIsLoading(isLoading), - OnSetImageSource); + _imageSourcePartLoader ??= new ImageSourcePartLoader(this, () => VirtualView?.ImageSource, OnSetImageSource); public static IPropertyMapper TextStyleMapper = new PropertyMapper(ViewHandler.ViewMapper) { diff --git a/src/Core/src/Handlers/Image/ImageHandler.cs b/src/Core/src/Handlers/Image/ImageHandler.cs index 85435b2139ba..944af9286693 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.cs @@ -30,11 +30,7 @@ public partial class ImageHandler : IImageHandler ImageSourcePartLoader? _imageSourcePartLoader; public ImageSourcePartLoader SourceLoader => - _imageSourcePartLoader ??= new ImageSourcePartLoader(this, - () => VirtualView.Source, - () => VirtualView.IsAnimationPlaying, - (isLoading) => (VirtualView as IImage)?.UpdateIsLoading(isLoading), - OnSetImageSource); + _imageSourcePartLoader ??= new ImageSourcePartLoader(this, () => VirtualView, OnSetImageSource); public ImageHandler() : base(Mapper) { diff --git a/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs index 4ecfc218bc00..daf7f0585373 100644 --- a/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs @@ -8,7 +8,7 @@ namespace Microsoft.Maui { - public partial class ImageSourcePartLoader : IImageSourcePart + public partial class ImageSourcePartLoader { Action? SetImage { get; } @@ -16,10 +16,8 @@ public partial class ImageSourcePartLoader : IImageSourcePart public ImageSourcePartLoader( IElementHandler handler, - Func getSource, - Func? getIsAnimationPlaying, - Action? setIsLoading, - Action setDrawable) : this(handler, getSource, getIsAnimationPlaying, setIsLoading) + Func imageSourcePart, + Action setDrawable) : this(handler, imageSourcePart) { SetImage = setDrawable; } diff --git a/src/Core/src/Platform/ImageSourcePartWrapper.cs b/src/Core/src/Platform/ImageSourcePartWrapper.cs index 2170469e5381..8c8acca321f7 100644 --- a/src/Core/src/Platform/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/ImageSourcePartWrapper.cs @@ -1,30 +1,32 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Microsoft.Maui.Handlers; +#if __IOS__ || MACCATALYST +using NativeImage = UIKit.UIImage; +#elif MONOANDROID +using NativeImage = Android.Graphics.Drawables.Drawable; +#elif WINDOWS +using NativeImage = Microsoft.UI.Xaml.Media.ImageSource; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeImage = System.Object; +#endif namespace Microsoft.Maui { - public partial class ImageSourcePartLoader : IImageSourcePart + public partial class ImageSourcePartLoader { - public ImageSourceServiceResultManager SourceManager { get; } = new ImageSourceServiceResultManager(); - - Func? GetSource { get; } - - Func? GetIsAnimationPlaying { get; } + readonly Func _imageSourcePart; - Action? SetIsLoading { get; } + public ImageSourceServiceResultManager SourceManager { get; } = new ImageSourceServiceResultManager(); IElementHandler Handler { get; } internal ImageSourcePartLoader( IElementHandler handler, - Func getSource, - Func? getIsAnimationPlaying, - Action? setIsLoading) + Func imageSourcePart) { Handler = handler; + _imageSourcePart = imageSourcePart; } public void Reset() @@ -32,12 +34,6 @@ public void Reset() SourceManager.Reset(); } - IImageSource? IImageSourcePart.Source => GetSource?.Invoke(); - - bool IImageSourcePart.IsAnimationPlaying => GetIsAnimationPlaying?.Invoke() ?? false; - - void IImageSourcePart.UpdateIsLoading(bool isLoading) => SetIsLoading?.Invoke(isLoading); - public async Task UpdateImageSourceAsync() { #if __IOS__ || __ANDROID__ || WINDOWS @@ -45,8 +41,18 @@ public async Task UpdateImageSourceAsync() { var token = this.SourceManager.BeginLoad(); var provider = Handler.GetRequiredService(); - var result = await this.UpdateSourceAsync(NativeView, provider, SetImage!, token); - SourceManager.CompleteLoad(result); + var imageSource = _imageSourcePart(); + + if (imageSource != null) + { + var result = await imageSource.UpdateSourceAsync(NativeView, provider, SetImage!, token); + SourceManager.CompleteLoad(result); + } + else + { + SetImage?.Invoke(null); + SourceManager.CompleteLoad(null); + } } #else await Task.CompletedTask; diff --git a/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs index 8d4421226d2f..7293deaf4d0c 100644 --- a/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs @@ -10,11 +10,9 @@ public partial class ImageSourcePartLoader { public ImageSourcePartLoader( IElementHandler handler, - Func getSource, - Func? getIsAnimationPlaying, - Action? setIsLoading, + Func imageSourcePart, Action setImage) - : this(handler, getSource, getIsAnimationPlaying, setIsLoading) + : this(handler, imageSourcePart) { } } diff --git a/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs index fa449887368b..c63bfec98994 100644 --- a/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs @@ -16,11 +16,9 @@ public partial class ImageSourcePartLoader public ImageSourcePartLoader( IElementHandler handler, - Func getSource, - Func? getIsAnimationPlaying, - Action? setIsLoading, + Func imageSourcePart, Action setImage) - : this(handler, getSource, getIsAnimationPlaying, setIsLoading) + : this(handler, imageSourcePart) { SetImage = setImage; } diff --git a/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs b/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs index 2b29a6b3c003..820615239bdb 100644 --- a/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs @@ -15,11 +15,9 @@ public partial class ImageSourcePartLoader public ImageSourcePartLoader( IElementHandler handler, - Func getSource, - Func? getIsAnimationPlaying, - Action? setIsLoading, + Func imageSourcePart, Action setImage) - : this(handler, getSource, getIsAnimationPlaying, setIsLoading) + : this(handler, imageSourcePart) { SetImage = setImage; } From 70e49401216408c55007ff971c3dc736cd9fef5a Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 21 Sep 2021 10:54:07 -0500 Subject: [PATCH 03/22] - consolidating code --- src/Controls/src/Core/MenuItem.cs | 13 +---- .../Android/BottomNavigationViewUtils.cs | 12 ++--- .../Android/Extensions/ToolbarExtensions.cs | 2 +- .../Platform/Android/ImageSourceLoader.cs | 51 ------------------ .../Shell/ShellFlyoutTemplatedContentView.cs | 12 ++--- .../Platform/Android/Shell/ShellItemView.cs | 7 +-- .../Platform/Android/Shell/ShellSearchView.cs | 8 +-- .../Android/Shell/ShellToolbarTracker.cs | 2 +- .../src/Core/Platform/ImageSourceLoader.cs | 53 ++----------------- .../Platform/Standard/ImageSourceLoader.cs | 2 +- .../Platform/Windows/ImageSourceLoader.cs | 14 ----- .../Core/Platform/iOS/ImageSourceLoader.cs | 15 ------ .../src/Handlers/Image/ImageHandler.iOS.cs | 2 +- .../Android/ImageSourcePartWrapper.cs | 25 --------- .../src/Platform/ImageSourceExtensions.cs | 42 +++++++++++++++ ...artWrapper.cs => ImageSourcePartLoader.cs} | 16 +++++- .../Standard/ImageSourcePartWrapper.cs | 19 ------- .../Windows/ImageSourcePartWrapper.cs | 26 --------- .../Platform/iOS/ImageSourcePartWrapper.cs | 25 --------- .../src/Platform/iOS/ImageViewExtensions.cs | 5 +- 20 files changed, 86 insertions(+), 265 deletions(-) delete mode 100644 src/Controls/src/Core/Platform/Android/ImageSourceLoader.cs delete mode 100644 src/Controls/src/Core/Platform/Windows/ImageSourceLoader.cs delete mode 100644 src/Controls/src/Core/Platform/iOS/ImageSourceLoader.cs delete mode 100644 src/Core/src/Platform/Android/ImageSourcePartWrapper.cs create mode 100644 src/Core/src/Platform/ImageSourceExtensions.cs rename src/Core/src/Platform/{ImageSourcePartWrapper.cs => ImageSourcePartLoader.cs} (77%) delete mode 100644 src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs delete mode 100644 src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs delete mode 100644 src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs diff --git a/src/Controls/src/Core/MenuItem.cs b/src/Controls/src/Core/MenuItem.cs index c974ce9d4930..9dd394ac0a17 100644 --- a/src/Controls/src/Core/MenuItem.cs +++ b/src/Controls/src/Core/MenuItem.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.Controls { - public class MenuItem : BaseMenuItem, IMenuItemController, IStyleSelectable, IImageSourcePart + public class MenuItem : BaseMenuItem, IMenuItemController, IStyleSelectable { public static readonly BindableProperty AcceleratorProperty = BindableProperty.CreateAttached(nameof(Accelerator), typeof(Accelerator), typeof(MenuItem), null); @@ -141,16 +141,5 @@ void OnCommandParameterChanged() IsEnabledCore = Command.CanExecute(CommandParameter); } - - - IImageSource IImageSourcePart.Source => this.IconImageSource; - - bool _isLoading; - bool IImageSourcePart.IsAnimationPlaying => false; - - void IImageSourcePart.UpdateIsLoading(bool isLoading) - { - _isLoading = isLoading; - } } } \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs b/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs index 7a901a617176..066dfe0fbf3b 100644 --- a/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs +++ b/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs @@ -167,16 +167,10 @@ void clickCallback(object s, EventArgs e) image.ImageTintList = ColorStateList.ValueOf(Colors.Black.MultiplyAlpha(0.6f).ToNative()); - ImageSourceLoader shellImagePart = new ImageSourceLoader() + ImageSourceLoader.LoadImage(shellContent.icon, mauiContext, result => { - Source = shellContent.icon - }; - - - var services = mauiContext.Services; - var provider = services.GetRequiredService(); - image.UpdateSourceAsync(new ImageSourceLoader() { Source = shellContent.icon }, provider) - .FireAndForget(e => Internals.Log.Warning("MenuItem", $"{e}")); + image.SetImageDrawable(result.Value); + }); innerLayout.AddView(image); diff --git a/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs b/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs index 46b27875e014..63a691f5524c 100644 --- a/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs +++ b/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs @@ -147,7 +147,7 @@ static void UpdateMenuItem(AToolbar toolbar, internal static void UpdateMenuItemIcon(IMauiContext mauiContext, IMenuItem menuItem, ToolbarItem toolBarItem, Color tintColor) { - ImageSourceLoader.LoadImage(toolBarItem, mauiContext, result => + ImageSourceLoader.LoadImage(toolBarItem.IconImageSource, mauiContext, result => { var baseDrawable = result.Value; if (menuItem == null || !menuItem.IsAlive()) diff --git a/src/Controls/src/Core/Platform/Android/ImageSourceLoader.cs b/src/Controls/src/Core/Platform/Android/ImageSourceLoader.cs deleted file mode 100644 index 4ff4f45892f1..000000000000 --- a/src/Controls/src/Core/Platform/Android/ImageSourceLoader.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Threading.Tasks; -using Android.Content; -using Android.Graphics.Drawables; -using Android.Runtime; -using Android.Util; -using Android.Views; -using Android.Widget; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.Maui.Controls.Platform -{ - partial class ImageSourceLoader : IImageSourcePart - { - static Task> GetNativeImage(IImageSource imageSource, IImageSourceService imageSourceService, IMauiContext mauiContext) - { - return imageSourceService.GetDrawableAsync(imageSource, mauiContext.Context); - } - - public void LoadImage(ImageView view, Action> finished = null) - { - LoadImageResult(LoadImageAsync(view), finished) - .FireAndForget(e => Internals.Log.Warning(nameof(ImageSourceLoader), $"{e}")); - } - - public Task> LoadImageAsync(ImageView view) - { - var services = MauiContext.Services; - var provider = services.GetRequiredService(); - return view.UpdateSourceAsync(this, provider); - } - - public static Task> LoadImageAsync(ImageView imageView, IMauiContext mauiContext, IImageSource imageSource) - { - var part = new ImageSourceLoader() - { - MauiContext = mauiContext, - Source = imageSource, - }; - - return LoadImageAsync(imageView, part, mauiContext); - } - - public static Task> LoadImageAsync(ImageView imageView, IImageSourcePart part, IMauiContext mauiContext) - { - var services = mauiContext.Services; - var provider = services.GetRequiredService(); - return imageView.UpdateSourceAsync(part, provider); - } - } -} diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs index de45335df703..56abe29ae763 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs @@ -40,7 +40,6 @@ public class ShellFlyoutTemplatedContentView : Java.Lang.Object, IShellFlyoutCon int _actionBarHeight; int _flyoutHeight; int _flyoutWidth; - ImageSourceLoader _shellFlyoutBackgroundImagePart; protected IMauiContext MauiContext => _shellContext.Shell.Handler.MauiContext; @@ -53,7 +52,6 @@ public class ShellFlyoutTemplatedContentView : Java.Lang.Object, IShellFlyoutCon public ShellFlyoutTemplatedContentView(IShellContext shellContext) { _shellContext = shellContext; - _shellFlyoutBackgroundImagePart = new ImageSourceLoader(); LoadView(shellContext); } @@ -351,10 +349,9 @@ protected virtual void UpdateFlyoutBackground() UpdateFlyoutBgImageAsync(); } - async void UpdateFlyoutBgImageAsync() + void UpdateFlyoutBgImageAsync() { var imageSource = _shellContext.Shell.FlyoutBackgroundImage; - _shellFlyoutBackgroundImagePart.Source = imageSource; if (imageSource == null || !_shellContext.Shell.IsSet(Shell.FlyoutBackgroundImageProperty)) { @@ -366,8 +363,11 @@ async void UpdateFlyoutBgImageAsync() var services = MauiContext.Services; var provider = services.GetRequiredService(); - using (var result = await _bgImage.UpdateSourceAsync(_shellFlyoutBackgroundImagePart, provider)) + _bgImage.Clear(); + ImageSourceLoader.LoadImage(imageSource, MauiContext, result => { + _bgImage.SetImageDrawable(result.Value); + if (!_rootView.IsAlive()) return; @@ -400,7 +400,7 @@ async void UpdateFlyoutBgImageAsync() else _rootView.AddView(_bgImage, 0); } - } + }); } protected virtual void UpdateFlyoutHeaderBehavior() diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs index d947e35f3190..0c5dd644f093 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs @@ -210,11 +210,12 @@ void clickCallback(object s, EventArgs e) var provider = services.GetRequiredService(); var icon = shellContent.Icon; - var imageLoad = new ImageSourceLoader() { Source = shellContent.Icon, MauiContext = MauiContext }; - - imageLoad.LoadImage(image, + ImageSourceLoader.LoadImage( + shellContent.Icon, + MauiContext, (result) => { + image.SetImageDrawable(result.Value); if (result.Value != null) { var color = Colors.Black.MultiplyAlpha(0.6f).ToNative(); diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs index 65a88b02bd43..8fc5560d228e 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs @@ -328,17 +328,17 @@ AImageButton CreateImageButton(Context context, BindableObject bindable, Bindabl if (bindable.GetValue(property) is ImageSource image) AutomationPropertiesProvider.SetContentDescription(result, image, null, null); - new ImageSourceLoader() + ImageSourceLoader.LoadImage((ImageSource)bindable.GetValue(property), MauiContext, (r) => { - Source = (ImageSource)bindable.GetValue(property), - MauiContext = MauiContext - }.LoadImage(result); + result.SetImageDrawable(r.Value); + }); var lp = new LinearLayout.LayoutParams((int)Context.ToPixels(22), LP.MatchParent) { LeftMargin = leftMargin, RightMargin = rightMargin }; + result.LayoutParameters = lp; lp.Dispose(); result.SetBackground(null); diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs index 5f264af1dfbc..956d523def04 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs @@ -372,7 +372,7 @@ protected virtual async void UpdateLeftBarButtonItem(Context context, Toolbar to if (fid?.IconBitmapSource == image) customIcon = fid.IconBitmap; else - customIcon = (await ImageSourceLoader.GetImageAsync(image, MauiContext))?.Value; + customIcon = (await image.GetNativeImage(MauiContext))?.Value; if (customIcon != null) { diff --git a/src/Controls/src/Core/Platform/ImageSourceLoader.cs b/src/Controls/src/Core/Platform/ImageSourceLoader.cs index 15186ff20431..b970e7acafad 100644 --- a/src/Controls/src/Core/Platform/ImageSourceLoader.cs +++ b/src/Controls/src/Core/Platform/ImageSourceLoader.cs @@ -13,45 +13,12 @@ namespace Microsoft.Maui.Controls.Platform { - partial class ImageSourceLoader : IImageSourcePart + partial class ImageSourceLoader { - public IImageSource Source - { - get; - set; - } - - public IMauiContext MauiContext - { - get; - set; - } - - public bool IsAnimationPlaying { get; set; } - public bool IsLoading { get; private set; } - - public void UpdateIsLoading(bool isLoading) - { - IsLoading = isLoading; - } - - public static Task> GetImageAsync(IImageSource imageSource, IMauiContext mauiContext) - { - if (imageSource == null) - return Task.FromResult>(new ImageSourceServiceResult(null)); - - var services = mauiContext.Services; - var provider = services.GetRequiredService(); - var imageSourceService = provider.GetRequiredImageSourceService(imageSource); - return GetNativeImage(imageSource, imageSourceService, mauiContext); - } - - public static Task> GetImageAsync(IImageSourcePart imagePart, IMauiContext mauiContext) + public static void LoadImage(IImageSource source, IMauiContext mauiContext, Action> finished = null) { - var services = mauiContext.Services; - var provider = services.GetRequiredService(); - var imageSourceService = provider.GetRequiredImageSourceService(imagePart.Source); - return GetNativeImage(imagePart.Source, imageSourceService, mauiContext); + LoadImageResult(source.GetNativeImage(mauiContext), finished) + .FireAndForget(e => Internals.Log.Warning(nameof(ImageSourceLoader), $"{e}")); } static async Task LoadImageResult(Task> task, Action> finished = null) @@ -59,17 +26,5 @@ static async Task LoadImageResult(Task> ta var result = await task; finished?.Invoke(result); } - - public static void LoadImage(IImageSource source, IMauiContext mauiContext, Action> finished = null) - { - LoadImageResult(GetImageAsync(source, mauiContext), finished) - .FireAndForget(e => Internals.Log.Warning(nameof(ImageSourceLoader), $"{e}")); - } - - public static void LoadImage(IImageSourcePart part, IMauiContext mauiContext, Action> finished = null) - { - LoadImageResult(GetImageAsync(part.Source, mauiContext), finished) - .FireAndForget(e => Internals.Log.Warning(nameof(ImageSourceLoader), $"{e}")); - } } } diff --git a/src/Controls/src/Core/Platform/Standard/ImageSourceLoader.cs b/src/Controls/src/Core/Platform/Standard/ImageSourceLoader.cs index 3db2db4daf2b..49bfc95b232d 100644 --- a/src/Controls/src/Core/Platform/Standard/ImageSourceLoader.cs +++ b/src/Controls/src/Core/Platform/Standard/ImageSourceLoader.cs @@ -4,7 +4,7 @@ namespace Microsoft.Maui.Controls.Platform { - partial class ImageSourceLoader : IImageSourcePart + partial class ImageSourceLoader { static Task> GetNativeImage(IImageSource imageSource, IImageSourceService imageSourceService, IMauiContext mauiContext) { diff --git a/src/Controls/src/Core/Platform/Windows/ImageSourceLoader.cs b/src/Controls/src/Core/Platform/Windows/ImageSourceLoader.cs deleted file mode 100644 index 350ef151622a..000000000000 --- a/src/Controls/src/Core/Platform/Windows/ImageSourceLoader.cs +++ /dev/null @@ -1,14 +0,0 @@ - -using System; -using System.Threading.Tasks; - -namespace Microsoft.Maui.Controls.Platform -{ - partial class ImageSourceLoader : IImageSourcePart - { - static Task> GetNativeImage(IImageSource imageSource, IImageSourceService imageSourceService, IMauiContext mauiContext) - { - return imageSourceService.GetImageSourceAsync(imageSource); - } - } -} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/iOS/ImageSourceLoader.cs b/src/Controls/src/Core/Platform/iOS/ImageSourceLoader.cs deleted file mode 100644 index 8cab6c10db05..000000000000 --- a/src/Controls/src/Core/Platform/iOS/ImageSourceLoader.cs +++ /dev/null @@ -1,15 +0,0 @@ - -using System; -using System.Threading.Tasks; -using UIKit; - -namespace Microsoft.Maui.Controls.Platform -{ - partial class ImageSourceLoader : IImageSourcePart - { - static Task> GetNativeImage(IImageSource imageSource, IImageSourceService imageSourceService, IMauiContext mauiContext) - { - return imageSourceService.GetImageAsync(imageSource); - } - } -} \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.iOS.cs b/src/Core/src/Handlers/Image/ImageHandler.iOS.cs index c7e941b8a19b..6138bb6d69e4 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.iOS.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.iOS.cs @@ -59,7 +59,7 @@ public static Task MapSourceAsync(IImageHandler handler, IImage image) void OnSetImageSource(UIImage? obj) { - NativeView.UpdateSource(obj, VirtualView); + NativeView.Image = obj; } void OnWindowChanged(object? sender, EventArgs e) diff --git a/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs deleted file mode 100644 index daf7f0585373..000000000000 --- a/src/Core/src/Platform/Android/ImageSourcePartWrapper.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Android.Graphics.Drawables; -using Android.Views; -using Microsoft.Maui.Handlers; - -namespace Microsoft.Maui -{ - public partial class ImageSourcePartLoader - { - Action? SetImage { get; } - - View? NativeView => Handler.NativeView as View; - - public ImageSourcePartLoader( - IElementHandler handler, - Func imageSourcePart, - Action setDrawable) : this(handler, imageSourcePart) - { - SetImage = setDrawable; - } - } -} diff --git a/src/Core/src/Platform/ImageSourceExtensions.cs b/src/Core/src/Platform/ImageSourceExtensions.cs new file mode 100644 index 000000000000..1ecca9103067 --- /dev/null +++ b/src/Core/src/Platform/ImageSourceExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; + +#if __IOS__ || MACCATALYST +using NativeImage = UIKit.UIImage; +#elif MONOANDROID +using NativeImage = Android.Graphics.Drawables.Drawable; +#elif WINDOWS +using NativeImage = Microsoft.UI.Xaml.Media.ImageSource; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeImage = System.Object; +#endif + +namespace Microsoft.Maui +{ + public static class ImageSourceExtensions + { + public static Task?> GetNativeImage(this IImageSource imageSource, IMauiContext mauiContext) + { + var services = mauiContext.Services; + var provider = services.GetRequiredService(); + var imageSourceService = provider.GetRequiredImageSourceService(imageSource); + return imageSource.GetNativeImage(mauiContext, imageSourceService); + } + + public static Task?> GetNativeImage(this IImageSource imageSource, IMauiContext mauiContext, IImageSourceService imageSourceService) + { +#if __IOS__ || MACCATALYST + return imageSourceService.GetImageAsync(imageSource); +#elif MONOANDROID + return imageSourceService.GetDrawableAsync(imageSource, mauiContext.Context!); +#elif WINDOWS + return imageSourceService.GetImageSourceAsync(imageSource); +#else + throw new NotImplementedException(); +#endif + } + } +} diff --git a/src/Core/src/Platform/ImageSourcePartWrapper.cs b/src/Core/src/Platform/ImageSourcePartLoader.cs similarity index 77% rename from src/Core/src/Platform/ImageSourcePartWrapper.cs rename to src/Core/src/Platform/ImageSourcePartLoader.cs index 8c8acca321f7..0e14146e11a0 100644 --- a/src/Core/src/Platform/ImageSourcePartWrapper.cs +++ b/src/Core/src/Platform/ImageSourcePartLoader.cs @@ -1,13 +1,18 @@ using System; using System.Threading.Tasks; using Microsoft.Maui.Handlers; + #if __IOS__ || MACCATALYST using NativeImage = UIKit.UIImage; +using NativeView = UIKit.UIView; #elif MONOANDROID using NativeImage = Android.Graphics.Drawables.Drawable; +using NativeView = Android.Views.View; #elif WINDOWS using NativeImage = Microsoft.UI.Xaml.Media.ImageSource; +using NativeView = Microsoft.UI.Xaml.FrameworkElement; #elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeView = System.Object; using NativeImage = System.Object; #endif @@ -21,12 +26,19 @@ public partial class ImageSourcePartLoader IElementHandler Handler { get; } - internal ImageSourcePartLoader( + + Action? SetImage { get; } + + NativeView? NativeView => Handler.NativeView as NativeView; + + public ImageSourcePartLoader( IElementHandler handler, - Func imageSourcePart) + Func imageSourcePart, + Action setImage) { Handler = handler; _imageSourcePart = imageSourcePart; + SetImage = setImage; } public void Reset() diff --git a/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs deleted file mode 100644 index 7293deaf4d0c..000000000000 --- a/src/Core/src/Platform/Standard/ImageSourcePartWrapper.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Maui.Handlers; - -namespace Microsoft.Maui -{ - public partial class ImageSourcePartLoader - { - public ImageSourcePartLoader( - IElementHandler handler, - Func imageSourcePart, - Action setImage) - : this(handler, imageSourcePart) - { - } - } -} diff --git a/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs b/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs deleted file mode 100644 index c63bfec98994..000000000000 --- a/src/Core/src/Platform/Windows/ImageSourcePartWrapper.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Maui.Handlers; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Media; - -namespace Microsoft.Maui -{ - public partial class ImageSourcePartLoader - { - Action? SetImage { get; } - - FrameworkElement? NativeView => Handler.NativeView as FrameworkElement; - - public ImageSourcePartLoader( - IElementHandler handler, - Func imageSourcePart, - Action setImage) - : this(handler, imageSourcePart) - { - SetImage = setImage; - } - } -} diff --git a/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs b/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs deleted file mode 100644 index 820615239bdb..000000000000 --- a/src/Core/src/Platform/iOS/ImageSourcePartWrapper.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Maui.Handlers; -using UIKit; - -namespace Microsoft.Maui -{ - public partial class ImageSourcePartLoader - { - Action? SetImage { get; } - - UIView? NativeView => Handler.NativeView as UIView; - - public ImageSourcePartLoader( - IElementHandler handler, - Func imageSourcePart, - Action setImage) - : this(handler, imageSourcePart) - { - SetImage = setImage; - } - } -} diff --git a/src/Core/src/Platform/iOS/ImageViewExtensions.cs b/src/Core/src/Platform/iOS/ImageViewExtensions.cs index e5430d1c1dd5..cfaf928d352c 100644 --- a/src/Core/src/Platform/iOS/ImageViewExtensions.cs +++ b/src/Core/src/Platform/iOS/ImageViewExtensions.cs @@ -47,7 +47,7 @@ public static void UpdateSource(this UIImageView imageView, UIImage? uIImage, II imageView.Clear(); return image.UpdateSourceAsync(imageView, services, (uiImage) => { - imageView.UpdateSource(uiImage, image); + imageView.Image = uiImage; }, cancellationToken); } @@ -84,6 +84,9 @@ public static void UpdateSource(this UIImageView imageView, UIImage? uIImage, II if (applied) { setImage.Invoke(uiImage); + if (destinationContext is UIImageView imageView) + imageView.UpdateIsAnimationPlaying(image); + } events?.LoadingCompleted(applied); From 39dac1df98b65efc8f4ccfddfd1c4b74bac043a1 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 21 Sep 2021 15:14:50 -0500 Subject: [PATCH 04/22] - the actual handler --- .../Pages/Compatibility/ImageButtonPage.xaml | 26 ----- .../Pages/Controls/ImageButtonPage.xaml | 29 +++++ .../ImageButtonPage.xaml.cs | 2 + .../Controls.Sample/Pages/MainPage.xaml | 2 +- .../samples/Controls.Sample/XamlApp.xaml.cs | 2 +- .../Core/Hosting/AppHostBuilderExtensions.cs | 1 + .../Android/BottomNavigationViewUtils.cs | 2 +- .../Android/ControlsNavigationManager.cs | 2 +- .../Android/Extensions/ToolbarExtensions.cs | 2 +- .../Shell/ShellFlyoutTemplatedContentView.cs | 2 +- .../Platform/Android/Shell/ShellItemView.cs | 3 +- .../Platform/Android/Shell/ShellSearchView.cs | 2 +- .../Android/Shell/ShellToolbarTracker.cs | 2 +- .../src/Core/Platform/ImageSourceLoader.cs | 30 ----- .../Windows/ControlsNavigationManager.cs | 2 +- .../Handlers/Button/ButtonHandler.Android.cs | 8 +- .../src/Handlers/Button/IButtonHandler.cs | 8 -- .../Handlers/Image/ImageHandler.Android.cs | 4 - .../Handlers/Image/ImageHandler.Windows.cs | 2 +- .../src/Handlers/Image/ImageHandler.iOS.cs | 1 + .../ImageButton/IImageButtonHandler.cs | 7 ++ .../ImageButton/ImageButtonHandler.Android.cs | 46 ++++---- .../ImageButtonHandler.Standard.cs | 24 ++-- .../ImageButton/ImageButtonHandler.Windows.cs | 105 ++++++++++++++++++ .../ImageButton/ImageButtonHandler.cs | 92 ++++++++------- .../ImageButton/ImageButtonHandler.iOS.cs | 26 +++++ .../Platform/Android/ImageViewExtensions.cs | 3 +- .../src/Platform/ImageSourceExtensions.cs | 12 ++ .../Platform/Windows/ImageViewExtensions.cs | 8 +- 29 files changed, 291 insertions(+), 164 deletions(-) delete mode 100644 src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml create mode 100644 src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml rename src/Controls/samples/Controls.Sample/Pages/{Compatibility => Controls}/ImageButtonPage.xaml.cs (91%) delete mode 100644 src/Controls/src/Core/Platform/ImageSourceLoader.cs create mode 100644 src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs create mode 100644 src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs create mode 100644 src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs diff --git a/src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml deleted file mode 100644 index 73f2182044a5..000000000000 --- a/src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml new file mode 100644 index 000000000000..f38e1f823beb --- /dev/null +++ b/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml @@ -0,0 +1,29 @@ + + + + + + \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml.cs similarity index 91% rename from src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml.cs rename to src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml.cs index 71ab81609fc8..09d9044180e1 100644 --- a/src/Controls/samples/Controls.Sample/Pages/Compatibility/ImageButtonPage.xaml.cs +++ b/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml.cs @@ -1,9 +1,11 @@ using System; +using Microsoft.Maui.Controls; namespace Maui.Controls.Sample.Pages { public partial class ImageButtonPage { + int _clickTotal; public ImageButtonPage() diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml b/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml index 2cc0ea36ae2f..3feab3be4394 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.xaml @@ -60,7 +60,7 @@ RowDefinitions="150, *, Auto" RowSpacing="0"> - diff --git a/src/Controls/samples/Controls.Sample/XamlApp.xaml.cs b/src/Controls/samples/Controls.Sample/XamlApp.xaml.cs index d91bb4101d92..5e2ee02eff40 100644 --- a/src/Controls/samples/Controls.Sample/XamlApp.xaml.cs +++ b/src/Controls/samples/Controls.Sample/XamlApp.xaml.cs @@ -17,7 +17,7 @@ public XamlApp(IServiceProvider services, ITextService textService) Debug.WriteLine($"The injected text service had a message: '{textService.GetText()}'"); - MainPage = Services.GetRequiredService(); + MainPage = new Pages.ImageButtonPage(); //Services.GetRequiredService(); RequestedThemeChanged += (sender, args) => { diff --git a/src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs b/src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs index 5447a958daec..90835cf87cc2 100644 --- a/src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs +++ b/src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs @@ -42,6 +42,7 @@ public static partial class AppHostBuilderExtensions { typeof(Shapes.Polyline), typeof(ShapeViewHandler) }, { typeof(Shapes.Rectangle), typeof(ShapeViewHandler) }, { typeof(Window), typeof(WindowHandler) }, + { typeof(ImageButton), typeof(ImageButtonHandler) }, #if __ANDROID__ || __IOS__ { typeof(RefreshView), typeof(RefreshViewHandler) }, #endif diff --git a/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs b/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs index 066dfe0fbf3b..9373f963fcb6 100644 --- a/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs +++ b/src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs @@ -167,7 +167,7 @@ void clickCallback(object s, EventArgs e) image.ImageTintList = ColorStateList.ValueOf(Colors.Black.MultiplyAlpha(0.6f).ToNative()); - ImageSourceLoader.LoadImage(shellContent.icon, mauiContext, result => + shellContent.icon.LoadImage(mauiContext, result => { image.SetImageDrawable(result.Value); }); diff --git a/src/Controls/src/Core/Platform/Android/ControlsNavigationManager.cs b/src/Controls/src/Core/Platform/Android/ControlsNavigationManager.cs index 11514d2cbf3e..373ae5db00f7 100644 --- a/src/Controls/src/Core/Platform/Android/ControlsNavigationManager.cs +++ b/src/Controls/src/Core/Platform/Android/ControlsNavigationManager.cs @@ -421,7 +421,7 @@ void UpdateTitleIcon() _imageSource = source; _titleIconView.SetImageResource(global::Android.Resource.Color.Transparent); - ImageSourceLoader.LoadImage(source, MauiContext, (result) => + source.LoadImage(MauiContext, (result) => { _titleIconView.SetImageDrawable(result.Value); AutomationPropertiesProvider.AccessibilitySettingsChanged(_titleIconView, source); diff --git a/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs b/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs index 63a691f5524c..8a73a6084c18 100644 --- a/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs +++ b/src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs @@ -147,7 +147,7 @@ static void UpdateMenuItem(AToolbar toolbar, internal static void UpdateMenuItemIcon(IMauiContext mauiContext, IMenuItem menuItem, ToolbarItem toolBarItem, Color tintColor) { - ImageSourceLoader.LoadImage(toolBarItem.IconImageSource, mauiContext, result => + toolBarItem.IconImageSource.LoadImage(mauiContext, result => { var baseDrawable = result.Value; if (menuItem == null || !menuItem.IsAlive()) diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs index 56abe29ae763..19f4a179517a 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellFlyoutTemplatedContentView.cs @@ -364,7 +364,7 @@ void UpdateFlyoutBgImageAsync() var provider = services.GetRequiredService(); _bgImage.Clear(); - ImageSourceLoader.LoadImage(imageSource, MauiContext, result => + imageSource.LoadImage(MauiContext, result => { _bgImage.SetImageDrawable(result.Value); diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs index 0c5dd644f093..ecbfaa745667 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellItemView.cs @@ -210,8 +210,7 @@ void clickCallback(object s, EventArgs e) var provider = services.GetRequiredService(); var icon = shellContent.Icon; - ImageSourceLoader.LoadImage( - shellContent.Icon, + shellContent.Icon.LoadImage( MauiContext, (result) => { diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs index 8fc5560d228e..b7435a9b9884 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellSearchView.cs @@ -328,7 +328,7 @@ AImageButton CreateImageButton(Context context, BindableObject bindable, Bindabl if (bindable.GetValue(property) is ImageSource image) AutomationPropertiesProvider.SetContentDescription(result, image, null, null); - ImageSourceLoader.LoadImage((ImageSource)bindable.GetValue(property), MauiContext, (r) => + ((ImageSource)bindable.GetValue(property)).LoadImage(MauiContext, (r) => { result.SetImageDrawable(r.Value); }); diff --git a/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs b/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs index 956d523def04..4f5f5fad0c45 100644 --- a/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs +++ b/src/Controls/src/Core/Platform/Android/Shell/ShellToolbarTracker.cs @@ -477,7 +477,7 @@ protected virtual Task UpdateDrawerArrowFromFlyoutIcon(Context context, ActionBa protected virtual void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem) { - ImageSourceLoader.LoadImage(toolBarItem.IconImageSource, MauiContext, finished => + toolBarItem.IconImageSource.LoadImage(MauiContext, finished => { var baseDrawable = finished.Value; if (baseDrawable != null) diff --git a/src/Controls/src/Core/Platform/ImageSourceLoader.cs b/src/Controls/src/Core/Platform/ImageSourceLoader.cs deleted file mode 100644 index b970e7acafad..000000000000 --- a/src/Controls/src/Core/Platform/ImageSourceLoader.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -#if __IOS__ || MACCATALYST -using NativeView = UIKit.UIImage; -#elif MONOANDROID -using NativeView = Android.Graphics.Drawables.Drawable; -#elif WINDOWS -using NativeView = Microsoft.UI.Xaml.Media.ImageSource; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) -using NativeView = System.Object; -#endif - -namespace Microsoft.Maui.Controls.Platform -{ - partial class ImageSourceLoader - { - public static void LoadImage(IImageSource source, IMauiContext mauiContext, Action> finished = null) - { - LoadImageResult(source.GetNativeImage(mauiContext), finished) - .FireAndForget(e => Internals.Log.Warning(nameof(ImageSourceLoader), $"{e}")); - } - - static async Task LoadImageResult(Task> task, Action> finished = null) - { - var result = await task; - finished?.Invoke(result); - } - } -} diff --git a/src/Controls/src/Core/Platform/Windows/ControlsNavigationManager.cs b/src/Controls/src/Core/Platform/Windows/ControlsNavigationManager.cs index f497f884cdb8..e001bf555d3c 100644 --- a/src/Controls/src/Core/Platform/Windows/ControlsNavigationManager.cs +++ b/src/Controls/src/Core/Platform/Windows/ControlsNavigationManager.cs @@ -60,7 +60,7 @@ protected virtual void UpdateToolbar() header.Visibility = (hasNavigationBar) ? UI.Xaml.Visibility.Visible : UI.Xaml.Visibility.Collapsed; header.Title = title; - ImageSourceLoader.LoadImage(titleIcon, MauiContext, (result) => + titleIcon.LoadImage(MauiContext, (result) => { header.TitleIcon = result.Value; }); diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Android.cs b/src/Core/src/Handlers/Button/ButtonHandler.Android.cs index 73856ba69c3a..1e8cbd997cb4 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Android.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Android.cs @@ -19,8 +19,8 @@ public partial class ButtonHandler : ViewHandler static Thickness? DefaultPadding; static Drawable? DefaultBackground; - public ButtonClickListener ClickListener { get; } = new ButtonClickListener(); - public ButtonTouchListener TouchListener { get; } = new ButtonTouchListener(); + ButtonClickListener ClickListener { get; } = new ButtonClickListener(); + ButtonTouchListener TouchListener { get; } = new ButtonTouchListener(); static ColorStateList? _transparentColorStateList; @@ -196,7 +196,7 @@ void OnClick(IButton? button, AView? v) button?.Clicked(); } - public class ButtonClickListener : Java.Lang.Object, AView.IOnClickListener + class ButtonClickListener : Java.Lang.Object, AView.IOnClickListener { public ButtonHandler? Handler { get; set; } @@ -206,7 +206,7 @@ public void OnClick(AView? v) } } - public class ButtonTouchListener : Java.Lang.Object, AView.IOnTouchListener + class ButtonTouchListener : Java.Lang.Object, AView.IOnTouchListener { public ButtonHandler? Handler { get; set; } diff --git a/src/Core/src/Handlers/Button/IButtonHandler.cs b/src/Core/src/Handlers/Button/IButtonHandler.cs index 9e8ce2743c06..7e84ad85436e 100644 --- a/src/Core/src/Handlers/Button/IButtonHandler.cs +++ b/src/Core/src/Handlers/Button/IButtonHandler.cs @@ -15,13 +15,5 @@ public partial interface IButtonHandler : IViewHandler IButton TypedVirtualView { get; } NativeView TypedNativeView { get; } ImageSourcePartLoader ImageSourceLoader { get; } - - -#if __ANDROID__ - // These are a little odd here but Android doesn't let you retrieve these from a control - ButtonHandler.ButtonClickListener ClickListener { get; } - ButtonHandler.ButtonTouchListener TouchListener { get; } -#endif - } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.Android.cs b/src/Core/src/Handlers/Image/ImageHandler.Android.cs index 8018dfd63e78..e11e965d23eb 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Android.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Android.cs @@ -6,10 +6,6 @@ namespace Microsoft.Maui.Handlers { - public partial interface IImageHandler : IViewHandler - { - } - public partial class ImageHandler : ViewHandler { public static void MapBackground(IImageHandler handler, IImage image) diff --git a/src/Core/src/Handlers/Image/ImageHandler.Windows.cs b/src/Core/src/Handlers/Image/ImageHandler.Windows.cs index b9e884adffd4..620ccfc9db28 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Windows.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Windows.cs @@ -62,7 +62,7 @@ public static Task MapSourceAsync(IImageHandler handler, IImage image) void OnSetImageSource(ImageSource? obj) { - NativeView.UpdateSource(obj, VirtualView); + NativeView.Source = obj; } void OnNativeViewLoaded(object sender = null!, RoutedEventArgs e = null!) diff --git a/src/Core/src/Handlers/Image/ImageHandler.iOS.cs b/src/Core/src/Handlers/Image/ImageHandler.iOS.cs index 6138bb6d69e4..1ccd396c4a42 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.iOS.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.iOS.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.Threading.Tasks; +using Microsoft.Maui.Graphics; using Microsoft.Maui.Platform.iOS; using UIKit; diff --git a/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs b/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs new file mode 100644 index 000000000000..eca82a308d65 --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs @@ -0,0 +1,7 @@ +namespace Microsoft.Maui.Handlers +{ + public interface IImageButtonHandler : IImageHandler + { + new IImageButton TypedVirtualView { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs index decfa16c1c5b..1ffdb6ded8e5 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs @@ -1,23 +1,29 @@ -//using System; -//using System.Collections.Generic; -//using System.Text; -//using Android.Views; -//using Android.Widget; -//using AndroidX.AppCompat.Widget; +using System; +using System.Collections.Generic; +using System.Text; +using Android.Graphics.Drawables; +using Android.Views; +using Android.Widget; +using AndroidX.AppCompat.Widget; -//namespace Microsoft.Maui.Handlers -//{ -// public partial class ImageButtonHandler : ViewHandler, IImageButtonHandler -// { -// ImageView IImageHandler.NativeView => this.NativeView; +namespace Microsoft.Maui.Handlers +{ + public partial class ImageButtonHandler : ViewHandler + { + protected override AppCompatImageButton CreateNativeView() + { + return new AppCompatImageButton(Context); + } -// ButtonHandler.ButtonClickListener IButtonHandler.ClickListener { get; } = new ButtonHandler.ButtonClickListener(); + void OnSetImageSource(Drawable? obj) + { + NativeView.SetImageDrawable(obj); + } -// ButtonHandler.ButtonTouchListener IButtonHandler.TouchListener { get; } = new ButtonHandler.ButtonTouchListener(); - -// protected override AppCompatImageButton CreateNativeView() -// { -// return new AppCompatImageButton(Context); -// } -// } -//} + protected override void DisconnectHandler(AppCompatImageButton nativeView) + { + base.DisconnectHandler(nativeView); + SourceLoader.Reset(); + } + } +} diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs index 44410230fb73..98722a217a57 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Standard.cs @@ -1,13 +1,13 @@ -//using System; +using System; -//namespace Microsoft.Maui.Handlers -//{ -// public static partial class ImageButtonMapper -// { -// } - -// public sealed partial class ImageButtonHandler : ViewHandler -// { -// protected override object CreateNativeView() => throw new NotImplementedException(); -// } -//} \ No newline at end of file +namespace Microsoft.Maui.Handlers +{ + public sealed partial class ImageButtonHandler : ViewHandler + { + protected override object CreateNativeView() => throw new NotImplementedException(); + void OnSetImageSource(object? obj) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs new file mode 100644 index 000000000000..1379784b1810 --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; + +namespace Microsoft.Maui.Handlers +{ + public partial class ImageButtonHandler : ViewHandler + { + Image? _image; + protected override MauiButton CreateNativeView() + { + _image = new Image() + { + VerticalAlignment = Microsoft.UI.Xaml.VerticalAlignment.Center, + HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Center, + Stretch = Stretch.Uniform, + }; + + var mauiButton = new MauiButton() + { + Content = _image + }; + + mauiButton.Padding = WinUIHelpers.CreateThickness(0); + mauiButton.BorderThickness = WinUIHelpers.CreateThickness(0); + mauiButton.Background = null; + + return mauiButton; + } + + protected override void ConnectHandler(MauiButton nativeView) + { + if (_image != null) + { + _image.ImageFailed += OnImageFailed; + _image.ImageOpened += OnImageOpened; + } + + base.ConnectHandler(nativeView); + + nativeView.Loaded += OnNativeViewLoaded; + nativeView.Unloaded += OnNativeViewUnloaded; + } + + void OnImageOpened(object sender, RoutedEventArgs e) + { + + } + + void OnImageFailed(object sender, ExceptionRoutedEventArgs e) + { + } + + protected override void DisconnectHandler(MauiButton nativeView) + { + base.DisconnectHandler(nativeView); + + if (nativeView.XamlRoot != null) + nativeView.XamlRoot.Changed -= OnXamlRootChanged; + + nativeView.Loaded -= OnNativeViewLoaded; + nativeView.Unloaded -= OnNativeViewUnloaded; + + SourceLoader.Reset(); + } + + void OnSetImageSource(ImageSource? obj) + { + if (NativeView.Content is Image i) + i.Source = obj; + } + + public override Graphics.Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + return base.GetDesiredSize(widthConstraint, heightConstraint); + } + + public override void NativeArrange(Graphics.Rectangle rect) + { + base.NativeArrange(rect); + } + + void OnNativeViewLoaded(object sender = null!, RoutedEventArgs e = null!) + { + if (NativeView?.XamlRoot != null) + { + NativeView.XamlRoot.Changed += OnXamlRootChanged; + } + } + + void OnNativeViewUnloaded(object sender = null!, RoutedEventArgs e = null!) + { + if (NativeView?.XamlRoot != null) + NativeView.XamlRoot.Changed -= OnXamlRootChanged; + } + + void OnXamlRootChanged(XamlRoot sender, XamlRootChangedEventArgs args) + { + UpdateValue(nameof(IImage.Source)); + } + } +} diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs index f8c13afea948..2324763bce46 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs @@ -1,40 +1,52 @@ -//using System; -//using System.Collections.Generic; -//using System.Text; - -//namespace Microsoft.Maui.Handlers -//{ -// public partial interface IImageButtonHandler : IViewHandler, IButtonHandler, IImageHandler -// { -// public new IImageButton VirtualView { get; } -// } - -// public static partial class ImageButtonMapper -// { -// public static IPropertyMapper Mapper = -// new PropertyMapper(ViewHandler.ViewMapper, ButtonMapper.Mapper, ImageMapper.Mapper) -// { -// }; - -// public static CommandMapper ImageButtonCommandMapper = new(ButtonMapper.CommandMapper) -// { -// }; -// } - -// public partial class ImageButtonHandler : IImageButtonHandler -// { -// IButton IButtonHandler.VirtualView => this.VirtualView; - -// IImage IImageHandler.VirtualView => this.VirtualView; - -// ImageSourceServiceResultManager IImageHandler.SourceManager { get; } = new ImageSourceServiceResultManager(); - -// public ImageButtonHandler() : base(ImageMapper.Mapper) -// { -// } - -// public ImageButtonHandler(IPropertyMapper mapper) : base(mapper ?? ImageButtonMapper.Mapper) -// { -// } -// } -//} +using System; +using System.Collections.Generic; +using System.Text; +#if __IOS__ || MACCATALYST +using NativeImage = UIKit.UIImage; +using NativeView = UIKit.UIButton; +#elif MONOANDROID +using NativeImage = Android.Graphics.Drawables.Drawable; +using NativeView = AndroidX.AppCompat.Widget.AppCompatImageButton; +#elif WINDOWS +using NativeImage = Microsoft.UI.Xaml.Media.ImageSource; +using NativeView = Microsoft.UI.Xaml.FrameworkElement; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +using NativeView = System.Object; +using NativeImage = System.Object; +#endif + +namespace Microsoft.Maui.Handlers +{ + public partial class ImageButtonHandler : IImageButtonHandler + { + public static IPropertyMapper ImageMapper = new PropertyMapper(ImageHandler.Mapper); + public static IPropertyMapper Mapper = new PropertyMapper(ImageMapper); + + ImageSourcePartLoader? _imageSourcePartLoader; + public ImageSourcePartLoader SourceLoader => + _imageSourcePartLoader ??= new ImageSourcePartLoader(this, () => VirtualView, OnSetImageSource); + + public ImageButtonHandler() : base(Mapper) + { + } + + public ImageButtonHandler(IPropertyMapper mapper) : base(mapper ?? Mapper) + { + } + + IImageButton IImageButtonHandler.TypedVirtualView => VirtualView; + + IImage IImageHandler.TypedVirtualView => VirtualView; + +#if __IOS__ + UIKit.UIImageView IImageHandler.TypedNativeView => NativeView.ImageView; +#elif WINDOWS + UI.Xaml.Controls.Image IImageHandler.TypedNativeView => (UI.Xaml.Controls.Image)NativeView.Content; +#elif __ANDROID__ + Android.Widget.ImageView IImageHandler.TypedNativeView => NativeView; +#else + object IImageHandler.TypedNativeView => NativeView; +#endif + ImageSourcePartLoader IImageHandler.SourceLoader => SourceLoader; + } +} diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs new file mode 100644 index 000000000000..ee4eaf4e886b --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UIKit; + +namespace Microsoft.Maui.Handlers +{ + public partial class ImageButtonHandler : ViewHandler + { + protected override UIButton CreateNativeView() + { + return new UIButton(UIButtonType.System); + } + + void OnSetImageSource(UIImage? obj) + { + NativeView.ImageView.Image = obj; + } + + protected override void DisconnectHandler(UIButton nativeView) + { + base.DisconnectHandler(nativeView); + SourceLoader.Reset(); + } + } +} diff --git a/src/Core/src/Platform/Android/ImageViewExtensions.cs b/src/Core/src/Platform/Android/ImageViewExtensions.cs index 06b748e62b9a..ca82ce31f077 100644 --- a/src/Core/src/Platform/Android/ImageViewExtensions.cs +++ b/src/Core/src/Platform/Android/ImageViewExtensions.cs @@ -1,5 +1,4 @@ -#nullable enable -using System; +using System; using System.Threading; using System.Threading.Tasks; using Android.Graphics.Drawables; diff --git a/src/Core/src/Platform/ImageSourceExtensions.cs b/src/Core/src/Platform/ImageSourceExtensions.cs index 1ecca9103067..1976a089c75b 100644 --- a/src/Core/src/Platform/ImageSourceExtensions.cs +++ b/src/Core/src/Platform/ImageSourceExtensions.cs @@ -18,6 +18,18 @@ namespace Microsoft.Maui { public static class ImageSourceExtensions { + public static void LoadImage(this IImageSource source, IMauiContext mauiContext, Action?>? finished = null) + { + LoadImageResult(source.GetNativeImage(mauiContext), finished) + .FireAndForget(mauiContext.Services.CreateLogger(), nameof(LoadImage)); + } + + static async Task LoadImageResult(Task?> task, Action?>? finished = null) + { + var result = await task; + finished?.Invoke(result); + } + public static Task?> GetNativeImage(this IImageSource imageSource, IMauiContext mauiContext) { var services = mauiContext.Services; diff --git a/src/Core/src/Platform/Windows/ImageViewExtensions.cs b/src/Core/src/Platform/Windows/ImageViewExtensions.cs index 50019f7e1386..722fe79b8a2a 100644 --- a/src/Core/src/Platform/Windows/ImageViewExtensions.cs +++ b/src/Core/src/Platform/Windows/ImageViewExtensions.cs @@ -55,12 +55,6 @@ public static void UpdateIsAnimationPlaying(this WImage imageView, IImageSourceP } } - public static void UpdateSource(this WImage imageView, WImageSource? uIImage, IImageSourcePart image) - { - imageView.Source = uIImage; - imageView.UpdateIsAnimationPlaying(image); - } - public static async Task?> UpdateSourceAsync( this IImageSourcePart image, FrameworkElement destinationContext, @@ -93,6 +87,8 @@ public static void UpdateSource(this WImage imageView, WImageSource? uIImage, II if (applied) { setImage(uiImage); + if (destinationContext is WImage imageView) + imageView.UpdateIsAnimationPlaying(image); } events?.LoadingCompleted(applied); From 8a39390daeda236c74118633adb25465c222a8ae Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 21 Sep 2021 15:21:44 -0500 Subject: [PATCH 05/22] - wire up events --- .../ImageButton/ImageButtonHandler.Android.cs | 31 ++++++++++++++ .../ImageButton/ImageButtonHandler.Windows.cs | 40 +++++++++++++++---- .../ImageButton/ImageButtonHandler.iOS.cs | 27 +++++++++++++ 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs index 1ffdb6ded8e5..2a7181cb02c2 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Android.cs @@ -22,8 +22,39 @@ void OnSetImageSource(Drawable? obj) protected override void DisconnectHandler(AppCompatImageButton nativeView) { + nativeView.Click -= OnClick; + nativeView.Touch -= OnTouch; base.DisconnectHandler(nativeView); + SourceLoader.Reset(); } + + protected override void ConnectHandler(AppCompatImageButton nativeView) + { + nativeView.Click += OnClick; + nativeView.Touch += OnTouch; + base.ConnectHandler(nativeView); + } + + void OnTouch(object? sender, View.TouchEventArgs e) + { + var motionEvent = e.Event; + switch (motionEvent?.ActionMasked) + { + case MotionEventActions.Down: + VirtualView?.Pressed(); + break; + case MotionEventActions.Up: + VirtualView?.Released(); + break; + } + + e.Handled = false; + } + + void OnClick(object? sender, EventArgs e) + { + VirtualView?.Clicked(); + } } } diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs index 1379784b1810..bcb1cfc59c18 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs @@ -3,12 +3,15 @@ using System.Text; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; namespace Microsoft.Maui.Handlers { public partial class ImageButtonHandler : ViewHandler { + + PointerEventHandler? _pointerPressedHandler; Image? _image; protected override MauiButton CreateNativeView() { @@ -33,6 +36,11 @@ protected override MauiButton CreateNativeView() protected override void ConnectHandler(MauiButton nativeView) { + _pointerPressedHandler = new PointerEventHandler(OnPointerPressed); + + nativeView.Click += OnClick; + nativeView.AddHandler(UI.Xaml.UIElement.PointerPressedEvent, _pointerPressedHandler, true); + if (_image != null) { _image.ImageFailed += OnImageFailed; @@ -45,17 +53,13 @@ protected override void ConnectHandler(MauiButton nativeView) nativeView.Unloaded += OnNativeViewUnloaded; } - void OnImageOpened(object sender, RoutedEventArgs e) + protected override void DisconnectHandler(MauiButton nativeView) { + nativeView.Click -= OnClick; + nativeView.RemoveHandler(UI.Xaml.UIElement.PointerPressedEvent, _pointerPressedHandler); - } - - void OnImageFailed(object sender, ExceptionRoutedEventArgs e) - { - } + _pointerPressedHandler = null; - protected override void DisconnectHandler(MauiButton nativeView) - { base.DisconnectHandler(nativeView); if (nativeView.XamlRoot != null) @@ -67,6 +71,15 @@ protected override void DisconnectHandler(MauiButton nativeView) SourceLoader.Reset(); } + void OnImageOpened(object sender, RoutedEventArgs e) + { + + } + + void OnImageFailed(object sender, ExceptionRoutedEventArgs e) + { + } + void OnSetImageSource(ImageSource? obj) { if (NativeView.Content is Image i) @@ -101,5 +114,16 @@ void OnXamlRootChanged(XamlRoot sender, XamlRootChangedEventArgs args) { UpdateValue(nameof(IImage.Source)); } + + void OnClick(object sender, UI.Xaml.RoutedEventArgs e) + { + VirtualView?.Clicked(); + VirtualView?.Released(); + } + + void OnPointerPressed(object sender, PointerRoutedEventArgs e) + { + VirtualView?.Pressed(); + } } } diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs index ee4eaf4e886b..91aa0cb5a389 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.iOS.cs @@ -17,10 +17,37 @@ void OnSetImageSource(UIImage? obj) NativeView.ImageView.Image = obj; } + protected override void ConnectHandler(UIButton nativeView) + { + nativeView.TouchUpInside += OnButtonTouchUpInside; + nativeView.TouchUpOutside += OnButtonTouchUpOutside; + nativeView.TouchDown += OnButtonTouchDown; + base.ConnectHandler(nativeView); + } + protected override void DisconnectHandler(UIButton nativeView) { + nativeView.TouchUpInside -= OnButtonTouchUpInside; + nativeView.TouchUpOutside -= OnButtonTouchUpOutside; + nativeView.TouchDown -= OnButtonTouchDown; base.DisconnectHandler(nativeView); SourceLoader.Reset(); } + + void OnButtonTouchUpInside(object? sender, EventArgs e) + { + VirtualView?.Released(); + VirtualView?.Clicked(); + } + + void OnButtonTouchUpOutside(object? sender, EventArgs e) + { + VirtualView?.Released(); + } + + void OnButtonTouchDown(object? sender, EventArgs e) + { + VirtualView?.Pressed(); + } } } From d1f4c3534157b3465f569b7328b295a1219b8cef Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Tue, 21 Sep 2021 15:34:13 -0500 Subject: [PATCH 06/22] - fix iOS --- .../Controls.Sample/Pages/Controls/ImageButtonPage.xaml | 8 ++++---- .../src/Handlers/ImageButton/ImageButtonHandler.iOS.cs | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml index f38e1f823beb..25377e702a80 100644 --- a/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml +++ b/src/Controls/samples/Controls.Sample/Pages/Controls/ImageButtonPage.xaml @@ -9,19 +9,19 @@