将焦点放在 Xamarin.Forms MVVM (Prism) 中的 Entry 字段
Set focus on Entry field in Xamarin.Forms MVVM (Prism)
我正在使用 Xamarin.Forms 和 Prism 来创建我的移动应用程序。
我有一个包含 2 个条目的屏幕。进入屏幕时,我想将焦点设置在第一个条目上。
然后在用户在此条目中输入数据并验证后,我想将焦点设置到第二个条目。
基于第一个答案:
我应该做错事。我创建了一个新的 Prism 小项目来测试它:
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:testEntry"
x:Class="testEntry.Views.MainPage"
Title="{Binding Title}">
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Welcome to Xamarin Forms and Prism!" />
<local:MyEntry Placeholder="" x:Name="entry1" />
<Button Text="set focus on entry1" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
using Xamarin.Forms;
namespace testEntry.Views
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
entry1.Focus(); //Not Working
}
private void Button_Clicked(object sender, EventArgs e)
{
entry1.Focus(); //Working
}
}
}
MyEntry.cs(在主项目中)
using Xamarin.Forms;
namespace testEntry
{
public class MyEntry : Entry
{
}
}
MyEntryRenderer.cs(在 Android 项目中)
using Android.Content;
using Android.Views;
using Android.Views.Accessibility;
using Xamarin.Forms.Platform.Android;
namespace testEntry.Droid
{
public class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context)
{
}
public static void Focus(View view)
{
view.SendAccessibilityEvent(EventTypes.ViewFocused);
}
}
}
不幸的是,仍然没有关注我的领域:'(
有一种方法可以使用每个平台的辅助功能 API 来执行此操作。 Xamarin 表单尚不具备可访问性的所有平台功能,因此您必须创建自定义呈现器,然后在页面的生命周期事件中调用焦点方法。
因此调用此 Focus 函数会使应用程序聚焦于该元素。您通常不想这样做,因为该应用程序有目的地专注于它所做的事情,以便可访问的用户获得一致的体验。但是如果你真的想覆盖默认行为,在 Android 中是这样的
public static void Focus(View view)
{
view.SendAccessibilityEvent(EventTypes.ViewFocused);
}
并且在 iOS 中,您必须使用 PostNotification api,这将是此
的一些变体
UIAccessibility.PostNotification(UIAccessibilityPostNotification.ScreenChanged, entry element)
您可以进一步查看 Accessibility Focus 以获得确切答案
最后,感谢 Saamer,我找到了另一种方法,即使用 EventAggregator。
public class FocusChanged : PubSubEvent<String> { }
然后在我的视图模型中:
IEventAggregator _ea;
public MainPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator) : base(navigationService)
{
_ea = eventAggregator;
}
在 viewModel 中,每当我想将焦点设置到某个字段时,我都会发送一个事件:
_ea.GetEvent<FocusChanged>().Publish("Source");
在我的视图后面的代码中,我处理了这个事件:
IEventAggregator _ea;
public MainPage(IEventAggregator eventAggregator)
{
InitializeComponent();
_ea = eventAggregator;
_ea.GetEvent<FocusChanged>().Subscribe(SetFocusOnControl); //Name of method which will handle this event
}
/// set the focus on entry based on parameter
/// each event value will set focus on a specific entry (example: source is linked to entry txtScanSrc)
private async void SetFocusOnControl(String fieldName)
{
Entry l_view;
switch(fieldName)
{
case "source": l_view = this.FindByName<Entry>("txtScanSrc"); break;
case "quantity": l_view = this.FindByName<Entry>("txtQty"); break;
case "tote": l_view = this.FindByName<Entry>("txtScanTote"); break;
case "pallet": l_view = this.FindByName<Entry>("txtScanPalout"); break;
case "destination": l_view = this.FindByName<Entry>("txtScanDest"); break;
default: l_view = this.FindByName<Entry>("txtScanSrc"); break;
}
await WaitAndExecute(500, () => { l_view.Focus(); });
}
我正在使用 Xamarin.Forms 和 Prism 来创建我的移动应用程序。
我有一个包含 2 个条目的屏幕。进入屏幕时,我想将焦点设置在第一个条目上。 然后在用户在此条目中输入数据并验证后,我想将焦点设置到第二个条目。
基于第一个答案: 我应该做错事。我创建了一个新的 Prism 小项目来测试它:
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:testEntry"
x:Class="testEntry.Views.MainPage"
Title="{Binding Title}">
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Welcome to Xamarin Forms and Prism!" />
<local:MyEntry Placeholder="" x:Name="entry1" />
<Button Text="set focus on entry1" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
using Xamarin.Forms;
namespace testEntry.Views
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
entry1.Focus(); //Not Working
}
private void Button_Clicked(object sender, EventArgs e)
{
entry1.Focus(); //Working
}
}
}
MyEntry.cs(在主项目中)
using Xamarin.Forms;
namespace testEntry
{
public class MyEntry : Entry
{
}
}
MyEntryRenderer.cs(在 Android 项目中)
using Android.Content;
using Android.Views;
using Android.Views.Accessibility;
using Xamarin.Forms.Platform.Android;
namespace testEntry.Droid
{
public class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context)
{
}
public static void Focus(View view)
{
view.SendAccessibilityEvent(EventTypes.ViewFocused);
}
}
}
不幸的是,仍然没有关注我的领域:'(
有一种方法可以使用每个平台的辅助功能 API 来执行此操作。 Xamarin 表单尚不具备可访问性的所有平台功能,因此您必须创建自定义呈现器,然后在页面的生命周期事件中调用焦点方法。
因此调用此 Focus 函数会使应用程序聚焦于该元素。您通常不想这样做,因为该应用程序有目的地专注于它所做的事情,以便可访问的用户获得一致的体验。但是如果你真的想覆盖默认行为,在 Android 中是这样的
public static void Focus(View view)
{
view.SendAccessibilityEvent(EventTypes.ViewFocused);
}
并且在 iOS 中,您必须使用 PostNotification api,这将是此
的一些变体UIAccessibility.PostNotification(UIAccessibilityPostNotification.ScreenChanged, entry element)
您可以进一步查看 Accessibility Focus 以获得确切答案
最后,感谢 Saamer,我找到了另一种方法,即使用 EventAggregator。
public class FocusChanged : PubSubEvent<String> { }
然后在我的视图模型中:
IEventAggregator _ea;
public MainPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator) : base(navigationService)
{
_ea = eventAggregator;
}
在 viewModel 中,每当我想将焦点设置到某个字段时,我都会发送一个事件:
_ea.GetEvent<FocusChanged>().Publish("Source");
在我的视图后面的代码中,我处理了这个事件:
IEventAggregator _ea;
public MainPage(IEventAggregator eventAggregator)
{
InitializeComponent();
_ea = eventAggregator;
_ea.GetEvent<FocusChanged>().Subscribe(SetFocusOnControl); //Name of method which will handle this event
}
/// set the focus on entry based on parameter
/// each event value will set focus on a specific entry (example: source is linked to entry txtScanSrc)
private async void SetFocusOnControl(String fieldName)
{
Entry l_view;
switch(fieldName)
{
case "source": l_view = this.FindByName<Entry>("txtScanSrc"); break;
case "quantity": l_view = this.FindByName<Entry>("txtQty"); break;
case "tote": l_view = this.FindByName<Entry>("txtScanTote"); break;
case "pallet": l_view = this.FindByName<Entry>("txtScanPalout"); break;
case "destination": l_view = this.FindByName<Entry>("txtScanDest"); break;
default: l_view = this.FindByName<Entry>("txtScanSrc"); break;
}
await WaitAndExecute(500, () => { l_view.Focus(); });
}