Как установить фокус из ViewModel в Xamarin Forms
Я хочу установить фокус в SearchBox
После выполнения некоторых асинхронных операций, и я хотел бы сделать это из моей ViewModel.
Как я мог сделать это возможным?
РЕДАКТИРОВАТЬ
Код ViewModel:
private bool _searchBarFocused;
public bool SearchBarFocused
{
get { return _searchBarFocused; }
set
{
_searchBarFocused = value;
base.OnPropertyChanged("SearchBarFocused");
}
}
public async Task InitializeData()
{
// Other operations...
SearchBarFocused = true;
}
Код с выделенным кодом вида:
protected override void OnAppearing()
{
base.OnAppearing();
(this.BindingContext as MyViewModel).InitializeData();
}
XAML код SearchBar:
<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>
Код действия триггера:
public class SearchBarFocusTriggerAction : TriggerAction<SearchBar>
{
public bool Focused { get; set; }
protected override void Invoke(SearchBar searchBar)
{
if (Focused)
searchBar.Focus();
else
searchBar.Unfocus();
}
}
2 ответа
Один из вариантов - использовать триггеры (способ XAML):
<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;
}
}
Подробнее читайте здесь: https://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/triggers/
Это пример того, как я это делаю, до этого я использовал MessagingCenter
в xaml вам нужно дать x:Name объекту, на который вы хотите сфокусироваться.
<!-- PICKER's DEFINITION -->
<DatePicker
x:Name="Datepicker"
Date="{Binding SelectedDate, Mode=TwoWay}"
IsEnabled="true"
IsVisible="false">
</DatePicker>
затем вы должны сделать ссылку на этот элемент управления в параметре вашей команды на кнопке или, например, в этом случае я использую элемент панели инструментов.
<!-- MENU TOOLBAR -->
<ContentPage.ToolbarItems>
<ToolbarItem
Command="{Binding ShowCalendarCommand}"
Icon="Calendar"
CommandParameter="{x:Reference Datepicker}" />
</ContentPage.ToolbarItems>
тогда в вашей команде vm:
#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");
}
Я решил проблему, передав страницу содержимого в качестве параметра в viewmodel.
BindingContext = new YourViewModel(this);
и создал свойство в модели просмотра
public ContentPage m_View { get; set; }
а затем установите значение этого свойства из конструктора
public YourViewModel(ContentPage view)
{
m_View = view;
}
а затем установите фокус на моем DatePicker, используя его имя
var DatePicker = m_View.FindByName("YourDatePickerName") as DatePicker;
DatePicker.Focus();
мой код DatePicker был
<DatePicker x:Name="YourDatePickerName"
Date="{Binding SelectedDate}" />