将焦点放在Xamarin.Forms MVVM(Prism)

时间:2019-06-06 08:12:38

标签: xamarin.forms 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);
        }
    }
}

不幸的是,仍然没有专注于我的领域:'(

2 个答案:

答案 0 :(得分:0)

有一种方法可以使用每个平台的辅助功能API。 Xamarin表单尚不具备可访问性的所有平台功能,因此您必须创建一个自定义渲染器,然后在页面的生命周期事件中调用focus方法。

因此,调用此Focus函数将导致应用程序专注于该元素。您通常不希望这样做,因为该应用程序有目的地专注于它所做的事情,因此可访问的用户会获得一致的体验。但是,如果您真的想覆盖默认行为,则在Android中类似

public static void Focus(View view)
        {
view.SendAccessibilityEvent(EventTypes.ViewFocused);
        }

在iOS中,您必须使用PostNotification API,这将是此版本的

UIAccessibility.PostNotification(UIAccessibilityPostNotification.ScreenChanged, entry element)

您可以深入研究Accessibility Focus以获取确切答案

答案 1 :(得分:0)

最后,感谢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(); });
}