You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms+Prism(MVVM)中自定义输入框如何正确设置焦点

问题根因

SacTextBox继承自ContentView,属于布局容器类型,本身不承接输入焦点。直接调用实例的Focus()方法,焦点请求只会作用在ContentView根容器上,不会传递给内部封装的名为txtBox的Entry输入控件,这就是焦点设置不生效的核心原因。

实现步骤

1. 基础改造:让自定义控件支持焦点转发

打开SacTextBox的后台代码文件SacTextBox.xaml.cs,重写基类的Focus、Unfocus方法,把焦点请求直接转发给内部的Entry控件:

public new bool Focus()
{
    // 把焦点请求透传给内部实际的输入框
    return txtBox.Focus();
}

public new void Unfocus()
{
    txtBox.Unfocus();
}

改完之后,你之前在页面代码后置写的Descripcion.Focus();就可以正常生效,适合直接在按钮点击事件(写在xaml.cs中)里调用的场景。

2. MVVM+Prism适配(推荐,符合架构规范)

Prism架构下不建议在ViewModel中直接持有控件实例,通过可绑定属性实现焦点控制更符合MVVM分层要求:

第一步:给SacTextBox添加焦点可绑定属性

在SacTextBox.xaml.cs中追加以下代码,实现支持绑定的焦点状态属性,同时同步Entry原生的焦点事件,避免状态不一致:

public static readonly BindableProperty IsFocusedProperty = BindableProperty.Create(
    propertyName: nameof(IsFocused),
    returnType: typeof(bool),
    declaringType: typeof(SacTextBox),
    defaultValue: false,
    propertyChanged: OnIsFocusedPropertyChanged);

public new bool IsFocused
{
    get => (bool)GetValue(IsFocusedProperty);
    set => SetValue(IsFocusedProperty, value);
}

private static void OnIsFocusedPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var control = bindable as SacTextBox;
    if (control == null) return;

    bool targetFocusState = (bool)newValue;
    if (targetFocusState)
        control.txtBox.Focus();
    else
        control.txtBox.Unfocus();

    // 同步Entry原生焦点事件,保证双向绑定状态一致
    control.txtBox.Focused -= control.SyncFocusStateFromEntry;
    control.txtBox.Unfocused -= control.SyncFocusStateFromEntry;
    control.txtBox.Focused += control.SyncFocusStateFromEntry;
    control.txtBox.Unfocused += control.SyncFocusStateFromEntry;
}

private void SyncFocusStateFromEntry(object sender, FocusEventArgs e)
{
    IsFocused = e.IsFocused;
}

第二步:ViewModel中添加焦点控制逻辑

在对应页面的ViewModel(当前场景下是FrmArticulosGeneralViewModel)中,添加焦点状态属性和触发命令,Prism的BindableBase已经自带属性变更通知,直接用SetProperty即可:

private bool _isDescripcionFocused;
public bool IsDescripcionFocused
{
    get => _isDescripcionFocused;
    set => SetProperty(ref _isDescripcionFocused, value);
}

private DelegateCommand _triggerFocusDescripcionCommand;
public DelegateCommand TriggerFocusDescripcionCommand =>
    _triggerFocusDescripcionCommand ??= new DelegateCommand(ExecuteTriggerFocusDescripcion);

private void ExecuteTriggerFocusDescripcion()
{
    // 先重置为false,避免重复设置true时不触发属性变更回调
    IsDescripcionFocused = false;
    IsDescripcionFocused = true;
}

第三步:页面XAML中完成绑定

修改页面XAML,给SacTextBox添加IsFocused属性绑定,给触发焦点的按钮绑定对应命令:

<sofadControls:SacTextBox
    x:Name="Descripcion"
    Grid.Column="1"
    Placeholder="Descripción"
    SacAlineacion="Start"
    SacValidacion="AlfaNumerico"
    IsFocused="{Binding IsDescripcionFocused}"
    Text="{Binding Source={RelativeSource AncestorType={x:Type dialogos:FrmArticulosGeneralViewModel}}, Path=DetalleActual.Descripcion}"/>

<!-- 触发焦点的按钮示例 -->
<Button 
    Text="定位到描述输入框"
    Command="{Binding TriggerFocusDescripcionCommand}"/>

补充注意:如果需要在页面初次加载时自动定位焦点,不要在构造函数、OnAppearing的同步逻辑中直接触发,要等页面控件渲染完成后再执行。可以借助Xamarin Community Toolkit的EventToCommandBehavior绑定页面Loaded事件触发命令,避免控件未加载完成导致焦点设置失效。

内容的提问来源于stack exchange,提问作者Angel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:30:45