如何从 EventToCommandBehavior 传递 Command 参数
How can I pass Command parameter from EventToCommandBehavior
我正在使用 EventToCommandBehavior
和 Entry
控件。 Entry
在 Bindable stacklayout
的 DataTemplate
内。
我想将当前项目作为命令参数传递。我做不到。下面是我的代码。
这是我的行为class
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter Converter
{
get { return (IValueConverter)GetValue(InputConverterProperty); }
set { SetValue(InputConverterProperty, value); }
}
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(VisualElement bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
behavior.CommandParameter = bindable;
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name)) return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name) || eventHandler == null)
return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null) return;
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else if (Converter != null)
{
resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
}
else
{
resolvedParameter = eventArgs;
}
if (Command.CanExecute(resolvedParameter))
Command.Execute(resolvedParameter);
}
}
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
这是我的xaml代码
<Entry
MaxLength="5"
HorizontalOptions="Center"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior
Command="{Binding BindingContext.RefreshCommand, Source={x:Reference multitenderPage}}"
CommandParameter="{Binding .}" EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
这是视图模型代码
public ICommand RefreshCommand { get; set; }
RefreshCommand = new Command<TendersList>(Refresh1);
当我执行 Command<TendersList>
时,命令没有命中。当我执行 Command(async (args) =>
时,我在 args
中得到 old
和 new
Entry
的值,而不是我想得到 item
或itemId
来自参数
如何获取列表的当前 record/item。当行为发生时?
发生这种情况的原因是此方法的最后一行,每次您设置新事件时,它都会覆盖您在 Command 参数中的任何内容,并将其替换为该特定对象:
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
behavior.CommandParameter = bindable;
}
是否要在触发事件后获取条目的文本 RefreshCommand
?
如果是,您可以将条目本身作为 CommandParameter
的参数传递。
请参考以下代码:
<StackLayout BindableLayout.ItemsSource="{Binding User.Items}"
Orientation="Vertical"
Margin="0,10,0,0"
Spacing="20">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Entry x:Name="myEntry" MaxLength="5"
HorizontalOptions="FillAndExpand" HeightRequest="42">
<Entry.Behaviors>
<bindablelayoutdemo:EventToCommandBehavior
Command="{Binding BindingContext.RefreshCommand, Source={x:Reference myPage}}"
CommandParameter="{x:Reference myEntry}" EventName="TextChanged"></bindablelayoutdemo:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
注:
myPage
是当前页的x:Name="myPage"
。
我正在使用 EventToCommandBehavior
和 Entry
控件。 Entry
在 Bindable stacklayout
的 DataTemplate
内。
我想将当前项目作为命令参数传递。我做不到。下面是我的代码。
这是我的行为class
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter Converter
{
get { return (IValueConverter)GetValue(InputConverterProperty); }
set { SetValue(InputConverterProperty, value); }
}
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(VisualElement bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
behavior.CommandParameter = bindable;
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name)) return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name) || eventHandler == null)
return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null) return;
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else if (Converter != null)
{
resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
}
else
{
resolvedParameter = eventArgs;
}
if (Command.CanExecute(resolvedParameter))
Command.Execute(resolvedParameter);
}
}
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
这是我的xaml代码
<Entry
MaxLength="5"
HorizontalOptions="Center"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior
Command="{Binding BindingContext.RefreshCommand, Source={x:Reference multitenderPage}}"
CommandParameter="{Binding .}" EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
这是视图模型代码
public ICommand RefreshCommand { get; set; }
RefreshCommand = new Command<TendersList>(Refresh1);
当我执行 Command<TendersList>
时,命令没有命中。当我执行 Command(async (args) =>
时,我在 args
中得到 old
和 new
Entry
的值,而不是我想得到 item
或itemId
来自参数
如何获取列表的当前 record/item。当行为发生时?
发生这种情况的原因是此方法的最后一行,每次您设置新事件时,它都会覆盖您在 Command 参数中的任何内容,并将其替换为该特定对象:
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
behavior.CommandParameter = bindable;
}
是否要在触发事件后获取条目的文本 RefreshCommand
?
如果是,您可以将条目本身作为 CommandParameter
的参数传递。
请参考以下代码:
<StackLayout BindableLayout.ItemsSource="{Binding User.Items}"
Orientation="Vertical"
Margin="0,10,0,0"
Spacing="20">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Entry x:Name="myEntry" MaxLength="5"
HorizontalOptions="FillAndExpand" HeightRequest="42">
<Entry.Behaviors>
<bindablelayoutdemo:EventToCommandBehavior
Command="{Binding BindingContext.RefreshCommand, Source={x:Reference myPage}}"
CommandParameter="{x:Reference myEntry}" EventName="TextChanged"></bindablelayoutdemo:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
注:
myPage
是当前页的x:Name="myPage"
。