In Xamarin.Forms, how do you designate a button as the default button for a page?
For example, on UWP the click handler for a DefaultButton should fire when the user presses the Enter key while the page has focus.
In Xamarin.Forms, how do you designate a button as the default button for a page?
For example, on UWP the click handler for a DefaultButton should fire when the user presses the Enter key while the page has focus.
Assuming you are trying to replicate the behavior as noted in your first comment to Alessandro, you want to declare the Completed
field of your Entry
control to use the same event handler as your button.
For example, in XAML:
<Entry Placeholder="Enter PIN Here"
Completed="DefaultButton_Clicked"/>
<Button Text="OK"
Clicked="DefaultButton_Clicked"/>
Then in your code behind:
void DefaultButton_Clicked(object sender, EventArgs e)
{
//Do stuff
}
If you are looking to do this all in code behind like you have answered, I suggest doing it this way so you are able to unsubscribe your events. You'll find working with anonymous functions to be more of a pain. You should subscribe and unsubscribe your events in OnAppearing/OnDisappearing.
void DefaultButton_Clicked(object sender, EventArgs e)
{
if (model.MyCommand.CanExecute(null))
model.MyCommand.Execute(null);
}
protected override void OnAppearing()
{
base.OnAppearing();
foreach (var child in ((StackLayout)Content).Children)
{
if (child is Entry entry)
entry.Completed += DefaultButton_Clicked;
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
foreach (var child in ((StackLayout)Content).Children)
{
if (child is Entry entry)
entry.Completed -= DefaultButton_Clicked;
}
}
I ended up writing code that wires up each Entry to conditionally invoke the default button's command. In my case, each Entry is in a single StackLayout at the page root, so the page's constructor has code like this:
foreach (var child in ((StackLayout)Content).Children)
if (child is Entry entry)
entry.Completed += delegate {
if (model.MyCommand.CanExecute(null))
model.MyCommand.Execute(null);
};
-=
them. –
Indicia We ended up implementing an entry behavior for the completed event. We wanted to bind it from .xaml and to be able to both navigate between fields and submit on the last field. It took some research, so I'm sharing here in the hopes it will be useful for someone else, too:
<Entry TabIndex="0" Placeholder="{ui:Resource ID_STR_USERNAME}" Text="{Binding Username, Mode=TwoWay}" Style="{StaticResource EntryText}">
<Entry.Behaviors>
<behaviors:EntryCompletedBehavior />
</Entry.Behaviors>
</Entry>
<Entry TabIndex="1" Placeholder="{ui:Resource ID_STR_PASSWORD_HINT}" IsPassword="True" Text="{Binding Password.Value, Mode=TwoWay}" Style="{StaticResource EntryText}">
<Entry.Behaviors>
<behaviors:EntryTextChangeCommandBehavior Command="{Binding Password.ValidateCommand}" />
<behaviors:EntryCompletedBehavior Command="{Binding LoginCommand, Mode=TwoWay}" CommandParameter="{Binding Password}" />
</Entry.Behaviors>
</Entry>
and the behavior:
public class EntryCompletedBehavior : Behavior<Entry>
{
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(EntryCompletedBehavior), null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(EntryCompletedBehavior), null);
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
protected override void OnAttachedTo(Entry bindable)
{
base.OnAttachedTo(bindable);
if(bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += Bindable_BindingContextChanged;
bindable.Completed += Bindable_Completed;
}
protected override void OnDetachingFrom(Entry bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= Bindable_BindingContextChanged;
bindable.Completed -= Bindable_Completed;
}
private void Bindable_Completed(object sender, System.EventArgs e)
{
if(sender is Entry entry)
{
var ix = entry.TabIndex;
int allIndexesOnPage;
var coll = entry.GetTabIndexesOnParentPage(out allIndexesOnPage);
foreach(var item in coll)
{
if(ix < item.Key)
{
item.Value.First().Focus();
return;
}
}
}
if(Command == null)
return;
if(Command.CanExecute(CommandParameter))
{
Command.Execute(CommandParameter);
}
}
void Bindable_BindingContextChanged(object sender, EventArgs e)
{
base.OnBindingContextChanged();
if(!(sender is BindableObject bindable))
return;
BindingContext = bindable.BindingContext;
}
}
As an added bonus, the behavior can be used on its own, just to navigate between tab-indexed fields.
Based on this post: https://forums.xamarin.com/discussion/124714/how-to-fire-a-complete-event-from-viewmodel
You have not to say "In Xamarin.Forms, how do you designate a button as the default button for a page?" because Xamarin.Forms visualize only Platform Specific controls.
You should ask "In Android (or iOS) how do you designate a button as the default button for a page?".
I think it is the focused button, so you can try something like
Button b = new Button {Text = "This is the focused button"};
b.Focus();
But I am not sure of this.
Take a look here in Xamarin forum
PageRenderer.Control
was always null. –
Loss © 2022 - 2024 — McMap. All rights reserved.
Completed
event handler will fire when pressing enter. Note that I've been using this for iOS and Android. Not sure about other uses. – Indicia