Xamarin EventToCommandBehavior bindable not an instance of AssociatedType 异常
问题出在我的EventToCommandBehavior基类的泛型类型上。
原来EventToCommandBehavior继承自
BindableBehavior<View>
将EventToCommandBehavior改为继承自
BindableBehavior<VisualElement>
解决问题
这里挖个坑,原理有时间在研究
这是最终可以使用的EventToCommandBehavior文件:
public class EventToCommandBehavior : BindableBehavior<VisualElement>
{
public static BindableProperty EventNameProperty =
BindableProperty.CreateAttached("EventName", typeof(string), typeof(EventToCommandBehavior), null,
BindingMode.OneWay);
public static BindableProperty CommandProperty =
BindableProperty.CreateAttached("Command", typeof(ICommand), typeof(EventToCommandBehavior), null,
BindingMode.OneWay);
public static BindableProperty CommandParameterProperty =
BindableProperty.CreateAttached("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null,
BindingMode.OneWay);
public static BindableProperty EventArgsConverterProperty =
BindableProperty.CreateAttached("EventArgsConverter", typeof(IValueConverter), typeof(EventToCommandBehavior), null,
BindingMode.OneWay);
public static BindableProperty EventArgsConverterParameterProperty =
BindableProperty.CreateAttached("EventArgsConverterParameter", typeof(object), typeof(EventToCommandBehavior), null,
BindingMode.OneWay);
protected Delegate _handler;
private EventInfo _eventInfo;
public string EventName
{
get => (string)GetValue(EventNameProperty);
set => SetValue(EventNameProperty, value);
}
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public IValueConverter EventArgsConverter
{
get => (IValueConverter)GetValue(EventArgsConverterProperty);
set => SetValue(EventArgsConverterProperty, value);
}
public object EventArgsConverterParameter
{
get => GetValue(EventArgsConverterParameterProperty);
set => SetValue(EventArgsConverterParameterProperty, value);
}
protected override void OnAttachedTo(VisualElement visualElement)
{
base.OnAttachedTo(visualElement);
var events = AssociatedObject.GetType().GetRuntimeEvents().ToArray();
if (!events.Any()) return;
_eventInfo = events.FirstOrDefault(e => e.Name == EventName);
if (_eventInfo == null)
throw new ArgumentException(
$"EventToCommand: Can't find any event named '{EventName}' on attached type");
AddEventHandler(_eventInfo, AssociatedObject, OnFired);
}
protected override void OnDetachingFrom(VisualElement view)
{
if (_handler != null)
_eventInfo.RemoveEventHandler(AssociatedObject, _handler);
base.OnDetachingFrom(view);
}
private void AddEventHandler(EventInfo eventInfo, object item, Action<object, EventArgs> action)
{
var eventParameters = eventInfo.EventHandlerType
.GetRuntimeMethods().First(m => m.Name == "Invoke")
.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType))
.ToArray();
var actionInvoke = action.GetType()
.GetRuntimeMethods().First(m => m.Name == "Invoke");
_handler = Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action), actionInvoke, eventParameters[0], eventParameters[1]),
eventParameters
)
.Compile();
eventInfo.AddEventHandler(item, _handler);
}
private void OnFired(object sender, EventArgs eventArgs)
{
if (Command == null)
return;
var parameter = CommandParameter;
if (eventArgs != null && eventArgs != EventArgs.Empty)
{
parameter = eventArgs;
if (EventArgsConverter != null)
{
parameter = EventArgsConverter.Convert(eventArgs, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentUICulture);
}
}
if (Command.CanExecute(parameter))
{
Command.Execute(parameter);
}
}
}