Xamarin.Forms的控件原生是没有点击事件的,只能曲线救国,如使用TapGestureRecognizer、Effects等
以下以使用Effects在WPF、Android双端实现长按(Windows里为右键)、单击为例
其他平台、其他事件做法类似
1 在Xamarin.Forms主工程里创建ViewEffect类
using System;
using System.Diagnostics;
using Xamarin.Forms;
namespace XamarinDemo
{
public class ViewEffect : RoutingEffect
{
public event Action<Element> Click = null;
public event Action<Element> LongClick = null;
public ViewEffect() : base("MyCompany.ViewEffect")//这里要取一个唯一的名字
{
}
public ViewEffect(string cls) : base(cls)
{
}
public void OnClick(Element v)
{
Click?.Invoke(v);
}
public void OnLongClick(Element v)
{
LongClick?.Invoke(v);
}
}
}
2、在WPF工程和Android工程分别创建PlatformEffect的子类,实现ViewEffect的功能
WPF端:
using System.Linq;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;
using WView = System.Windows.FrameworkElement;
using XView = Xamarin.Forms.Element;
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(XamarinDemo.WPF.WViewEffect), "ViewEffect")]//这个与ResolutionGroupName组合出来的字符串需与ViewEffect类设置的唯一名称相同
namespace XamarinDemo.WPF
{
public class WViewEffect : PlatformEffect
{
ViewEffect effect;
protected override void OnAttached()
{
XView xsv = Element as XView;
WView wsv = Control as WView;
if (wsv != null)
{
effect = (ViewEffect)Element.Effects.
FirstOrDefault(d => d is ViewEffect);
wsv.MouseRightButtonUp += Wsv_MouseRightButtonUp;
//并非所有WPF控件都有Click事件,所以需要曲线救国
wsv.MouseLeftButtonDown += Wsv_MouseLeftButtonDown;
wsv.MouseLeftButtonUp += Wsv_MouseLeftButtonUp;
}
}
DateTime downTime = DateTime.Now;
private void Wsv_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
downTime = DateTime.Now;
}
private void Wsv_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DateTime dt = DateTime.Now;
if ((dt - downTime).TotalMilliseconds < 500)
effect.OnClick(Element);
}
private void Wsv_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
effect.OnLongClick(Element);
}
protected override void OnDetached()
{
}
}
}
Android端:
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static Android.Views.View;
using AView = Android.Views.View;
using XView = Xamarin.Forms.View;
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(XamarinDemo.Droid.AViewEffect), "ViewEffect")]//这个与ResolutionGroupName组合出来的字符串需与ViewEffect类设置的唯一名称相同
namespace XamarinDemo.Droid
{
public class AViewEffect : PlatformEffect
{
ViewEffect effect;
protected override void OnAttached()
{
XView xsv = Element as XView;
AView asv = Control as AView;
if(asv==null)
asv = Container as AView;
if (asv != null)
{
effect = (ViewEffect)Element.Effects.
FirstOrDefault(d => d is ViewEffect);
asv.LongClick += Asv_LongClick;
asv.Click += Asv_Click;
}
}
private void Asv_Click(object sender, System.EventArgs e)
{
effect.OnClick(Element);
}
private void Asv_LongClick(object sender, LongClickEventArgs e)
{
effect.OnLongClick(Element);
}
protected override void OnDetached()
{
}
}
}
3、控件绑定,这里有两种方法,要么从Xaml里绑定,要么用代码
Xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamarinDemo"
x:Class="XamarinDemo.MyXamarinDemo">
<Grid x:Name="grd">
<Grid.Effects>
<local:ViewEffect x:Name="effGrid"/>
</Grid.Effects>
<Label x:Name="lab">
<Label.Effects>
<local:ViewEffect x:Name="effLabel"/>
</Label.Effects>
</Label>
</Grid>
</ContentView>
从代码:
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XamarinDemo
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyXamarinDemo : ContentView
{
public MyXamarinDemo()
{
InitializeComponent();
ViewEffect effGrid = new ViewEffect();
ViewEffect effLabel = new ViewEffect();
grd.Effects.Add(effGrid);
lab.Effects.Add(effLabel);
}
}
}
然后就可以添加事件了:
effGrid.LongClick += (v) => { DoSomeThing.... };
effGrid.Click += (v) => { DoSomeThing.... };
4、如果是自行生成的控件,可以使用扩展方法,方便使用
在Xamarin.Forms主工程里创建一个static类ViewHelper
using System;
using System.Linq;
using Xamarin.Forms;
namespace XamarinDemo
{
public static class ViewHelper
{
/// <summary>
/// 生成控件(添加ViewEffect)
/// </summary>
/// <typeparam name="T">要生成的控件类型</typeparam>
/// <param name="v"></param>
/// <returns></returns>
public static T CreateView<T> (this Element v) where T: Element
{
return v.CreateView<T, ViewEffect>();
}
/// <summary>
/// 生成控件
/// </summary>
/// <typeparam name="T">要生成的控件类型</typeparam>
/// <typeparam name="E">要添加的效果器类型</typeparam>
/// <param name="v"></param>
/// <returns></returns>
public static T CreateView<T, E> (this Element v) where T: Element where E : ViewEffect
{
T t = Activator.CreateInstance<T>();
t.Effects.Add(Activator.CreateInstance<E>());
return t;
}
/// <summary>
/// 生成控件
/// </summary>
/// <typeparam name="E">要添加的效果器类型</typeparam>
/// <param name="v"></param>
/// <param name="t">要生成的控件类型</param>
/// <returns></returns>
public static object CreateView<E>(this Element v, Type t) where E : ViewEffect
{
return v.CreateView(t, typeof(E));
}
/// <summary>
/// 生成控件(添加ViewEffect)
/// </summary>
/// <param name="v"></param>
/// <param name="t">要生成的控件类型</param>
/// <returns></returns>
public static object CreateView(this Element v, Type t)
{
return v.CreateView(t, typeof(ViewEffect));
}
/// <summary>
/// 生成控件
/// </summary>
/// <param name="v"></param>
/// <param name="t">要生成的控件类型</param>
/// <param name="eff">要添加的效果器类型</param>
/// <returns></returns>
public static object CreateView(this Element v, Type t, Type eff)
{
object obj = Activator.CreateInstance(t);
object ef = Activator.CreateInstance(eff);
if (obj is Element e && ef is ViewEffect)
e.Effects.Add(ef as ViewEffect);
return obj;
}
/// <summary>
/// 获取相应类型的效果器
/// </summary>
/// <typeparam name="T">效果器类型</typeparam>
/// <param name="v"></param>
/// <returns></returns>
public static ViewEffect Effect<T>(this Element v) where T : ViewEffect
{
return v.Effects.FirstOrDefault() as T;
}
/// <summary>
/// 获取ViewEffect
/// </summary>
/// <typeparam name="T">效果器类型</typeparam>
/// <param name="v"></param>
/// <returns></returns>
public static ViewEffect ViewEffect(this Element v)
{
return v.Effect<ViewEffect>();
}
}
}
然后使用CreateView方法替代 new XXX,并使用View.Effect<T>方法获取相应效果器来调用方法
//原来的写法
Label lab1 = new Label();
ViewEffect eff = new ViewEffect();
lab1.Effects.Add(eff);
eff.LongClick += (v) => { DoSomeThing.... };
//改成
Label lab2 = this.CreateView<Label>();
//或
Label lab2 = this.CreateView(typeof(Label)) as Label;
//调用效果器绑定事件
lab2.ViewEffect().LongClick += (v) => { DoSomeThing.... };
//或
lab2.Effect<ViewEffct>().LongClick += (v) => { DoSomeThing.... };