在xamarin形式的listview内随机触发进入控制焦点未聚焦事件



在我的xamarin表单项目中,我有一个带有listview的屏幕,其中包含Entry和其他控件的编号。对于条目,我定义了text_changed、focus和unfocus事件的功能。并且条目具有十进制键盘(只接受十进制)

问题:每当我尝试输入数字时,预期的行为是触发text_changed,但它也会触发两次unfocus和focus事件
[输入text->text_changed->unfocus->focus->unfous->focus]。正因为如此,我在各个事件中所写的所有逻辑都被打乱了,并显示出奇怪的行为
这一个在iOS中正常工作,仅在Android中显示此问题。
代码:

<DataTemplate x:Key="Numeric">
<ViewCell>
<ViewCell.View>
<StackLayout Padding="0">
<StackLayout Spacing="0" Padding="10">
<Grid ColumnSpacing="0" Padding="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:CustomLabel Text="{Binding .Question}" Style="{StaticResource ListItemInspectionLabelStyleWordwrap}" HorizontalOptions="Start" VerticalOptions="Start" Grid.Row="0" Grid.Column="0" />
<controls:CustomEntry x:Name="InputEntry" IsEnabled="{Binding .CanRespond}" FontSize="12" TextChanged="OnNumericTextChanged" HeightRequest="50" Keyboard="Numeric" Focused="OnNumericFocus" Unfocused="OnNumericUnFocus" HorizontalOptions="FillAndExpand" VerticalOptions="End"
ClassId="{Binding .QuestionId}" Grid.Row="1" Grid.Column="0" />
<controls:ExtendedLabel x:Name="NumberHint" TextColor="#71797B" LineBreakMode="NoWrap"  Text="{Binding NumericFieldTitle}" Style="{StaticResource ListItemInspectionLabelStyleWordwrap}"
HorizontalOptions="Start" VerticalOptions="Start" Grid.Row="2" Grid.Column="0" />
</Grid>
</StackLayout>
<BoxView Style="{StaticResource ListDividerStyle}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>

对于条目,我已经为一些对齐编写了渲染器:

[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
namespace Inspect.Droid
{ 
public class CustomEntryRenderer : EntryRenderer
{ 
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.SetBackgroundColor(global::Android.Graphics.Color.Rgb(230, 230, 230));
Control.SetTextColor(global::Android.Graphics.Color.Black);
var nativeEditText = (global::Android.Widget.EditText)Control;
nativeEditText.SetTextColor(Android.Graphics.Color.Black);
nativeEditText.SetBackgroundResource(Resource.Drawable.inspection_editor_background);
nativeEditText.SetPadding(30, 0, 0, 0);
nativeEditText.Gravity = Android.Views.GravityFlags.CenterVertical; 
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var nativeEditText = (global::Android.Widget.EditText)Control;
nativeEditText.SetPadding(30, 0, 0, 0);
nativeEditText.Gravity = Android.Views.GravityFlags.CenterVertical;
}
}
}

即使我也很少看到有帖子报道同样的问题,但没有得到任何解决方案/解决方案。xamarin bugzilla中也报告了同样的问题,在ViewCells中选择条目控件会导致FocusChange周期以及在其他链路中

由于我的需求只适用于此事件,我没有其他方法来实现它。请为我提供此实现的任何解决方案/解决方案或提示/链接
感谢

我在测试Forms 2.3.3.180时重新访问了您提到的焦点循环错误,从中可以看出,焦点循环来自ListView上激发的OnLayout()。我不知道为什么叫它,但我觉得这可能与键盘的出现有关。

但是,即使调用了它,位置和大小似乎也不会改变,changed参数设置为false也支持这一点。因此,您可以创建一个自定义ListView渲染器,并覆盖OnLayout(),使其在changed == false时不调用base。

我确实在错误报告中的示例项目中尝试了这一点,它似乎解决了这个问题。然而,作为免责声明,我要说的是,我没有对其进行广泛的测试,并且鉴于示例项目很简单,这样做可能会在您的应用程序中出现其他问题。

[assembly: ExportRenderer(typeof(EntryListView), typeof(EntryListViewRenderer))]
namespace ListViewCheck.Droid
{
public class EntryListViewRenderer: ListViewRenderer
{
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
if (changed)
base.OnLayout(changed, l, t, r, b);
}
}
}

我更新了jimmgarr的解决方法,用false调用Onlyout,以在启动时渲染listview。

public class EntryListViewRenderer : ListViewRenderer
{
private int countCaller = 0;
public EntryListViewRenderer(Context context) : base(context)
{
}        
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == VisualElement.IsVisibleProperty.PropertyName)
{
countCaller = 0;
}
}

protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
if (changed)
{
base.OnLayout(changed, l, t, r, b);
}
else
{
if (countCaller == 0)
{
base.OnLayout(changed, l, t, r, b);
countCaller++;
}
}
}
}

在此"base.OnElementChanged(e);"之后添加此行---->"var baseEntry=Element as Entry;">

并通过在"if(e.OldElement==null)"内添加此行-->"baseEntry.focus();"来获得条目焦点

最新更新