首页 > 技术文章 > Xamarin.Forms 自定义 TapGestureRecognizer 附加属性

mschen 2019-03-20 15:32 原文

While creating Xamarin.Forms applications, definitely you are going to need TapGestureRecognizer often. Implementing it in XAML many times may end up with a lot of unnecessary code. Let’s take a look at that simple clickable Image:

1 <Image Source="img.png">
2   <Image.GestureRecognizers>
3     <TapGestureRecognizer Command="{Binding CloseCommand}" CommandParamter="{Binding .}" />
4   </Image.GestureRecognizers>
5 </Image>

This is a lot of lines, especially when you have to add many clickable controls. However, we can do it better and put everything into a single line using our custom attached property:

XHTML

xmlns:ex="clr-namespace:MyApp.Extensions;assembly=MyApp"
...
<Image Source="img.png" ex:Gestures.TapCommand="{ex:Command CloseCommand, Parameter={Binding .}}"/>

xmlns:ex="clr-namespace:MyApp.Extensions;assembly=MyApp"
...
<Image Source="img.png" ex:Gestures.TapCommand="{ex:Command CloseCommand, Parameter={Binding .}}"/>

Implementation

 1 using System;
 2 using Xamarin.Forms;
 3 using Xamarin.Forms.Xaml;
 4 using System.Windows.Input;
 5 
 6 namespace MyApp.Extensions
 7 {
 8     [ContentProperty("Command")]
 9     public class CommandExtension : BindableObject, IMarkupExtension
10     {
11         public string Command { get; set; }
12 
13         // Binding source for Command
14         public object Source { get; set; }
15 
16         // CommandParameter
17         public object Parameter { get; set; }
18 
19         public object ProvideValue(IServiceProvider serviceProvider)
20         {
21             return this;
22         }
23     }
24 }
 1 using Xamarin.Forms;
 2 using System.Linq;
 3 
 4 namespace MyApp.Extensions
 5 {
 6     public class Gestures
 7     {
 8         #region TapCommand
 9 
10         public static readonly BindableProperty TapCommandProperty = 
11             BindableProperty.CreateAttached<Gestures, CommandExtension>(
12               x => (CommandExtension)x.GetValue(Gestures.TapCommandProperty), 
13               null, BindingMode.OneWay, propertyChanged: TapCommandChanged);
14 
15         #endregion
16 
17         private static void TapCommandChanged(BindableObject source, CommandExtension oldVal, 
18                                               CommandExtension newVal)
19         {
20             var tapGesture = new TapGestureRecognizer();
21             
22             // Set command
23             var commandBinding = new Binding(newVal.Command, source: newVal.Source);
24             tapGesture.SetBinding(TapGestureRecognizer.CommandProperty, commandBinding);
25             
26             // Set command parameter
27             if (newVal.Parameter is Binding)
28             {
29                 tapGesture.SetBinding(TapGestureRecognizer.CommandParameterProperty, 
30                                       newVal.Parameter as Binding);
31             }
32             else
33             {
34                 tapGesture.CommandParameter = newVal.Parameter;
35             }
36             
37             // Remove old TapGestureRecognizer
38             var view = source as View;
39             var toRemove = view.GestureRecognizers.OfType<TapGestureRecognizer>().FirstOrDefault();
40             view.GestureRecognizers.Remove(toRemove);
41 
42             // Add new one
43             view.GestureRecognizers.Add(tapGesture);
44         }
45     }
46 }

 

推荐阅读