295 строки
8.6 KiB
C#
295 строки
8.6 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using Windows.UI.Xaml;
|
|
using Windows.UI.Xaml.Controls;
|
|
using Windows.UI.Xaml.Media;
|
|
using Windows.UI.Xaml.Media.Imaging;
|
|
using Xamarin.Forms.Internals;
|
|
using WThickness = Windows.UI.Xaml.Thickness;
|
|
using WButton = Windows.UI.Xaml.Controls.Button;
|
|
using WImage = Windows.UI.Xaml.Controls.Image;
|
|
using Windows.UI.Xaml.Input;
|
|
|
|
namespace Xamarin.Forms.Platform.UWP
|
|
{
|
|
public class ButtonRenderer : ViewRenderer<Button, FormsButton>
|
|
{
|
|
bool _fontApplied;
|
|
|
|
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
|
|
{
|
|
base.OnElementChanged(e);
|
|
|
|
if (e.NewElement != null)
|
|
{
|
|
if (Control == null)
|
|
{
|
|
var button = new FormsButton();
|
|
|
|
button.Click += OnButtonClick;
|
|
button.AddHandler(PointerPressedEvent, new PointerEventHandler(OnPointerPressed), true);
|
|
button.Loaded += ButtonOnLoaded;
|
|
|
|
SetNativeControl(button);
|
|
}
|
|
else
|
|
{
|
|
WireUpFormsVsm();
|
|
}
|
|
|
|
UpdateContent();
|
|
|
|
//TODO: We may want to revisit this strategy later. If a user wants to reset any of these to the default, the UI won't update.
|
|
if (Element.IsSet(VisualElement.BackgroundColorProperty) && Element.BackgroundColor != (Color)VisualElement.BackgroundColorProperty.DefaultValue)
|
|
UpdateBackground();
|
|
|
|
if (Element.IsSet(Button.TextColorProperty) && Element.TextColor != (Color)Button.TextColorProperty.DefaultValue)
|
|
UpdateTextColor();
|
|
|
|
if (Element.IsSet(Button.BorderColorProperty) && Element.BorderColor != (Color)Button.BorderColorProperty.DefaultValue)
|
|
UpdateBorderColor();
|
|
|
|
if (Element.IsSet(Button.CharacterSpacingProperty))
|
|
UpdateCharacterSpacing();
|
|
|
|
if (Element.IsSet(Button.BorderWidthProperty) && Element.BorderWidth != (double)Button.BorderWidthProperty.DefaultValue)
|
|
UpdateBorderWidth();
|
|
|
|
if (Element.IsSet(Button.CornerRadiusProperty) && Element.CornerRadius != (int)Button.CornerRadiusProperty.DefaultValue)
|
|
UpdateBorderRadius();
|
|
|
|
// By default Button loads width padding 8, 4, 8 ,4
|
|
if (Element.IsSet(Button.PaddingProperty))
|
|
UpdatePadding();
|
|
|
|
UpdateFont();
|
|
}
|
|
}
|
|
|
|
void ButtonOnLoaded(object o, RoutedEventArgs routedEventArgs)
|
|
{
|
|
WireUpFormsVsm();
|
|
}
|
|
|
|
void WireUpFormsVsm()
|
|
{
|
|
if (Element.UseFormsVsm())
|
|
{
|
|
InterceptVisualStateManager.Hook(Control.GetFirstDescendant<Windows.UI.Xaml.Controls.Grid>(), Control, Element);
|
|
}
|
|
}
|
|
|
|
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
base.OnElementPropertyChanged(sender, e);
|
|
|
|
if (e.PropertyName == Button.TextProperty.PropertyName || e.PropertyName == Button.ImageSourceProperty.PropertyName)
|
|
{
|
|
UpdateContent();
|
|
}
|
|
else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
|
|
{
|
|
UpdateCharacterSpacing();
|
|
}
|
|
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
|
|
{
|
|
UpdateBackground();
|
|
}
|
|
else if (e.PropertyName == Button.TextColorProperty.PropertyName)
|
|
{
|
|
UpdateTextColor();
|
|
}
|
|
else if (e.PropertyName == Button.FontProperty.PropertyName)
|
|
{
|
|
UpdateFont();
|
|
}
|
|
else if (e.PropertyName == Button.BorderColorProperty.PropertyName)
|
|
{
|
|
UpdateBorderColor();
|
|
}
|
|
else if (e.PropertyName == Button.BorderWidthProperty.PropertyName)
|
|
{
|
|
UpdateBorderWidth();
|
|
}
|
|
else if (e.PropertyName == Button.CornerRadiusProperty.PropertyName)
|
|
{
|
|
UpdateBorderRadius();
|
|
}
|
|
else if (e.PropertyName == Button.PaddingProperty.PropertyName)
|
|
{
|
|
UpdatePadding();
|
|
}
|
|
}
|
|
|
|
protected override void UpdateBackgroundColor()
|
|
{
|
|
// Button is a special case; we don't want to set the Control's background
|
|
// because it goes outside the bounds of the Border/ContentPresenter,
|
|
// which is where we might change the BorderRadius to create a rounded shape.
|
|
return;
|
|
}
|
|
|
|
protected override bool PreventGestureBubbling { get; set; } = true;
|
|
|
|
void OnButtonClick(object sender, RoutedEventArgs e)
|
|
{
|
|
((IButtonController)Element)?.SendReleased();
|
|
((IButtonController)Element)?.SendClicked();
|
|
}
|
|
|
|
void OnPointerPressed(object sender, RoutedEventArgs e)
|
|
{
|
|
((IButtonController)Element)?.SendPressed();
|
|
}
|
|
|
|
void UpdateBackground()
|
|
{
|
|
Control.BackgroundColor = Element.BackgroundColor != Color.Default ? Element.BackgroundColor.ToBrush() : (Brush)Windows.UI.Xaml.Application.Current.Resources["ButtonBackgroundThemeBrush"];
|
|
}
|
|
|
|
void UpdateBorderColor()
|
|
{
|
|
Control.BorderBrush = Element.BorderColor != Color.Default ? Element.BorderColor.ToBrush() : (Brush)Windows.UI.Xaml.Application.Current.Resources["ButtonBorderThemeBrush"];
|
|
}
|
|
|
|
void UpdateBorderRadius()
|
|
{
|
|
Control.BorderRadius = Element.CornerRadius;
|
|
}
|
|
|
|
void UpdateBorderWidth()
|
|
{
|
|
Control.BorderThickness = Element.BorderWidth == (double)Button.BorderWidthProperty.DefaultValue ? new WThickness(3) : new WThickness(Element.BorderWidth);
|
|
}
|
|
|
|
void UpdateCharacterSpacing()
|
|
{
|
|
Control.UpdateCharacterSpacing(Element.CharacterSpacing.ToEm());
|
|
}
|
|
|
|
async void UpdateContent()
|
|
{
|
|
var text = Element.Text;
|
|
var elementImage = await Element.ImageSource.ToWindowsImageSourceAsync();
|
|
|
|
// No image, just the text
|
|
if (elementImage == null)
|
|
{
|
|
Control.Content = text;
|
|
Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
|
|
return;
|
|
}
|
|
|
|
var size = elementImage.GetImageSourceSize();
|
|
var image = new WImage
|
|
{
|
|
Source = elementImage,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
Stretch = Stretch.Uniform,
|
|
Width = size.Width,
|
|
Height = size.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 (elementImage is BitmapImage bmp)
|
|
{
|
|
bmp.ImageOpened += (sender, args) => {
|
|
var actualSize = bmp.GetImageSourceSize();
|
|
image.Width = actualSize.Width;
|
|
image.Height = actualSize.Height;
|
|
Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
|
|
};
|
|
}
|
|
|
|
// No text, just the image
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
Control.Content = image;
|
|
Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
|
|
return;
|
|
}
|
|
|
|
// Both image and text, so we need to build a container for them
|
|
Control.Content = CreateContentContainer(Element.ContentLayout, image, text);
|
|
Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
|
|
}
|
|
|
|
static StackPanel CreateContentContainer(Button.ButtonContentLayout layout, WImage image, string text)
|
|
{
|
|
var container = new StackPanel();
|
|
var textBlock = new TextBlock {
|
|
Text = text,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
HorizontalAlignment = HorizontalAlignment.Center
|
|
};
|
|
|
|
var spacing = layout.Spacing;
|
|
|
|
container.HorizontalAlignment = HorizontalAlignment.Center;
|
|
container.VerticalAlignment = VerticalAlignment.Center;
|
|
|
|
switch (layout.Position)
|
|
{
|
|
case Button.ButtonContentLayout.ImagePosition.Top:
|
|
container.Orientation = Orientation.Vertical;
|
|
image.Margin = new WThickness(0, 0, 0, spacing);
|
|
container.Children.Add(image);
|
|
container.Children.Add(textBlock);
|
|
break;
|
|
case Button.ButtonContentLayout.ImagePosition.Bottom:
|
|
container.Orientation = Orientation.Vertical;
|
|
image.Margin = new WThickness(0, spacing, 0, 0);
|
|
container.Children.Add(textBlock);
|
|
container.Children.Add(image);
|
|
break;
|
|
case Button.ButtonContentLayout.ImagePosition.Right:
|
|
container.Orientation = Orientation.Horizontal;
|
|
image.Margin = new WThickness(spacing, 0, 0, 0);
|
|
container.Children.Add(textBlock);
|
|
container.Children.Add(image);
|
|
break;
|
|
default:
|
|
// Defaults to image on the left
|
|
container.Orientation = Orientation.Horizontal;
|
|
image.Margin = new WThickness(0, 0, spacing, 0);
|
|
container.Children.Add(image);
|
|
container.Children.Add(textBlock);
|
|
break;
|
|
}
|
|
|
|
return container;
|
|
}
|
|
|
|
void UpdateFont()
|
|
{
|
|
if (Control == null || Element == null)
|
|
return;
|
|
|
|
if (Element.Font == Font.Default && !_fontApplied)
|
|
return;
|
|
|
|
Font fontToApply = Element.Font == Font.Default ? Font.SystemFontOfSize(NamedSize.Medium) : Element.Font;
|
|
|
|
Control.ApplyFont(fontToApply);
|
|
_fontApplied = true;
|
|
}
|
|
|
|
void UpdateTextColor()
|
|
{
|
|
Control.Foreground = Element.TextColor != Color.Default ? Element.TextColor.ToBrush() : (Brush)Windows.UI.Xaml.Application.Current.Resources["DefaultTextForegroundThemeBrush"];
|
|
}
|
|
|
|
void UpdatePadding()
|
|
{
|
|
Control.Padding = new WThickness(
|
|
Element.Padding.Left,
|
|
Element.Padding.Top,
|
|
Element.Padding.Right,
|
|
Element.Padding.Bottom
|
|
);
|
|
}
|
|
}
|
|
}
|