Maui自定义Entry行为导致ViewModel数组Set调用失效求助
问题分析
你遇到的核心问题是:数组是引用类型,修改数组内的单个元素时,数组本身的引用并没有改变,所以ViewModel中CodeDigits的Set方法永远不会被触发——只有当你把整个数组替换成新的实例时,Set才会执行。另外你的行为中还存在事件与Command绑定不匹配的问题,导致ViewModel无法正确接收文本变更通知。
解决方案
1. 修复行为与ViewModel的Command绑定问题
你的行为中定义的EntryTextChanged是EventHandler<TextChangedEventArgs>类型,但XAML里绑定的是ICommand,两者不兼容,需要把行为中的事件改成Command属性:
public class AutoFocusBehavior : Behavior<Entry> { private string previousText = string.Empty; // 替换原有事件为Command属性 public static readonly BindableProperty TextChangedCommandProperty = BindableProperty.Create(nameof(TextChangedCommand), typeof(ICommand), typeof(AutoFocusBehavior), null); public ICommand TextChangedCommand { get => (ICommand)GetValue(TextChangedCommandProperty); set => SetValue(TextChangedCommandProperty, value); } // 原有OnAttachedTo、OnDetachingFrom、OnEntryFocused逻辑不变 private void OnEntryTextChanged(object sender, TextChangedEventArgs e) { if (sender is Entry entry) { if (e.NewTextValue.Length == 0 && e.OldTextValue.Length == 1) { if (!MoveFocusToPreviousEntry(entry)) { entry.Text = string.Empty; } } else if (e.NewTextValue.Length == 1) { entry.Unfocus(); MoveFocusToNextEntry(entry); } // 调用ViewModel的Command,传递文本变更参数 TextChangedCommand?.Execute(e); } } // 原有MoveFocusToNextEntry、MoveFocusToPreviousEntry逻辑不变 }
然后修改XAML中的绑定:
<Entry WidthRequest="40" Text="{Binding CodeDigits[0], Mode=TwoWay}" Keyboard="Numeric" MaxLength="1" HorizontalTextAlignment="Center"> <Entry.Behaviors> <b:AutoFocusBehavior TextChangedCommand="{Binding EntryTextChangedCommand}" /> </Entry.Behaviors> </Entry> <!-- 其他Entry同理修改绑定 -->
2. 解决数组元素变更不触发通知的问题
方案A:改用ObservableCollection代替数组
ObservableCollection会自动监听元素变更,更适合这种需要跟踪单个元素变化的场景:
private ObservableCollection<string> _codeDigits; public ObservableCollection<string> CodeDigits { get { return _codeDigits; } set { if (_codeDigits != value) { _codeDigits = value; RaisePropertyChanged(nameof(CodeDigits)); UpdateVerifyButtonState(); } } } public YourViewModel() { // 初始化8个空字符串元素 CodeDigits = new ObservableCollection<string>(Enumerable.Repeat(string.Empty, 8)); // 监听元素变更事件 CodeDigits.CollectionChanged += (s, e) => UpdateVerifyButtonState(); } private void UpdateVerifyButtonState() { RaisePropertyChanged(nameof(IsVerifyButtonEnabled)); } // ViewModel中的Command public ICommand EntryTextChangedCommand => new Command<TextChangedEventArgs>(args => { // 这里可以做额外的文本校验逻辑 });
方案B:保留数组,手动触发元素变更通知
如果不想替换数组,可以在每个Entry的文本变更时,手动触发对应索引的属性通知:
首先给XAML中的每个Entry添加Tag标记索引:
<Entry WidthRequest="40" Text="{Binding CodeDigits[0], Mode=TwoWay}" Keyboard="Numeric" MaxLength="1" HorizontalTextAlignment="Center" Tag="0"> <Entry.Behaviors> <b:AutoFocusBehavior TextChangedCommand="{Binding EntryTextChangedCommand}" /> </Entry.Behaviors> </Entry> <!-- 其他Entry依次设置Tag为1~7 -->
然后在ViewModel的Command中处理:
public ICommand EntryTextChangedCommand => new Command<TextChangedEventArgs>(args => { if (args.OriginalSource is Entry entry && int.TryParse(entry.Tag.ToString(), out int index)) { // 手动触发对应索引的属性通知 RaisePropertyChanged($"CodeDigits[{index}]"); // 更新按钮状态 RaisePropertyChanged(nameof(IsVerifyButtonEnabled)); } });
内容的提问来源于stack exchange,提问作者Sean Bennington
相关产品推荐
相关产品推荐

