我有一个场景,使用
INotifyPropertyChanged
接口从 ViewModel 更新 View 是不合适的。
相反,我想显式刷新一些绑定。
在 WPF 中,这似乎可以通过从控件获取
BindingExpression
并调用 BindingExpression.UpdateTarget()
来实现(请参阅如何强制刷新 WPF 绑定?)。
毛伊岛也可能有类似的事情吗?
BindingExpression
根本不存在...
背景
我正在显示一个项目列表,每个项目都有一个
CreatedAt
时间戳。例如,在用户界面中,我想将其显示为“7 分钟前”。因此,我创建了一个值转换器,将 DateTime
转换为字符串。当然,显示的字符串应该随着时间的推移而更新。
恕我直言,在这种情况下,更新 UI 中的文本应该是视图的问题。我不想在我的 ViewModel 中有间隔计时器。我更喜欢在我的视图中(在后面的代码中)有一个间隔计时器,它只刷新当前可见的那些项目的绑定。
“恕我直言,更新 UI 中的文本应该是 View 的问题 这个案例。我不想在我的 ViewModel 中有间隔计时器。我 更喜欢在我的视图中(在后面的代码中)有一个间隔计时器 仅刷新当前可见的那些项目的绑定。”
我想指出一些关于 MVVM 的重要内容。
遵循 MVVM 架构时,ViewModel 不应该了解有关 View 的任何信息。但是,您的视图始终可以访问 ViewModel。
您可以随时从 ViewModel 调用方法。无论是作为对事件的响应、收到的消息还是其他东西。
您的 View 应该已经保存了对 ViewModel 的引用,因此通过创建计时器并调用方法来更新数据,您将不会违反任何 MVVM 原则。
(如果我还没有说服你,请告诉我继续...)
不幸的是,Maui 缺乏任何方法来访问绑定表达式。
一种解决方案是创建执行您想要的操作的视图属性,并在计时器上触发属性更改:
<Label Text="{Binding RelativeTime1, Source={RelativeSource Self}}" />
在视图的代码隐藏中:
MyViewModel VM => BindingContext as MyViewModel;
public RelativeTime1 => AsRelativeTime(VM.Time1);
// Each timer tick
public void Elapsed()
{
OnPropertyChanged(nameof(RelativeTime1));
}
在 Xamarin 情况下,我使用这个辅助方法(我希望在 MAUI 中也一样)
internal static void ApplyBinding(this BindableObject bindableObject, BindableProperty property)
{
var binding = bindableObject.GetBindableObject(property);
var tBinding = typeof(BindingBase);
var mUnapply = tBinding.GetMethod("Unapply", BindingFlags.NonPublic | BindingFlags.Instance);
mUnapply?.Invoke(binding, new object[] { false });
var mApply = tBinding.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(v => v.Name == "Apply" && v.GetParameters().Length > 2);
mApply?.Invoke(binding, new[] { bindableObject.BindingContext, bindableObject, property, false });
}
计时器“Elapsed”后面的代码中的用法是(如果我们在自定义 TabView 类中)
this.ApplyBinding(TabItemsSourceProperty);