diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/ButtonPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/ButtonPage.xaml
index c2e8992c9566..08e46dd28b96 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/ButtonPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/ButtonPage.xaml
@@ -30,6 +30,12 @@
BackgroundColor="Red"
TextColor="White"
Text="Button"/>
+
+
diff --git a/src/Controls/src/Core/Platform/Windows/Extensions/ButtonExtensions.cs b/src/Controls/src/Core/Platform/Windows/Extensions/ButtonExtensions.cs
index 4420dad480a9..cf4b7d0c7c38 100644
--- a/src/Controls/src/Core/Platform/Windows/Extensions/ButtonExtensions.cs
+++ b/src/Controls/src/Core/Platform/Windows/Extensions/ButtonExtensions.cs
@@ -1,26 +1,19 @@
#nullable enable
-
-using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Media.Imaging;
-using WImage = Microsoft.UI.Xaml.Controls.Image;
-using WStretch = Microsoft.UI.Xaml.Media.Stretch;
-using WThickness = Microsoft.UI.Xaml.Thickness;
-using WImageSource = Microsoft.UI.Xaml.Media.ImageSource;
namespace Microsoft.Maui.Controls.Platform
{
public static class ButtonExtensions
{
- public static void UpdateContentLayout(this MauiButton mauiButton, Button button)
+ public static void UpdateContentLayout(this UI.Xaml.Controls.Button mauiButton, Button button)
{
// If the Content isn't the StackPanel setup by Maui.Core then
// The user has set a custom Content or the content isn't a mix of text/images
if (mauiButton.Content is not StackPanel container)
return;
- var image = mauiButton.GetImage();
- var textBlock = mauiButton.GetTextBlock();
+ var image = mauiButton.GetContent();
+ var textBlock = mauiButton.GetContent();
// If either of these are null then the user has taken control of the content
// and we don't know how to apply our changes
@@ -31,14 +24,11 @@ public static void UpdateContentLayout(this MauiButton mauiButton, Button button
var layout = button.ContentLayout;
var spacing = layout.Spacing;
- container.HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Center;
- container.VerticalAlignment = Microsoft.UI.Xaml.VerticalAlignment.Center;
-
switch (layout.Position)
{
case Button.ButtonContentLayout.ImagePosition.Top:
container.Orientation = Orientation.Vertical;
- image.Margin = WinUIHelpers.CreateThickness(0, 0, 0, spacing);
+ image.Margin = WinUIHelpers.CreateThickness(0, 0, 0, spacing);
container.Children.Add(image);
container.Children.Add(textBlock);
break;
diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs b/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs
index 9541306e1094..19389e2d77ef 100644
--- a/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs
+++ b/src/Core/src/Handlers/Button/ButtonHandler.Windows.cs
@@ -1,46 +1,65 @@
#nullable enable
-using System.Threading.Tasks;
+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 ButtonHandler : ViewHandler
+ public partial class ButtonHandler : ViewHandler
{
- static UI.Xaml.Thickness? DefaultPadding;
- static UI.Xaml.Media.Brush? DefaultForeground;
- static UI.Xaml.Media.Brush? DefaultBackground;
-
PointerEventHandler? _pointerPressedHandler;
PointerEventHandler? _pointerReleasedHandler;
- protected override MauiButton CreateNativeView()
- => new MauiButton();
-
- void SetupDefaults(MauiButton nativeView)
- {
- DefaultPadding = (UI.Xaml.Thickness)MauiWinUIApplication.Current.Resources["ButtonPadding"];
- DefaultForeground = (UI.Xaml.Media.Brush)MauiWinUIApplication.Current.Resources["ButtonForegroundThemeBrush"];
- DefaultBackground = (UI.Xaml.Media.Brush)MauiWinUIApplication.Current.Resources["ButtonBackgroundThemeBrush"];
- }
-
- protected override void ConnectHandler(MauiButton nativeView)
+ protected override Button CreateNativeView() =>
+ new Button
+ {
+ VerticalAlignment = VerticalAlignment.Stretch,
+ HorizontalAlignment = HorizontalAlignment.Stretch,
+ Content = new StackPanel
+ {
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Center,
+ Orientation = Orientation.Horizontal,
+ Margin = WinUIHelpers.CreateThickness(0),
+ Children =
+ {
+ new Image
+ {
+ VerticalAlignment = VerticalAlignment.Center,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ Stretch = Stretch.Uniform,
+ Margin = WinUIHelpers.CreateThickness(0),
+ Visibility = UI.Xaml.Visibility.Collapsed,
+ },
+ new TextBlock
+ {
+ VerticalAlignment = VerticalAlignment.Center,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ Margin = WinUIHelpers.CreateThickness(0),
+ Visibility = UI.Xaml.Visibility.Collapsed,
+ }
+ }
+ }
+ };
+
+ protected override void ConnectHandler(Button nativeView)
{
_pointerPressedHandler = new PointerEventHandler(OnPointerPressed);
_pointerReleasedHandler = new PointerEventHandler(OnPointerReleased);
nativeView.Click += OnClick;
- nativeView.AddHandler(UI.Xaml.UIElement.PointerPressedEvent, _pointerPressedHandler, true);
- nativeView.AddHandler(UI.Xaml.UIElement.PointerReleasedEvent, _pointerReleasedHandler, true);
+ nativeView.AddHandler(UIElement.PointerPressedEvent, _pointerPressedHandler, true);
+ nativeView.AddHandler(UIElement.PointerReleasedEvent, _pointerReleasedHandler, true);
base.ConnectHandler(nativeView);
}
- protected override void DisconnectHandler(MauiButton nativeView)
+ protected override void DisconnectHandler(Button nativeView)
{
nativeView.Click -= OnClick;
- nativeView.RemoveHandler(UI.Xaml.UIElement.PointerPressedEvent, _pointerPressedHandler);
- nativeView.RemoveHandler(UI.Xaml.UIElement.PointerReleasedEvent, _pointerReleasedHandler);
+ nativeView.RemoveHandler(UIElement.PointerPressedEvent, _pointerPressedHandler);
+ nativeView.RemoveHandler(UIElement.PointerReleasedEvent, _pointerReleasedHandler);
_pointerPressedHandler = null;
_pointerReleasedHandler = null;
@@ -51,7 +70,7 @@ protected override void DisconnectHandler(MauiButton nativeView)
// This is a Windows-specific mapping
public static void MapBackground(IButtonHandler handler, IButton button)
{
- handler.TypedNativeView?.UpdateBackground(button, DefaultBackground);
+ handler.TypedNativeView?.UpdateBackground(button);
}
public static void MapText(IButtonHandler handler, IText button)
@@ -61,12 +80,12 @@ public static void MapText(IButtonHandler handler, IText button)
public static void MapTextColor(IButtonHandler handler, ITextStyle button)
{
- handler.TypedNativeView?.UpdateTextColor(button, DefaultForeground);
+ handler.TypedNativeView?.UpdateTextColor(button);
}
public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button)
{
- handler.TypedNativeView?.UpdateCharacterSpacing(button.CharacterSpacing);
+ handler.TypedNativeView?.UpdateCharacterSpacing(button);
}
public static void MapFont(IButtonHandler handler, ITextStyle button)
@@ -78,7 +97,7 @@ public static void MapFont(IButtonHandler handler, ITextStyle button)
public static void MapPadding(IButtonHandler handler, IButton button)
{
- handler.TypedNativeView?.UpdatePadding(button, DefaultPadding);
+ handler.TypedNativeView?.UpdatePadding(button);
}
public static void MapImageSource(IButtonHandler handler, IButton image) =>
@@ -87,12 +106,12 @@ public static void MapPadding(IButtonHandler handler, IButton button)
.UpdateImageSourceAsync()
.FireAndForget(handler);
- void OnSetImageSource(ImageSource? obj)
+ void OnSetImageSource(ImageSource? nativeImageSource)
{
- NativeView.UpdateImageSource(VirtualView, obj);
+ NativeView.UpdateImageSource(nativeImageSource);
}
- void OnClick(object sender, UI.Xaml.RoutedEventArgs e)
+ void OnClick(object sender, RoutedEventArgs e)
{
VirtualView?.Clicked();
VirtualView?.Released();
diff --git a/src/Core/src/Handlers/Button/ButtonHandler.cs b/src/Core/src/Handlers/Button/ButtonHandler.cs
index c1a4d31b00da..23a11ba8e215 100644
--- a/src/Core/src/Handlers/Button/ButtonHandler.cs
+++ b/src/Core/src/Handlers/Button/ButtonHandler.cs
@@ -3,7 +3,7 @@
#elif MONOANDROID
using NativeView = Google.Android.Material.Button.MaterialButton;
#elif WINDOWS
-using NativeView = Microsoft.Maui.MauiButton;
+using NativeView = Microsoft.UI.Xaml.Controls.Button;
#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID)
using NativeView = System.Object;
#endif
diff --git a/src/Core/src/Handlers/Button/IButtonHandler.cs b/src/Core/src/Handlers/Button/IButtonHandler.cs
index 7e84ad85436e..7fd23a5ecffa 100644
--- a/src/Core/src/Handlers/Button/IButtonHandler.cs
+++ b/src/Core/src/Handlers/Button/IButtonHandler.cs
@@ -3,7 +3,7 @@
#elif MONOANDROID
using NativeView = Google.Android.Material.Button.MaterialButton;
#elif WINDOWS
-using NativeView = Microsoft.Maui.MauiButton;
+using NativeView = Microsoft.UI.Xaml.Controls.Button;
#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID)
using NativeView = System.Object;
#endif
diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs
index 4489a8fd143e..855e80bf3917 100644
--- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs
+++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Windows.cs
@@ -1,111 +1,55 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Microsoft.UI.Xaml;
+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
+ public partial class ImageButtonHandler : ViewHandler
{
-
PointerEventHandler? _pointerPressedHandler;
- 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()
+ protected override Button CreateNativeView() =>
+ new Button
{
- Content = _image
+ VerticalAlignment = VerticalAlignment.Stretch,
+ HorizontalAlignment = HorizontalAlignment.Stretch,
+ Content = new Image
+ {
+ VerticalAlignment = VerticalAlignment.Center,
+ HorizontalAlignment = HorizontalAlignment.Center,
+ Stretch = Stretch.Uniform,
+ }
};
- mauiButton.Padding = WinUIHelpers.CreateThickness(0);
- mauiButton.BorderThickness = WinUIHelpers.CreateThickness(0);
- mauiButton.Background = null;
-
- return mauiButton;
- }
-
- protected override void ConnectHandler(MauiButton nativeView)
+ protected override void ConnectHandler(Button nativeView)
{
_pointerPressedHandler = new PointerEventHandler(OnPointerPressed);
nativeView.Click += OnClick;
- nativeView.AddHandler(UI.Xaml.UIElement.PointerPressedEvent, _pointerPressedHandler, true);
-
- if (_image != null)
- {
- _image.ImageFailed += OnImageFailed;
- _image.ImageOpened += OnImageOpened;
- }
+ nativeView.AddHandler(UIElement.PointerPressedEvent, _pointerPressedHandler, true);
base.ConnectHandler(nativeView);
-
- nativeView.Loaded += OnNativeViewLoaded;
- nativeView.Unloaded += OnNativeViewUnloaded;
}
- protected override void DisconnectHandler(MauiButton nativeView)
+ protected override void DisconnectHandler(Button nativeView)
{
nativeView.Click -= OnClick;
- nativeView.RemoveHandler(UI.Xaml.UIElement.PointerPressedEvent, _pointerPressedHandler);
+ nativeView.RemoveHandler(UIElement.PointerPressedEvent, _pointerPressedHandler);
_pointerPressedHandler = null;
base.DisconnectHandler(nativeView);
- if (nativeView.XamlRoot != null)
- nativeView.XamlRoot.Changed -= OnXamlRootChanged;
-
- nativeView.Loaded -= OnNativeViewLoaded;
- nativeView.Unloaded -= OnNativeViewUnloaded;
-
SourceLoader.Reset();
}
- void OnImageOpened(object sender, RoutedEventArgs e)
- {
-
- }
-
- void OnImageFailed(object sender, ExceptionRoutedEventArgs e)
- {
- }
-
- void OnSetImageSource(ImageSource? obj)
- {
- if (NativeView.Content is Image i)
- i.Source = obj;
- }
-
- 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)
+ void OnSetImageSource(ImageSource? nativeImageSource)
{
- UpdateValue(nameof(IImage.Source));
+ NativeView.UpdateImageSource(nativeImageSource);
}
- void OnClick(object sender, UI.Xaml.RoutedEventArgs e)
+ void OnClick(object sender, RoutedEventArgs e)
{
VirtualView?.Clicked();
VirtualView?.Released();
@@ -116,4 +60,4 @@ void OnPointerPressed(object sender, PointerRoutedEventArgs e)
VirtualView?.Pressed();
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs
index 0a06774574c8..307c0eb39b90 100644
--- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs
+++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs
@@ -1,18 +1,20 @@
using System;
-using System.Collections.Generic;
-using System.Text;
#if __IOS__ || MACCATALYST
using NativeImage = UIKit.UIImage;
+using NativeImageView = UIKit.UIImageView;
using NativeView = UIKit.UIButton;
#elif MONOANDROID
using NativeImage = Android.Graphics.Drawables.Drawable;
+using NativeImageView = Android.Widget.ImageView;
using NativeView = AndroidX.AppCompat.Widget.AppCompatImageButton;
#elif WINDOWS
using NativeImage = Microsoft.UI.Xaml.Media.ImageSource;
+using NativeImageView = Microsoft.UI.Xaml.Controls.Image;
using NativeView = Microsoft.UI.Xaml.FrameworkElement;
#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID)
-using NativeView = System.Object;
using NativeImage = System.Object;
+using NativeImageView = System.Object;
+using NativeView = System.Object;
#endif
namespace Microsoft.Maui.Handlers
@@ -38,15 +40,14 @@ public ImageButtonHandler(IPropertyMapper mapper) : base(mapper ?? Mapper)
IImage IImageHandler.TypedVirtualView => VirtualView;
+ NativeImageView IImageHandler.TypedNativeView =>
#if __IOS__
- UIKit.UIImageView IImageHandler.TypedNativeView => NativeView.ImageView;
+ NativeView.ImageView;
#elif WINDOWS
- UI.Xaml.Controls.Image IImageHandler.TypedNativeView => NativeView.GetImage() ?? (UI.Xaml.Controls.Image)NativeView.Content;
-#elif __ANDROID__
- Android.Widget.ImageView IImageHandler.TypedNativeView => NativeView;
+ NativeView.GetContent() ?? throw new InvalidOperationException("ImageButton did not contain an Image element.");
#else
- object IImageHandler.TypedNativeView => NativeView;
+ NativeView;
#endif
ImageSourcePartLoader IImageHandler.SourceLoader => SourceLoader;
}
-}
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/Windows/ButtonExtensions.cs b/src/Core/src/Platform/Windows/ButtonExtensions.cs
index 17fc77ca2eb1..02a936d26cc0 100644
--- a/src/Core/src/Platform/Windows/ButtonExtensions.cs
+++ b/src/Core/src/Platform/Windows/ButtonExtensions.cs
@@ -1,127 +1,141 @@
#nullable enable
-using System.Threading.Tasks;
+using Microsoft.Maui.Graphics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using WImage = Microsoft.UI.Xaml.Controls.Image;
-using WStretch = Microsoft.UI.Xaml.Media.Stretch;
-using WThickness = Microsoft.UI.Xaml.Thickness;
using WImageSource = Microsoft.UI.Xaml.Media.ImageSource;
namespace Microsoft.Maui
{
public static class ButtonExtensions
{
- public static void UpdateText(this MauiButton nativeButton, IText textButton)
+ public static void UpdateText(this Button nativeButton, IText text)
{
- if (textButton is IButton button)
- UpdateContent(nativeButton, button, nativeButton.GetImage());
- else
- nativeButton.Content = textButton.Text;
- }
-
- 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, ITextStyle button) =>
- nativeButton.UpdateCharacterSpacing((int)button.CharacterSpacing);
-
- public static void UpdateImageSource(this MauiButton nativeButton, IButton button, WImageSource? nativeImageSource)
- {
- UpdateContent(nativeButton, button, nativeImageSource);
+ if (nativeButton.GetContent() is TextBlock textBlock)
+ {
+ var actualText = text.Text;
+ textBlock.Text = actualText;
+ textBlock.Visibility = string.IsNullOrEmpty(actualText)
+ ? UI.Xaml.Visibility.Collapsed
+ : UI.Xaml.Visibility.Visible;
+ }
}
- static void UpdateContent(this MauiButton nativeButton, IButton button, object? content)
+ public static void UpdateBackground(this Button nativeButton, IButton button)
{
- WImage? image = null;
-
- var text = (button as IText)?.Text;
-
- if (content is WImageSource nativeImageSource)
+ var brush = button.Background?.ToNative();
+ if (brush is null)
{
- var imageSourceSize = nativeImageSource.GetImageSourceSize();
- image = nativeButton.GetImage() ?? new();
- image.Source = nativeImageSource;
- image.Width = imageSourceSize.Width;
- image.Height = imageSourceSize.Height;
-
- // BitmapImage is a special case that has an event when the image is loaded
- // when this happens, we want to resize the button
- if (nativeImageSource is BitmapImage bitmapImage)
- {
- bitmapImage.ImageOpened += OnImageOpened;
-
- void OnImageOpened(object sender, RoutedEventArgs e)
- {
- bitmapImage.ImageOpened -= OnImageOpened;
-
- var actualImageSourceSize = nativeImageSource.GetImageSourceSize();
- image.Width = actualImageSourceSize.Width;
- image.Height = actualImageSourceSize.Height;
- };
- }
+ nativeButton.Resources.Remove("ButtonBackground");
+ nativeButton.Resources.Remove("ButtonBackgroundPointerOver");
+ nativeButton.Resources.Remove("ButtonBackgroundPressed");
+ nativeButton.Resources.Remove("ButtonBackgroundDisabled");
}
- else if (content is WImage contentImage)
- {
- image = contentImage;
- }
- // This means the users image hasn't loaded yet but we still want to setup the container for the user
- else if (button is IImageButton ib && ib.Source != null)
+ else
{
- image = nativeButton.GetImage() ?? new();
+ nativeButton.Resources["ButtonBackground"] = brush;
+ nativeButton.Resources["ButtonBackgroundPointerOver"] = brush;
+ nativeButton.Resources["ButtonBackgroundPressed"] = brush;
+ nativeButton.Resources["ButtonBackgroundDisabled"] = brush;
}
+ }
- // No text, just the image
- if (string.IsNullOrEmpty(text))
+ public static void UpdateTextColor(this Button nativeButton, ITextStyle button)
+ {
+ var brush = button.TextColor?.ToNative();
+ if (brush is null)
{
- nativeButton.Content = image;
- return;
+ nativeButton.Resources.Remove("ButtonForeground");
+ nativeButton.Resources.Remove("ButtonForegroundPointerOver");
+ nativeButton.Resources.Remove("ButtonForegroundPressed");
+ nativeButton.Resources.Remove("ButtonForegroundDisabled");
}
- else if (image == null)
+ else
{
- nativeButton.Content = text;
- return;
+ nativeButton.Resources["ButtonForeground"] = brush;
+ nativeButton.Resources["ButtonForegroundPointerOver"] = brush;
+ nativeButton.Resources["ButtonForegroundPressed"] = brush;
+ nativeButton.Resources["ButtonForegroundDisabled"] = brush;
}
+ }
+
+ public static void UpdatePadding(this Button nativeButton, IPadding padding) =>
+ nativeButton.UpdatePadding(padding, nativeButton.GetResource("ButtonPadding"));
+
+ public static void UpdateCharacterSpacing(this Button nativeButton, ITextStyle button)
+ {
+ var characterSpacing = button.CharacterSpacing.ToEm();
- if (image != null)
+ nativeButton.CharacterSpacing = characterSpacing;
+
+ if (nativeButton.GetContent() is TextBlock textBlock)
+ textBlock.CharacterSpacing = characterSpacing;
+ }
+
+ public static void UpdateImageSource(this Button nativeButton, WImageSource? nativeImageSource)
+ {
+ if (nativeButton.GetContent() is WImage nativeImage)
{
- image.VerticalAlignment = VerticalAlignment.Center;
- image.HorizontalAlignment = HorizontalAlignment.Center;
- image.Stretch = WStretch.Uniform;
+ nativeImage.Source = nativeImageSource;
- if (nativeButton.Content is not StackPanel)
+ if (nativeImageSource is not null)
{
- // Both image and text, so we need to build a container for them
- var container = CreateButtonContentContainer(image, text);
- nativeButton.Content = container;
+ // set the base size if we can
+ {
+ var imageSourceSize = nativeImageSource.GetImageSourceSize(nativeButton);
+ nativeImage.Width = imageSourceSize.Width;
+ nativeImage.Height = imageSourceSize.Height;
+ }
+
+ // BitmapImage is a special case that has an event when the image is loaded
+ // when this happens, we want to resize the button
+ if (nativeImageSource is BitmapImage bitmapImage)
+ {
+ bitmapImage.ImageOpened += OnImageOpened;
+
+ void OnImageOpened(object sender, RoutedEventArgs e)
+ {
+ bitmapImage.ImageOpened -= OnImageOpened;
+
+ // check if the image that just loaded is still the current image
+ var actualImageSource = sender as BitmapImage;
+ if (actualImageSource is not null && nativeImage.Source == actualImageSource)
+ {
+ // do the actual resize
+ var imageSourceSize = actualImageSource.GetImageSourceSize(nativeButton);
+ nativeImage.Width = imageSourceSize.Width;
+ nativeImage.Height = imageSourceSize.Height;
+ }
+ };
+ }
}
+
+ nativeImage.Visibility = nativeImageSource == null
+ ? UI.Xaml.Visibility.Collapsed
+ : UI.Xaml.Visibility.Visible;
}
}
- internal static StackPanel CreateButtonContentContainer(WImage image, string text)
+ public static T? GetContent(this Button nativeButton)
+ where T : FrameworkElement
{
- var container = new StackPanel();
-
- var textBlock = new TextBlock
- {
- Text = text,
- VerticalAlignment = VerticalAlignment.Center,
- HorizontalAlignment = HorizontalAlignment.Center
- };
-
- container.HorizontalAlignment = HorizontalAlignment.Center;
- container.VerticalAlignment = VerticalAlignment.Center;
+ if (nativeButton.Content is null)
+ return null;
- // TODO: Use ButtonContentLayout when available
- // Defaults to image on the left
- container.Orientation = Orientation.Horizontal;
- image.Margin = new WThickness(0);
+ if (nativeButton.Content is T t)
+ return t;
- container.Children.Add(image);
- container.Children.Add(textBlock);
+ if (nativeButton.Content is Panel panel)
+ {
+ foreach (var child in panel.Children)
+ {
+ if (child is T c)
+ return c;
+ }
+ }
- return container;
+ return null;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/Windows/FrameworkElementExtensions.cs b/src/Core/src/Platform/Windows/FrameworkElementExtensions.cs
index 5451033ac2e8..65a3bb7f1dd0 100644
--- a/src/Core/src/Platform/Windows/FrameworkElementExtensions.cs
+++ b/src/Core/src/Platform/Windows/FrameworkElementExtensions.cs
@@ -1,15 +1,15 @@
#nullable enable
using System;
-using System.Linq;
-using Microsoft.UI.Xaml;
using System.Collections.Concurrent;
-using Microsoft.UI.Xaml.Media;
using System.Collections.Generic;
+using System.Linq;
using System.Reflection;
+using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
using WBinding = Microsoft.UI.Xaml.Data.Binding;
-using WBrush = Microsoft.UI.Xaml.Media.Brush;
using WBindingExpression = Microsoft.UI.Xaml.Data.BindingExpression;
+using WBrush = Microsoft.UI.Xaml.Media.Brush;
namespace Microsoft.Maui
{
@@ -18,6 +18,14 @@ internal static class FrameworkElementExtensions
static readonly Lazy> ForegroundProperties =
new Lazy>(() => new ConcurrentDictionary());
+ public static T? GetResource(this FrameworkElement element, string key, T? def = default)
+ {
+ if (element.Resources.TryGetValue(key, out var resource))
+ return (T?)resource;
+
+ return def;
+ }
+
public static WBrush GetForeground(this FrameworkElement element)
{
if (element == null)
diff --git a/src/Core/src/Platform/Windows/ImageExtensions.cs b/src/Core/src/Platform/Windows/ImageExtensions.cs
index f1c542a3affe..c7a254f396b1 100644
--- a/src/Core/src/Platform/Windows/ImageExtensions.cs
+++ b/src/Core/src/Platform/Windows/ImageExtensions.cs
@@ -1,6 +1,7 @@
using System;
using Microsoft.Graphics.Canvas.UI.Xaml;
using Microsoft.Maui.Graphics;
+using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
@@ -8,7 +9,7 @@ namespace Microsoft.Maui
{
public static class ImageExtensions
{
- public static Size GetImageSourceSize(this ImageSource source)
+ public static Size GetImageSourceSize(this ImageSource source, FrameworkElement? element = null)
{
if (source is null)
{
@@ -16,10 +17,12 @@ public static Size GetImageSourceSize(this ImageSource source)
}
else if (source is BitmapSource bitmap)
{
+ var rasterizationScale = element?.XamlRoot?.RasterizationScale ?? 1;
+
return new Size
{
- Width = bitmap.PixelWidth,
- Height = bitmap.PixelHeight
+ Width = bitmap.PixelWidth / rasterizationScale,
+ Height = bitmap.PixelHeight / rasterizationScale
};
}
else if (source is CanvasImageSource canvas)
diff --git a/src/Core/src/Platform/Windows/MauiButton.cs b/src/Core/src/Platform/Windows/MauiButton.cs
deleted file mode 100644
index 03233a67d859..000000000000
--- a/src/Core/src/Platform/Windows/MauiButton.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-#nullable enable
-using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Controls;
-using WBrush = Microsoft.UI.Xaml.Media.Brush;
-using WContentPresenter = Microsoft.UI.Xaml.Controls.ContentPresenter;
-using WImage = Microsoft.UI.Xaml.Controls.Image;
-
-namespace Microsoft.Maui
-{
- // This is needed by WinUI because of
- // https://github.com/microsoft/microsoft-ui-xaml/issues/2698#issuecomment-648751713
- [Microsoft.UI.Xaml.Data.Bindable]
- public class MauiButton : Button
- {
- public static readonly DependencyProperty BorderRadiusProperty =
- DependencyProperty.Register(nameof(BorderRadius), typeof(int), typeof(MauiButton),
- new PropertyMetadata(default(int), OnBorderRadiusChanged));
-
- public static readonly DependencyProperty BackgroundColorProperty =
- DependencyProperty.Register(nameof(BackgroundColor), typeof(WBrush), typeof(MauiButton),
- new PropertyMetadata(default(WBrush), OnBackgroundColorChanged));
-
- WContentPresenter? _contentPresenter;
- Grid? _rootGrid;
-
- public WBrush BackgroundColor
- {
- get
- {
- return (WBrush)GetValue(BackgroundColorProperty);
- }
- set
- {
- SetValue(BackgroundColorProperty, value);
- }
- }
-
- public int BorderRadius
- {
- get
- {
- return (int)GetValue(BorderRadiusProperty);
- }
- set
- {
- SetValue(BorderRadiusProperty, value);
- }
- }
-
- protected override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
-
- _contentPresenter = GetTemplateChild("ContentPresenter") as WContentPresenter;
- _rootGrid = GetTemplateChild("RootGrid") as Grid;
-
- UpdateBackgroundColor();
- UpdateBorderRadius();
- }
-
- static void OnBackgroundColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- ((MauiButton)d).UpdateBackgroundColor();
- }
-
- static void OnBorderRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- ((MauiButton)d).UpdateBorderRadius();
- }
-
- void UpdateBackgroundColor()
- {
- if (BackgroundColor == null)
- BackgroundColor = Background;
-
- if (_contentPresenter != null)
- _contentPresenter.Background = BackgroundColor;
-
- Background = new UI.Xaml.Media.SolidColorBrush(UI.Colors.Transparent);
- }
-
- void UpdateBorderRadius()
- {
- var radius = BorderRadius == -1 ? 0 : BorderRadius;
- var cornerRadius = WinUIHelpers.CreateCornerRadius(radius);
-
- if (_contentPresenter != null)
- _contentPresenter.CornerRadius = cornerRadius;
-
- if (_rootGrid != null)
- _rootGrid.CornerRadius = cornerRadius;
- }
-
- public void UpdateCharacterSpacing(double characterSpacing)
- {
- CharacterSpacing = characterSpacing.ToEm();
-
- if (_contentPresenter != null)
- _contentPresenter.CharacterSpacing = CharacterSpacing;
-
- var textBlock = GetTextBlock();
-
- if (textBlock != null)
- textBlock.CharacterSpacing = CharacterSpacing;
- }
-
- public TextBlock? GetTextBlock() => GetContent();
-
-
- public WImage? GetImage() => GetContent();
-
- internal T? GetContent()
- {
- if (Content is T t)
- {
- return t;
- }
-
- if (Content is StackPanel sp)
- {
- foreach (var item in sp.Children)
- {
- if (item is T tChild)
- {
- return tChild;
- }
- }
- }
-
- return default;
- }
- }
-}
diff --git a/src/Core/src/Platform/Windows/Styles/MauiButtonStyle.xaml b/src/Core/src/Platform/Windows/Styles/MauiButtonStyle.xaml
deleted file mode 100644
index 3fa9bd813f53..000000000000
--- a/src/Core/src/Platform/Windows/Styles/MauiButtonStyle.xaml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Core/src/Platform/Windows/Styles/Resources.xaml b/src/Core/src/Platform/Windows/Styles/Resources.xaml
index 7c07331ac6ef..153b661093bd 100644
--- a/src/Core/src/Platform/Windows/Styles/Resources.xaml
+++ b/src/Core/src/Platform/Windows/Styles/Resources.xaml
@@ -7,7 +7,6 @@
-
diff --git a/src/Core/tests/DeviceTests/Core.DeviceTests.csproj b/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
index accb6a4eb95c..ed73aaa56d4b 100644
--- a/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
+++ b/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
@@ -62,6 +62,7 @@
+
diff --git a/src/Core/tests/DeviceTests/Handlers/Button/ButtonHandlerTests.Windows.cs b/src/Core/tests/DeviceTests/Handlers/Button/ButtonHandlerTests.Windows.cs
new file mode 100644
index 000000000000..efb16b953400
--- /dev/null
+++ b/src/Core/tests/DeviceTests/Handlers/Button/ButtonHandlerTests.Windows.cs
@@ -0,0 +1,89 @@
+#nullable enable
+using System.Threading.Tasks;
+using Microsoft.Maui.DeviceTests.Stubs;
+using Microsoft.Maui.Graphics;
+using Microsoft.Maui.Handlers;
+using Microsoft.UI.Xaml.Automation.Peers;
+using Microsoft.UI.Xaml.Automation.Provider;
+using Microsoft.UI.Xaml.Controls;
+using Xunit;
+
+namespace Microsoft.Maui.DeviceTests
+{
+ public partial class ButtonHandlerTests
+ {
+ [Fact(DisplayName = "CharacterSpacing Initializes Correctly")]
+ public async Task CharacterSpacingInitializesCorrectly()
+ {
+ var xplatCharacterSpacing = 4;
+
+ var button = new ButtonStub()
+ {
+ CharacterSpacing = xplatCharacterSpacing,
+ Text = "Test"
+ };
+
+ float expectedValue = button.CharacterSpacing.ToEm();
+
+ var values = await GetValueAsync(button, (handler) =>
+ {
+ return new
+ {
+ ViewValue = button.CharacterSpacing,
+ NativeViewValue = GetNativeCharacterSpacing(handler)
+ };
+ });
+
+ Assert.Equal(xplatCharacterSpacing, values.ViewValue);
+ Assert.Equal(expectedValue, values.NativeViewValue);
+ }
+
+ [Fact(DisplayName = "Button Padding Initializing")]
+ public async Task PaddingInitializesCorrectly()
+ {
+ var expected = new Thickness(5, 10, 15, 20);
+
+ var button = new ButtonStub()
+ {
+ Text = "Test",
+ Padding = expected
+ };
+
+ var actual = await GetValueAsync(button, GetNativePadding);
+
+ Assert.Equal(expected.Left, actual.Left);
+ Assert.Equal(expected.Top, actual.Top);
+ Assert.Equal(expected.Right, actual.Right);
+ Assert.Equal(expected.Bottom, actual.Bottom);
+ }
+
+ UI.Xaml.Controls.Button GetNativeButton(ButtonHandler buttonHandler) =>
+ buttonHandler.NativeView;
+
+ string? GetNativeText(ButtonHandler buttonHandler) =>
+ GetNativeButton(buttonHandler).GetContent()?.Text;
+
+ Color GetNativeTextColor(ButtonHandler buttonHandler) =>
+ ((UI.Xaml.Media.SolidColorBrush)GetNativeButton(buttonHandler).Foreground).Color.ToColor();
+
+ UI.Xaml.Thickness GetNativePadding(ButtonHandler buttonHandler) =>
+ GetNativeButton(buttonHandler).Padding;
+
+ Task PerformClick(IButton button)
+ {
+ return InvokeOnMainThreadAsync(() =>
+ {
+ var nativeButton = GetNativeButton(CreateHandler(button));
+ var ap = new ButtonAutomationPeer(nativeButton);
+ var ip = ap.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
+ ip?.Invoke();
+ });
+ }
+
+ double GetNativeCharacterSpacing(ButtonHandler buttonHandler) =>
+ GetNativeButton(buttonHandler).GetContent()?.CharacterSpacing ?? 0;
+
+ bool ImageSourceLoaded(ButtonHandler buttonHandler) =>
+ GetNativeButton(buttonHandler).GetContent()?.Source != null;
+ }
+}
\ No newline at end of file