Xamarin.Forms中DatePicker修改Date属性时无法调用函数问题排查
WPF DatePicker绑定SelectedDate时setter调用函数报错原因
相关代码
视图层DatePicker定义:
<DatePicker MinimumDate="{Binding Today}" Date="{Binding SelectedDate, Mode=TwoWay}"/>
ViewModel层属性实现:
private DateTime selectedDate; public DateTime SelectedDate { get { return selectedDate; } set { selectedDate = value; OnPropertyChanged(nameof(SelectedDate)); // 直接调用ExecuteFunction()会触发运行时异常 } } private DateTime today; public DateTime Today { get { return today; } set { today = value; OnPropertyChanged(nameof(Today)); ExecuteFunction(); // 此处调用可正常执行 } }
异常根因
该异常属于WPF依赖属性更新流程的重入冲突:
- 用户操作DatePicker选择日期时,控件正处于
Date依赖属性的内部同步更新周期,双向绑定机制会在这个周期内同步调用ViewModel中SelectedDate的set方法。此时DatePicker的内部状态还未完成本次日期选择的全流程更新。 - 如果在
SelectedDate的setter中直接调用ExecuteFunction(),只要函数内存在触发UI线程同步更新的逻辑——比如修改Today属性(即DatePicker的MinimumDate绑定源)、触发关联UI元素重绘、间接修改SelectedDate本身的值,就会触发WPF属性系统的重入保护,抛出无效操作异常。 Today属性的setter调用不会触发该问题,是因为Today的赋值逻辑和DatePicker的Date属性更新流程不在同一个同步调用栈中,不会打断控件本身的日期选择处理流程,因此无重入冲突。
修复方案
将函数调用调度到UI线程异步执行,等当前依赖属性的同步更新流程完全结束后再运行目标逻辑,即可规避重入问题:
private DateTime selectedDate; public DateTime SelectedDate { get { return selectedDate; } set { selectedDate = value; OnPropertyChanged(nameof(SelectedDate)); // 异步调度执行,避开当前同步更新栈 Application.Current.Dispatcher.BeginInvoke( new Action(ExecuteFunction), System.Windows.Threading.DispatcherPriority.Background ); } }
如果使用CommunityToolkit.Mvvm、Prism等MVVM框架,也可以直接使用框架提供的属性变更回调异步触发逻辑,效果一致。
内容的提问来源于stack exchange,提问作者João Fernandes
相关产品推荐
相关产品推荐

