В прошлой теме в элемент HeaderView были добавлены свойства. Теперь добавим также и события. В частности, событие нажатия.
Для вызова события нам необязательно писать какой-то код в самом элементе. В нем мы можем только определить нужные события, а затем их генерировать в рендерере.
Так, определим в классе HeaderView событие TappedOrClickEvent
:
using System; using Xamarin.Forms; namespace HelloApp { public class HeaderView : View { public event EventHandler TappedOrClickEvent; public void FireClick(EventArgs e) { if (this.TappedOrClickEvent != null) this.TappedOrClickEvent(this, e); } public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(HeaderView), string.Empty); public string Text { set { SetValue(TextProperty, value); } get { return (string)GetValue(TextProperty); } } public static readonly BindableProperty TextColorProperty = BindableProperty.Create("TextColor", typeof(Color), typeof(HeaderView), Color.Default); public Color TextColor { set { SetValue(TextColorProperty, value); } get { return (Color)GetValue(TextColorProperty); } } } }
На странице используем это событие:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:HelloApp;assembly=HelloApp" x:Class="HelloApp.MainPage"> <StackLayout> <local:HeaderView x:Name="headerView1" Text="Simple HeaderView" TappedOrClickEvent="ChangeText"></local:HeaderView> </StackLayout> </ContentPage>
А в файле кода страницы пропишем обработчик:
using System; using Xamarin.Forms; namespace HelloApp { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } int clicks = 0; private void ChangeText(object sender, EventArgs e) { HeaderView hView = sender as HeaderView; hView.Text = $"{++clicks} clicks"; } } }
Теперь изменим рендерер для Android:
using Xamarin.Forms; using Xamarin.Forms.Platform.Android; using Android.Util; using Android.Widget; using HelloApp; using HelloApp.Droid; using System.ComponentModel; [assembly: ExportRenderer(typeof(HeaderView), typeof(HeaderViewRenderer))] namespace HelloApp.Droid { public class HeaderViewRenderer : ViewRenderer<HeaderView, TextView> { public HeaderViewRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<HeaderView> args) { base.OnElementChanged(args); if (Control == null) { // создаем и настраиваем элемент TextView textView = new TextView(Context); textView.SetTextSize(ComplexUnitType.Dip, 28); textView.Touch += TextView_Touch; // устанавливаем элемент для класса из Portable-проекта SetNativeControl(textView); // установка свойств if (args.NewElement != null) { SetText(); SetTextColor(); } } } private void TextView_Touch(object sender, TouchEventArgs e) { if (Element != null) Element.FireClick(System.EventArgs.Empty); } // изменения свойства protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == HeaderView.TextColorProperty.PropertyName) { SetTextColor(); } else if (e.PropertyName == HeaderView.TextProperty.PropertyName) { SetText(); } } private void SetText() { Control.Text = Element.Text; } private void SetTextColor() { Android.Graphics.Color andrColor = Android.Graphics.Color.Gray; if (Element.TextColor != Xamarin.Forms.Color.Default) { Xamarin.Forms.Color color = Element.TextColor; andrColor = Android.Graphics.Color.Argb( (byte)(color.A * 255), (byte)(color.R * 255), (byte)(color.G * 255), (byte)(color.B * 255)); } Control.SetTextColor(andrColor); } } }
Ключевым моментом для обработки события здесь является обработка события Touch нативного элемента TextView. В его обработчике по сути мы переадресуем вызовы элементу HeaderView:
Element.FireClick(System.EventArgs.Empty);
Это общая схема обработки событий, которая работает вне зависимости от события элемента: в обработчиках событий нативного элемента мы генерируем события элемента из Xamarin.Forms.
Также изменим код рендерера для iOS:
using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; using UIKit; using HelloApp; using HelloApp.iOS; using System.ComponentModel; [assembly: ExportRenderer(typeof(HeaderView), typeof(HeaderViewRenderer))] namespace HelloApp.iOS { public class HeaderViewRenderer : ViewRenderer<HeaderView, UILabel> { UITapGestureRecognizer tapGestureRecognizer; protected override void OnElementChanged(ElementChangedEventArgs<HeaderView> args) { base.OnElementChanged(args); if (Control == null) { UILabel uilabel = new UILabel { Font = UIFont.SystemFontOfSize(25) }; tapGestureRecognizer = new UITapGestureRecognizer(() => { OnHeaderViewTapped(); }); uilabel.AddGestureRecognizer(tapGestureRecognizer); uilabel.UserInteractionEnabled = true; SetNativeControl(uilabel); } if (args.NewElement != null) { SetText(); SetTextColor(); } } private void OnHeaderViewTapped() { if(Element!=null) { Element.FireClick(System.EventArgs.Empty); } } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == HeaderView.TextColorProperty.PropertyName) { SetTextColor(); } else if (e.PropertyName == HeaderView.TextProperty.PropertyName) { SetText(); } } private void SetText() { Control.Text = Element.Text; } private void SetTextColor() { UIColor iosColor = UIColor.Gray; if (Element.TextColor != Xamarin.Forms.Color.Default) { Xamarin.Forms.Color color = Element.TextColor; iosColor = UIColor.FromRGBA( (byte)(color.R * 255), (byte)(color.G * 255), (byte)(color.B * 255), (byte)(color.A * 255)); } Control.TextColor = iosColor; } } }
Здесь для обработки нажатия используется класс UITapGestureRecognizer.
И изменим код рендерера для UWP:
using Xamarin.Forms.Platform.UWP; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using HelloApp; using HelloApp.UWP; using System.ComponentModel; [assembly: ExportRenderer(typeof(HeaderView), typeof(HeaderViewRenderer))] namespace HelloApp.UWP { public class HeaderViewRenderer : ViewRenderer<HeaderView, TextBlock> { protected override void OnElementChanged(ElementChangedEventArgs<HeaderView> args) { base.OnElementChanged(args); if (Control == null) { TextBlock textBlock = new TextBlock { FontSize = 28 }; textBlock.Tapped += TextBlock_Tapped; SetNativeControl(textBlock); if (args.NewElement != null) { SetText(); SetTextColor(); } } } private void TextBlock_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { if(Element!=null) { Element.FireClick(System.EventArgs.Empty); } } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == HeaderView.TextColorProperty.PropertyName) { SetTextColor(); } else if (e.PropertyName == HeaderView.TextProperty.PropertyName) { SetText(); } } private void SetText() { Control.Text = Element.Text; } private void SetTextColor() { Windows.UI.Color winColor = Windows.UI.Colors.Black; if (Element.TextColor != Xamarin.Forms.Color.Default) { Xamarin.Forms.Color color = Element.TextColor; winColor = Windows.UI.Color.FromArgb( (byte)(color.A * 255), (byte)(color.R * 255), (byte)(color.G * 255), (byte)(color.B * 255)); } Control.Foreground = new SolidColorBrush(winColor); } } }