Behavior
创建行为
- 创建一个继承自Behavior或Behavoir的自定义类,其中T是被将附加该行为的控件类型。
- 重写OnAttachedTo方法以执行所需业务逻辑。
- 重写OnDetachingFrom方法以执行所需的清理。
public class NumericValidationBehavior:Behavior<Entry>
{
protected override void OnAttachedTo(Entry bindable)
{
base.OnAttachedTo(bindable);
bindable.TextChanged += OnEntryTextChanged;
}
protected override void OnDetachingFrom(Entry bindable)
{
base.OnDetachingFrom(bindable);
bindable.TextChanged -= OnEntryTextChanged;
}
void OnEntryTextChanged(object sender,TextChangedEventArgs args)
{
double result;
bool isValid = double.TryParse(args.NewTextValue, out result);
(sender as Entry).TextColor = isValid ?Color.Default:Color.Red;
}
}
OnAttachedTo方法在行为附加到控件后立即触发。
OnDetachingFrom方法在从控件中删除行为时触发。
使用Xamarin.Form行为
xaml:
<Entry Placeholder="Enter a System.Double">
<Entry.Behaviors>
<behaviorsample:NumericValidationBehavior/>
</Entry.Behaviors>
</Entry>
C#:
var entry = new Entry { Placeholder = "Enter a System.Double" };
entry.Behaviors.Add (new NumericValidationBehavior ());
使用Sytle来应用行为
- 将附加属性添加到自定义的行为类中,以控制从控件中添加和删除行为。确保附加属性注册propertyChanged委托,该委托将在属性值更改时执行。
- 为附加属性创建static的getter和setter。
- 在propertyChanged委托中实现逻辑以添加和删除行为。
#region 使用Style来定义Behavior,通过附加属性来实现
public static readonly BindableProperty AttachBehaviorProperty = BindableProperty.CreateAttached("AttachBehavior",typeof(bool),typeof(NumericValidationBehavior),false,propertyChanged:OnAttachBehaviorChanged);
public static bool GetAttachBehavior(BindableObject view)
=> (bool)view.GetValue(AttachBehaviorProperty);
public static void SetAttachBehavior(BindableObject view,bool value)
=> view.SetValue(AttachBehaviorProperty,value);
static void OnAttachBehaviorChanged(BindableObject view,object oldValue,object newValue)
{
var entry = view as Entry;
if (entry is null)
{
return;
}
bool attachBehavior = (bool)newValue;
if (attachBehavior)
{
entry.Behaviors.Add(new NumericValidationBehavior());
}
else
{
var toRemove = entry.Behaviors.FirstOrDefault(b => b is NumericValidationBehavior);
if (toRemove != null)
{
entry.Behaviors.Remove(toRemove);
}
}
}
#endregion
应用行为
<ContentPage.Resources>
<Style x:Key="NumericValidationStyle" TargetType="Entry">
<Style.Setters>
<Setter Property="behaviorsample:NumericValidationBehavior.AttachBehavior" Value="True"/>
</Style.Setters>
</Style>
</ContentPage.Resources>
<Entry Placeholder="Enter a System.Double"
Style="{StaticResource NumericValidationStyle}"/>
EffectBehavior
使用Behavior可以向控件添加特定于平台的效果、从隐藏代码中省去冗余重复的效果处理代码。
概述
EffectBehavior自定义类是可重用的Xmarin.Forms自定义行为,当行为附加到控件时,它会将Effect实例添加到控件,当行为与控件分离时,它将删除Effect实例。
必须设置一下行为属性才能使用该行为:
- Group - 平台项目的自定义效果类特性ResolutionGroupName的属性值。
- Name - 平台项目的自定义效果类特性ExportEffect的属性值。
创建行为
EffectBehavior自定义类派生自Behavior类,其中T是View。这意味着EffectBehavior自定义类可以附加到任何Xamarin.Forms控件。
实现 BindableProperty
在共享项目中,创建EffectBehavior自定义类,该自定义类定义了两个 BindableProperty 实例,当行为附加到控件时,这些实例用于向控件添加Effect。
public class EffectBehavior:Behavior<View>
{
public static readonly BindableProperty GroupProperty =
BindableProperty.Create("Group",typeof(string),typeof(EffectBehavior),null);
public static readonly BindableProperty NameProperty =
BindableProperty.Create("Name",typeof(string),typeof(EffectBehavior),null);
public string Group
{
get => GetValue(GroupProperty) as string;
set => SetValue(GroupProperty,value);
}
public string Name
{
get => GetValue(NameProperty) as string;
set => SetValue(NameProperty,value);
}
}
当使用EffectBehavior时,应将Group属性设置为特定于平台效果类的ResolutionGroupName特性的值。此外,应将Name属性设置为特定于平台效果类的ExportEffect特性的值。
重写OnAttachTo和OnDetachingFrom方法
protected override void OnAttachedTo(BindableObject bindable)
{
base.OnAttachedTo(bindable);
AddEffect(bindable as View);
}
protected override void OnDetachingFrom(BindableObject bindable)
{
base.OnDetachingFrom(bindable);
RemoveEffect(bindable as View);
}
添加和删除行为功能
当行为附加到控件时,将Group和Name属性中定义的Effect添加到控件,并在行为与控件分离时删除Effefct。
Effect GetEffect()
{
if (!string.IsNullOrWhiteSpace(Group)&&!string.IsNullOrWhiteSpace(Name))
{
return Effect.Resolve($"{Group}.{Name}");
}
return null;
}
void AddEffect(View view)
{
var effect = GetEffect();
if (effect != null)
{
view.Effects.Add(effect);
}
}
void RemoveEffect(View view)
{
var efffect = GetEffect();
if (efffect !=null)
{
view.Effects.Remove(GetEffect());
}
}
GetEffect方法使用Effect.Resolve方法检索Effect。通过串联Group和Name属性值来从平台项目中定位检索该效果。如果平台项目不提供此效果,则Effect.Resolve方法将返回 NullEffect 实例。
在平台项目中各自实现效果类
iOS
using System;
using System.Diagnostics;
using CoreGraphics;
using EffectBehaviorSample.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly:ResolutionGroupName("Xamarin")]
[assembly:ExportEffect(typeof(LabelShadowEffect),"LabelShadowEffect")]
namespace EffectBehaviorSample.iOS
{
public class LabelShadowEffect:PlatformEffect
{
public LabelShadowEffect()
{
}
protected override void OnAttached()
{
try
{
Control.Layer.CornerRadius = 5;
Control.Layer.ShadowColor = Color.Black.ToCGColor();
Control.Layer.ShadowOffset = new CGSize(5,5);
Control.Layer.ShadowOpacity = 1.0f;
}
catch (Exception ex)
{
Debug.WriteLine("Cannot set property on attached control:",ex.Message);
}
}
protected override void OnDetached()
{
throw new NotImplementedException();
}
}
}
Droid
using System;
using System.Diagnostics;
using EffectBehaviorSample.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ResolutionGroupName("Xamarin")]
[assembly:ExportEffect(typeof(LabelShadowEffect),"LabelShadowEffect")]
namespace EffectBehaviorSample.Droid
{
public class LabelShadowEffect:PlatformEffect
{
public LabelShadowEffect()
{
}
protected override void OnAttached()
{
try
{
var control = Control as Android.Widget.TextView;
float radius = 5;
float distanceX = 5;
float distanceY = 10;
Android.Graphics.Color color = Color.IndianRed.ToAndroid();
control.SetShadowLayer(radius,distanceX,distanceY,color);
}
catch (Exception ex)
{
Debug.WriteLine("Cannot set property on attached control. Error: ",ex.Message);
}
}
protected override void OnDetached()
{
throw new NotImplementedException();
}
}
}
对于此示例,共享项目EffectBehavior的Group属性应为"Xamarin",Name属性应为"LabelShadowEffect",即可检索到该特定于平台的效果。
使用Behavior
EffectBehavior类可以附加到控件的Behaviors集合。
<StackLayout Margin="0,30,0,0"
HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="Label Shadow Effect">
<Label.Behaviors>
<effectbehaviorsample:EffectBehavior Group="Xamarin"
Name="LabelShadowEffect"/>
</Label.Behaviors>
</Label>
</StackLayout>
等到的C#
var label = new Label {
Text = "Label Shadow Effect",
...
};
label.Behaviors.Add (new EffectBehavior {
Group = "Xamarin",
Name = "LabelShadowEffect"
});
行为的Group和Name属性被设置为每个平台项目的效果类的ResolutionGroupName和ExportEffect特性的值。
运行示例
iOS
Droid
==官方Doc==