How to set focus from ViewModel in Xamarin Forms
11,966
Solution 1
One of options is to use Triggers (XAML way):
<SearchBar x:Name="searchBar"
Text=""
Placeholder="type something">
<SearchBar.Triggers>
<DataTrigger TargetType="SearchBar"
Binding="{Binding ViewModelIsSearchBarFocused}"
Value="True">
<Trigger.EnterActions>
<local:FocusTriggerAction Focused="True" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<local:FocusTriggerAction Focused="False" />
</Trigger.ExitActions>
</DataTrigger>
<EventTrigger Event="Unfocused">
<local:UnfocusedTriggerAction />
</EventTrigger>
</SearchBar.Triggers>
</SearchBar>
public class FocusTriggerAction : TriggerAction<SearchBar>
{
public bool Focused { get; set; }
protected override async void Invoke (SearchBar searchBar)
{
await Task.Delay(1000);
if (Focused)
{
searchBar.Focus();
}
else
{
searchBar.UnFocus();
}
}
}
public class UnfocusedTriggerAction : TriggerAction<SearchBar>
{
protected override void Invoke (SearchBar searchBar)
{
YourViewModel.ViewModelIsSearchBarFocused = false;
}
}
Read more here: https://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/triggers/
Solution 2
This is an example of how I do, before this I used to do using MessagingCenter
in xaml , you need to give an x:Name to the obj you want to make focus.
<!-- PICKER's DEFINITION -->
<DatePicker
x:Name="Datepicker"
Date="{Binding SelectedDate, Mode=TwoWay}"
IsEnabled="true"
IsVisible="false">
</DatePicker>
then you have to make reference to that control in your command parameter on a button or for example in this case I use a toolbar item.
<!-- MENU TOOLBAR -->
<ContentPage.ToolbarItems>
<ToolbarItem
Command="{Binding ShowCalendarCommand}"
Icon="Calendar"
CommandParameter="{x:Reference Datepicker}" />
</ContentPage.ToolbarItems>
then in your vm command :
#region toolbar commands
public ICommand ShowCalendarCommand => new RelayCommand<Object>(ShowCalendar);
#endregion
private void ShowCalendar(Object obj)
{
var calendar = (DatePicker)obj;
calendar.Focus();
// MessagingCenter.Send(this, "Calendar");
}
Author by
Fran_gg7
Updated on July 02, 2022Comments
-
Fran_gg7 almost 2 years
I want to set the focus in a
SearchBox
control after do some asynchronous operations, and I would like to do it from my ViewModel.How could I do this possible?
EDIT
ViewModel code:
private bool _searchBarFocused; public bool SearchBarFocused { get { return _searchBarFocused; } set { _searchBarFocused = value; base.OnPropertyChanged("SearchBarFocused"); } } public async Task InitializeData() { // Other operations... SearchBarFocused = true; }
View's code-behind code:
protected override void OnAppearing() { base.OnAppearing(); (this.BindingContext as MyViewModel).InitializeData(); }
SearchBar XAML code:
<SearchBar SearchCommand="{Binding SearchItemsCommand}"> <SearchBar.Triggers> <DataTrigger TargetType="SearchBar" Binding="{Binding SearchBarFocused, Mode=TwoWay}" Value="True"> <Trigger.EnterActions> <triggers:SearchBarFocusTriggerAction Focused="True" /> </Trigger.EnterActions> <Trigger.ExitActions> <triggers:SearchBarFocusTriggerAction Focused="False" /> </Trigger.ExitActions> </DataTrigger> </SearchBar.Triggers> </SearchBar>
Trigger action code:
public class SearchBarFocusTriggerAction : TriggerAction<SearchBar> { public bool Focused { get; set; } protected override void Invoke(SearchBar searchBar) { if (Focused) searchBar.Focus(); else searchBar.Unfocus(); } }
-
Fran_gg7 almost 9 yearsThanks for your reply, Daniel. I am using your approach in my project and it seemed to work, but the Invoke method is only raised the first time I assign the ViewModelIsSearchBarFocused value to true. The rest of the times this method is not called...do you know why?
-
Daniel Luberda almost 9 yearsDoes your ViewModel implements IOnNotifyPropertyChanged correctly? I'll need your ViewModel code to see why.
-
Fran_gg7 almost 9 yearsYes, it does. I just have updated the question with the source code I am using. It works the first time the method InitializeData() is called, but not the second...
-
Fran_gg7 almost 9 yearsI think that it is because when the focus is lost in UI, the ViewModelIsSearchBarFocused property is not setted to false. Would it be possible?
-
Daniel Luberda almost 9 years1. Did you try to use Task.Delay before focus? I modified my example. 2. Do you really need
Mode=TwoWay
in binding? -
Daniel Luberda almost 9 yearsAlso please note that successful Unfocus/Focus operation returns true if succeeded. Can you check what results do you get for each call?
-
Fran_gg7 almost 9 yearsDaniel, I put beakpoints inside Invoke method but only is called the first time I navigate to the screen. If I navigate to another screen and then go back, the InitializeData method is called, the SearchBarFocused property is setted to true but the Invoke method is not raised... I also have tried without Mode=TwoWay
-
Daniel Luberda almost 9 yearsAre you sure that before you open a new page SearchBarFocused is set to false? OR Just put SearchBarFocused = true; at the beginning of InitializeData method.
-
Daniel Luberda almost 9 yearstypo: SearchBarFocused = false; at the beginning of InitializeData method
-
Fran_gg7 almost 9 yearsIf I set to false the property SearchBarFocused before leave the page, this works when I go back :-) But...is there any way to automatically set the property SearchBarFocused = false when the focus is missed in UI? (when Unfocus() method is called...) thanks!
-
Daniel Luberda almost 9 yearsYou could use OnAppearing of other page override combined with Xamarin.Forms MessagingCenter or SearchBar.Unfocused event.
-
Fran_gg7 almost 9 yearsAnd is there possibility to do this with Triggers?
-
Daniel Luberda almost 9 yearsWhy just SearchBarFocused = false; at the beginning of InitializeData method won't work for you? You can add a Trigger which is paired with Searchbar.Unfocused event. Read more here (look for Event Triggers): developer.xamarin.com/guides/cross-platform/xamarin-forms/…
-
Fran_gg7 almost 9 yearsI have readed the full page, but I don't understand how I can do it....could you help me please?
-
Fran_gg7 almost 9 yearsThanks, but how do I access to my ViewModel from the UnfocusedTriggerAction? In addition, this approach only would work in only a page, it wouldn't be generical :-(
-
Daniel Luberda almost 9 yearseg you can pass it the same as I did in FocusTriggerAction with Focused property.
-
Shimmy Weitzhandler over 6 yearsIs there a way to raise a datatrigger without setting a property? In my scenario I'd just want to raise an event or call a method in the VM.
-
pixel about 5 yearsWhat if I want to focus back on a view each time I type a character in an Entry for example. Say I use entry or SearchBar to search and on each character entered, I want filtering to happen. But my filtering logic causes the Entry to loose focus, so at the end I want to focus back on that Entry so user can type next character.
-
Chris W over 3 years
Trigger.EnterActions
andTrigger.ExitActions
should be renamed toDataTrigger.EnterActions
andDataTrigger.ExitActions
respectively. -
Wolfgang Schreurs about 3 yearsI believe your answer has been downvoted as it's generally considered an ugly approach in context of MVVM. The ViewModel should not know anything about the view, communication between ViewModel and View should be one directional to keep the codebase flexible.