簡體   English   中英

將焦點設置到 Xamarin.Forms 中的條目

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

這只是一個簡化的示例,但我正在嘗試進行設置,以便當我在我的應用程序中打開此頁面時,發生的第一件事是鍵盤彈出准備好讓用戶輸入他們對條目的響應場地。

    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 }
    };

如何將頁面的焦點設置為第一個條目? 此外,在用戶輸入他們的第一個條目后,我如何設置它以便用戶可以按下鍵盤上的“下一步”按鈕(或類似的東西),應用程序將帶他們填寫第二個條目?

使用Focus方法

nameentry.Focus();

如果您希望在頁面出現時設置焦點,您可能應該在OnAppearing方法中執行此操作

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

        nameentry.Focus();
    }

在我的一個項目中,我做了這樣的事情。 請嘗試以下示例:

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;
            }
        }
    }
}

然后是 XAML: XAML 代碼

!!! 如果我在代碼中犯了錯誤,請告訴我。

就在 OnAppearing() 內部,添加以下代碼,

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

注意: txtName是您的輸入字段的參考名稱。

Focus() 需要有一個可見的頁面和可見的控件才能聚焦。

在我的情況下,問題是 OnAppearing 必須在頁面顯示/可見之前退出是必要的。 對我來說有幫助的是在不同的線程中等待頁面可見性,然后在主(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.");
                });
            });
        }

只要要關注的元素是最頂層的元素,這應該可以工作。 我把它放在OnAppearing方法中。

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

此信息的來源在這里: https ://forums.xamarin.com/discussion/100354/entry-focus-not-working-for-android

文章中有關於時間問題的進一步討論。

我知道這是一個舊線程,但這可能對某人有用,因為它對我有用。

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

FocusRequestFocus可能是因為您的控件沒有再次加載。 您可以覆蓋onAppearing但即使您使用它,也可能無法正常工作,因為沒有再次設置控件。

所以你可以使用 onAppearing,但對於第一個出現,你可以使用Xamarin community toolkit 和 LifeCycleEffect

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

在 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()
}

我建議你從這個鏈接做筆記

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

誰能向我解釋為什么這不起作用

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

但這確實(添加 async 和 Task.Delay(1))

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

我寧願不添加這種混亂,它看起來很hacky,但這是我能夠讓它工作的唯一方法(我也嘗試過在主線程上調用,但無濟於事)。

簡單的對我不起作用:

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

我不得不等待一段未指定的時間,但不想等待超過必要的時間。 此外,我不想用延遲代碼污染 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
    }
}

然后使用它

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();
    }
}

這對我來說非常有用: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