将焦点设置到 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 }
};
如何将页面焦点设置到第一个条目?此外,在用户输入他们的第一个条目后,我如何设置它以便用户可以按键盘上的 "Next" 按钮(或类似的东西)并且应用程序将让他们填写在第二个条目中?
使用Focus
方法
nameentry.Focus();
如果您希望在您的页面出现时设置焦点,您应该在 OnAppearing
方法中执行此操作
protected override void OnAppearing ()
{
base.OnAppearing ();
nameentry.Focus();
}
只要要关注的元素是最顶层的元素,这应该可行。我把它放在 OnAppearing
方法中。
base.OnAppearing();
Entry entry = this.FindByName<Entry>("NameOfEntryElement");
entry.Focus();
此信息的来源在这里:
https://forums.xamarin.com/discussion/100354/entry-focus-not-working-for-android
文章中有关于计时问题的进一步讨论。
在我的一个项目中,我做了这样的事情。请尝试以下示例:
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:
!!!如果我在代码中犯了错误,请告诉我。
就在 OnAppearing() 里面,添加下面的代码,
protected async override void OnAppearing()
{
await Task.Run(() =>
{
Task.Delay(100);
Device.BeginInvokeOnMainThread(async () =>
{
txtName.Focus();
});
});
}
注意:txtName 是您输入字段的参考名称。
任何人都可以向我解释为什么这不起作用
protected override void OnAppearing()
{
base.OnAppearing();
CustomerNameEntry.Focus();
}
但是这样做(添加异步和 Task.Delay(1))
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.Delay(1);
CustomerNameEntry.Focus();
}
我不想添加这种混乱,它看起来很老套,但这是我让它工作的唯一方法(我也试过在主线程上调用,但无济于事)。
我知道这是一个旧线程,但这可能对某些人有用,因为它对我有用。
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.Delay(500);
await Task.Run(() =>
{
entryname.Focus();
});
}
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.");
});
});
}
简单的方法对我不起作用:
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); }
}
可能 Focus
或 RequestFocus
因为您的控件没有再次加载。您可以覆盖 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()
}
我建议你从这个做笔记link
https://docs.microsoft.com/en-us/xamarin/community-toolkit/effects/lifecycleeffect
这只是一个简化的示例,但我正在尝试对其进行设置,以便当我在我的应用程序中打开此页面时,首先发生的事情是弹出键盘供用户输入他们对输入字段的响应。
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 }
};
如何将页面焦点设置到第一个条目?此外,在用户输入他们的第一个条目后,我如何设置它以便用户可以按键盘上的 "Next" 按钮(或类似的东西)并且应用程序将让他们填写在第二个条目中?
使用Focus
方法
nameentry.Focus();
如果您希望在您的页面出现时设置焦点,您应该在 OnAppearing
方法中执行此操作
protected override void OnAppearing ()
{
base.OnAppearing ();
nameentry.Focus();
}
只要要关注的元素是最顶层的元素,这应该可行。我把它放在 OnAppearing
方法中。
base.OnAppearing();
Entry entry = this.FindByName<Entry>("NameOfEntryElement");
entry.Focus();
此信息的来源在这里: https://forums.xamarin.com/discussion/100354/entry-focus-not-working-for-android
文章中有关于计时问题的进一步讨论。
在我的一个项目中,我做了这样的事情。请尝试以下示例:
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:
!!!如果我在代码中犯了错误,请告诉我。
就在 OnAppearing() 里面,添加下面的代码,
protected async override void OnAppearing()
{
await Task.Run(() =>
{
Task.Delay(100);
Device.BeginInvokeOnMainThread(async () =>
{
txtName.Focus();
});
});
}
注意:txtName 是您输入字段的参考名称。
任何人都可以向我解释为什么这不起作用
protected override void OnAppearing()
{
base.OnAppearing();
CustomerNameEntry.Focus();
}
但是这样做(添加异步和 Task.Delay(1))
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.Delay(1);
CustomerNameEntry.Focus();
}
我不想添加这种混乱,它看起来很老套,但这是我让它工作的唯一方法(我也试过在主线程上调用,但无济于事)。
我知道这是一个旧线程,但这可能对某些人有用,因为它对我有用。
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.Delay(500);
await Task.Run(() =>
{
entryname.Focus();
});
}
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.");
});
});
}
简单的方法对我不起作用:
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); }
}
可能 Focus
或 RequestFocus
因为您的控件没有再次加载。您可以覆盖 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()
}
我建议你从这个做笔记link
https://docs.microsoft.com/en-us/xamarin/community-toolkit/effects/lifecycleeffect