简体   繁体   English

将焦点设置到 Xamarin.Forms 中的条目

[英]Setting the Focus to an Entry in Xamarin.Forms

This is just a simplified example, but I'm trying to set this up so that when I open up this page in my Application, the first thing that happens is the keyboard pops up ready for the user to type in their response to an Entry field.这只是一个简化的示例,但我正在尝试进行设置,以便当我在我的应用程序中打开此页面时,发生的第一件事是键盘弹出准备好让用户输入他们对条目的响应场地。

    var namelabel = new Label { Text = "What is your name?" };
    var nameentry = new Entry { Placeholder = "Type here..." };
    var colorlabel = new Label { Text = "What's your fav color?" };
    var colorentry = new Entry { Placeholder = "Type here..." };
    Content = new StackLayout {
       Spacing = 15,
       Children = { namelabel, nameentry, colorlabel, colorentry }
    };

How can I set the focus of the page to the first entry?如何将页面的焦点设置为第一个条目? And additionally, after the user has put in their first entry, how could I set this up so that the user could press a "Next" Button on the Keyboard (or something along those lines) and the app will take them to fill in the second entry?此外,在用户输入他们的第一个条目后,我如何设置它以便用户可以按下键盘上的“下一步”按钮(或类似的东西),应用程序将带他们填写第二个条目?

Use the Focus method使用Focus方法

nameentry.Focus();

If you want the focus to be set when your page appears, you should probably do this in the OnAppearing method如果您希望在页面出现时设置焦点,您可能应该在OnAppearing方法中执行此操作

    protected override void OnAppearing ()
    {
        base.OnAppearing ();

        nameentry.Focus();
    }

In one of my projects I did something like this.在我的一个项目中,我做了这样的事情。 Please try the following example:请尝试以下示例:

public class EntryFocusBehavior : Behavior<Entry>
{
    public string NextFocusElementName { get; set; }

    protected override void OnAttachedTo(Entry bindable)
    {
        base.OnAttachedTo(bindable);
        bindable.Completed += Bindable_Completed;
    }

    protected override void OnDetachingFrom(Entry bindable)
    {
        bindable.Completed -= Bindable_Completed;
        base.OnDetachingFrom(bindable);
    }

    private void Bindable_Completed(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(NextFocusElementName))
            return;

        var parent = ((Entry)sender).Parent;
        while (parent != null)
        {
            var nextFocusElement = parent.FindByName<Entry>(NextFocusElementName);
            if (nextFocusElement != null)
            {
                nextFocusElement.Focus();
                break;
            }
            else
            {
                parent = parent.Parent;
            }
        }
    }
}

And then XAML:然后是 XAML: XAML 代码

!!! !!! Please let me know if I made a mistake in the code.如果我在代码中犯了错误,请告诉我。

Just inside OnAppearing(), add the following code,就在 OnAppearing() 内部,添加以下代码,

protected async override void OnAppearing()
{
    await Task.Run(async () =>
    {
        await Task.Delay(100);
        Device.BeginInvokeOnMainThread(async () =>
        {
            txtName.Focus();
        });
    });
}

Note: txtName is the reference name of your Entry Field.注意: txtName是您的输入字段的参考名称。

Focus() needs to have a visible page and visible control to focus on. Focus() 需要有一个可见的页面和可见的控件才能聚焦。

The issue in my case was that is is necessary that OnAppearing has to exit before a page is shown / visible.在我的情况下,问题是 OnAppearing 必须在页面显示/可见之前退出是必要的。 What helped in my case is to wait for page visibility in a different thread and then set the focus in the main (UI) thread:对我来说有帮助的是在不同的线程中等待页面可见性,然后在主(UI)线程中设置焦点:

protected override void OnAppearing()
        {
            base.OnAppearing();

            Task.Run(() =>
            {
                while (!IsVisible)
                {
                    Debug.WriteLine("Page not visible, waiting...");
                    Task.Delay(50).Wait();
                }

                Device.BeginInvokeOnMainThread(() =>
                {
                    bool gotFocus = Entry.Focus();
                    if (!gotFocus)
                        Debug.WriteLine("Could not set focus.");
                });
            });
        }

So long as the element to focus on is the topmost element, this should work.只要要关注的元素是最顶层的元素,这应该可以工作。 I place this in the OnAppearing method.我把它放在OnAppearing方法中。

base.OnAppearing();
Entry entry = this.FindByName<Entry>("NameOfEntryElement");
entry.Focus();

The source of this info is here: https://forums.xamarin.com/discussion/100354/entry-focus-not-working-for-android此信息的来源在这里: https ://forums.xamarin.com/discussion/100354/entry-focus-not-working-for-android

There is further discussion in the article about timing issues.文章中有关于时间问题的进一步讨论。

I know this is an old thread but this might work for someone as it worked for me.我知道这是一个旧线程,但这可能对某人有用,因为它对我有用。

protected override async void OnAppearing()
{
    base.OnAppearing();
    await Task.Delay(500);
    await Task.Run(() =>
    {
        entryname.Focus();
    });
}

It's possible that Focus or RequestFocus because your control didn't load again. FocusRequestFocus可能是因为您的控件没有再次加载。 You can override onAppearing but even if you use that, it may possible that didn't work because the control is not set again.您可以覆盖onAppearing但即使您使用它,也可能无法正常工作,因为没有再次设置控件。

So you can use onAppearing, but for the fist apparing you may use Xamarin community toolkit .所以你可以使用 onAppearing,但对于第一个出现,你可以使用Xamarin community toolkit And LifeCycleEffect和 LifeCycleEffect

<Entry x:Name="myEntry"> 
    <Entry.Effects> 
        <xct:LifecycleEffect Loaded="LifeCycleEffect_Loaded" /> 
    </Entry.Effects> 
</Entry>

Here in C#在 C# 中

void LifeCycleEffect_Loaded(object? sender, EventArgs e)
{
    if ( sender is Entry && (sender as Entry ).Name != null && (sender as Entry).Name.Equals("myEntry") )
        // myEntry.Focus() or myEntry.RequestFocus() or (sender as Entry).Focus()
}

I suggest you to take notes from this link我建议你从这个链接做笔记

https://docs.microsoft.com/en-us/xamarin/community-toolkit/effects/lifecycleeffect https://docs.microsoft.com/en-us/xamarin/community-toolkit/effects/lifecycleeffect

Can anyone explain to me why this doesn't work谁能向我解释为什么这不起作用

    protected override void OnAppearing()
    {
       base.OnAppearing();
       CustomerNameEntry.Focus();       
    }

But this does (adding async and Task.Delay(1))但这确实(添加 async 和 Task.Delay(1))

    protected override async void OnAppearing()
    {
         base.OnAppearing();
         await Task.Delay(1);
         CustomerNameEntry.Focus();       
    }

I'd rather not add this clutter, it seems hacky but it's the only way I've been able to get it to work (I've also tried invoking on main thread, to no avail).我宁愿不添加这种混乱,它看起来很hacky,但这是我能够让它工作的唯一方法(我也尝试过在主线程上调用,但无济于事)。

The simple one did not work for me:简单的对我不起作用:

protected override void OnAppearing()
{
    MyEntry.Focus();
}

I had to wait an unspecified amount of time, but did not want to wait longer than necessary.我不得不等待一段未指定的时间,但不想等待超过必要的时间。 Also, I didn't want to pollute OnAppearing() with delay code, so implemented a helper with a Focus methdo that works:此外,我不想用延迟代码污染 OnAppearing(),因此使用有效的 Focus 方法实现了一个助手:

using System.Threading.Tasks;
using Xamarin.Forms;

namespace MyApp.Xmrn.Views.Helpers
{
    internal static class ViewHelper
    {
        // Disable the warning about a non-awaited async, as we use it as
        // fire and forget and return from the method immediately.
#pragma warning disable 1998, 4014

        /// <summary>
        /// Entry.Focus replacement, that tries to focus a control
        /// multiple times until it succeeds.
        /// </summary>
        /// <param name="entry">Entry control to be focused.</param>
        internal static async Task Focus(Entry entry)
        {
            Task.Run(async () =>
            {
                int threshold = 20;

                while (!entry.Focus() && threshold-- > 0)
                    await Task.Delay(50);
            });
        }
#pragma warning restore 1998, 4014
    }
}

And then to use it然后使用它

protected override async void OnAppearing()
{
    base.OnAppearing();
    await ViewHelper.Focus(MyEntry);
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    base.OnPropertyChanged(propertyName);
    if (propertyName == "Renderer")
    {
        myEntry.Focus();
    }
}

This worked perfectly for me :D这对我来说非常有用:D

protected override async void OnAppearing() {
        base.OnAppearing();
        while(!passwordInput.Focus()) { await Task.Delay(50); }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM