MAUI:如何通过MVVM将4位验证码绑定至ViewModel
MAUI验证码自定义控件绑定与状态传递实现方案
核心思路
不需要使用隐藏<Entry>,而是通过给自定义控件**添加可绑定属性(BindableProperty)**来实现验证码拼接和状态传递,既满足内部输入逻辑,又能让外部页面/ViewModel轻松获取PinEntry和IsComplete值。
步骤1:给自定义控件添加可绑定属性
在PinCodeView.xaml.cs中定义两个可绑定属性,用于外部绑定:
public partial class PinCodeView : ContentView { public PinCodeView() { InitializeComponent(); } // 完整验证码的可绑定属性,支持双向绑定 public static readonly BindableProperty PinEntryProperty = BindableProperty.Create(nameof(PinEntry), typeof(string), typeof(PinCodeView), string.Empty, BindingMode.TwoWay, propertyChanged: OnPinEntryChanged); public string PinEntry { get => (string)GetValue(PinEntryProperty); set => SetValue(PinEntryProperty, value); } // 输入完成状态的可绑定属性 public static readonly BindableProperty IsCompleteProperty = BindableProperty.Create(nameof(IsComplete), typeof(bool), typeof(PinCodeView), false); public bool IsComplete { get => (bool)GetValue(IsCompleteProperty); set => SetValue(IsCompleteProperty, value); } // 可选:当外部手动设置PinEntry时,同步到四个输入框 private static void OnPinEntryChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is PinCodeView pinView && newValue is string pin) { pinView.Pin1.Text = pin.Length >= 1 ? pin[0].ToString() : string.Empty; pinView.Pin2.Text = pin.Length >= 2 ? pin[1].ToString() : string.Empty; pinView.Pin3.Text = pin.Length >= 3 ? pin[2].ToString() : string.Empty; pinView.Pin4.Text = pin.Length >= 4 ? pin[3].ToString() : string.Empty; pinView.UpdateIsComplete(); } } }
步骤2:完善输入框的TextChanged和焦点切换逻辑
更新每个输入框的TextChanged事件,实现输入后自动跳转焦点、删除后自动回退焦点,同时实时拼接验证码并更新PinEntry和IsComplete:
// Pin1的TextChanged private void Pin1_TextChanged(object sender, TextChangedEventArgs e) { if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue.Length == 1) { Pin2.Focus(); } UpdatePinEntryAndStatus(); } // Pin2的TextChanged private void Pin2_TextChanged(object sender, TextChangedEventArgs e) { if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue.Length == 1) { Pin3.Focus(); } else if (string.IsNullOrEmpty(e.NewTextValue) && !string.IsNullOrEmpty(e.OldTextValue)) { Pin1.Focus(); Pin1.Text = string.Empty; } UpdatePinEntryAndStatus(); } // Pin3的TextChanged private void Pin3_TextChanged(object sender, TextChangedEventArgs e) { if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue.Length == 1) { Pin4.Focus(); } else if (string.IsNullOrEmpty(e.NewTextValue) && !string.IsNullOrEmpty(e.OldTextValue)) { Pin2.Focus(); Pin2.Text = string.Empty; } UpdatePinEntryAndStatus(); } // Pin4的TextChanged private void Pin4_TextChanged(object sender, TextChangedEventArgs e) { if (string.IsNullOrEmpty(e.NewTextValue) && !string.IsNullOrEmpty(e.OldTextValue)) { Pin3.Focus(); Pin3.Text = string.Empty; } UpdatePinEntryAndStatus(); } // 核心方法:拼接验证码并更新状态 private void UpdatePinEntryAndStatus() { var pin = $"{Pin1.Text}{Pin2.Text}{Pin3.Text}{Pin4.Text}"; PinEntry = pin.Trim(); UpdateIsComplete(); } // 更新输入完成状态 private void UpdateIsComplete() { IsComplete = !string.IsNullOrEmpty(Pin1.Text) && !string.IsNullOrEmpty(Pin2.Text) && !string.IsNullOrEmpty(Pin3.Text) && !string.IsNullOrEmpty(Pin4.Text); }
步骤3:外部页面绑定ViewModel属性
在使用PinCodeView的页面XAML中,直接绑定到ViewModel的PinEntry和IsComplete属性:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:controls="clr-namespace:Pincode.Controls" x:Class="Pincode.Views.PinInputPage" BindingContext="{StaticResource PinCodeViewModel}"> <StackLayout> <!-- 绑定自定义控件的属性到ViewModel --> <controls:PinCodeView PinEntry="{Binding PinEntry, Mode=TwoWay}" IsComplete="{Binding IsComplete, Mode=OneWayToSource}"/> <!-- 示例:根据IsComplete启用验证按钮 --> <Button Text="验证验证码" IsEnabled="{Binding IsComplete}" Command="{Binding VerifyPinCommand}"/> </StackLayout> </ContentPage>
步骤4:ViewModel验证逻辑(可选)
在PinCodeViewModel中添加验证命令,利用绑定后的PinEntry进行验证:
public partial class PinCodeViewModel : ObservableObject { [ObservableProperty] string _pinEntry = string.Empty; [ObservableProperty] bool _isComplete = false; [RelayCommand] void VerifyPin() { // 这里使用PinEntry做验证逻辑 if (PinEntry == "1234") { // 验证成功逻辑 } else { // 验证失败逻辑 } } }
关键说明
- 无需隐藏Entry:通过自定义控件的可绑定属性,直接将内部四个输入框的文本拼接后对外暴露,比隐藏Entry更简洁且易维护。
- 双向绑定支持:
PinEntry属性设置为双向绑定,既可以从内部输入更新外部ViewModel,也可以从外部设置值同步到内部输入框(比如重置验证码)。 - 状态自动同步:每次输入/删除都会触发
UpdatePinEntryAndStatus方法,实时更新PinEntry和IsComplete,外部页面无需手动处理。
内容的提问来源于stack exchange,提问作者SJaka
相关产品推荐
相关产品推荐

