Xamarin.Forms的View实现WPF、Android原生控件的事件

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.... };

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值