I have a Entry
control inside DataTemplate
of Bindable StackLayout
. I have implemented TextChanged
event of Entry
control with Behavior
but event is not getting fired.
This is xaml
code
<Frame Padding="20,14,10,10"
Grid.Column="1"
BorderColor="LightGray">
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding RefreshCommand}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
</Frame>
Behavior classes in a single file
namespace Product.Helpers
{
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 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);
}
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;
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;
}
}
}
ViewModel Code for Command
public ICommand RefreshCommand
{
get
{
return new Command(async (args) =>
{
Refresh();
});
}
}
public void Refresh()
{
var textbox = Subtotal;
}
From here I have take the code csharpcorer - behavior. How can I make it work ?
CodePudding user response:
The reason you are not able to find it is because of the context.
Give your current ContentPage a name :
<ContentPage
...
x:Name="currentPage"/>
Then your Entry would look something like:
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding BindingContext.RefreshCommand, Source={x:Reference currentPage}}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>