xamarin.forms - xamarin.forms:仅跟踪用户发起的更改
问题描述
我找不到满足以下要求的 Xamarin.Forms 应用程序的概念:
对用户直接发起的任何值的任何更改都需要在“更改表”中添加时间戳和跟踪
任何不是由用户直接发起的值的更改(例如,应用程序启动时屏幕初始化引起的更改,或后台任务拉入的更新)可能不会被跟踪。然而,它们需要出现在屏幕上。
示例:在屏幕上,有一个“名称”输入。在应用程序首次加载时,输入的姓氏是从某个本地持久性存储中提取的,并写入屏幕,但不会记录此更改。
后台任务时不时地向 Web 服务查询“名称”,如果找到,名称会在屏幕和持久性存储中被覆盖。不会跟踪这两个更改,因为它们不是用户发起的。
但是,一旦用户键入名称,该值就会存储在持久性存储中,并且会跟踪更改(带有时间戳并写入本地持久性存储中的“更改表”。
相同的原则必须适用于所有 Xamarin.forms 控件,例如开关。如果绑定到 bool 属性的“完成”开关被用户翻转,则需要跟踪更改,如果在初始化期间或通过后台更新设置开关,则不得跟踪更改。我提到了开关控件,因为我已经遇到了在 SO 和其他地方描述的 Xamarin.forms 开关控件的特定问题(如果以编程方式更改基础值,则 OnToggled 会意外触发)。
有谁能帮忙吗?谢谢!
解决方案
如果您使用的是 MVVM 模式,则可以执行以下操作:
为记录的视图模型创建抽象
public interface ILoggedViewModel : INotifyPropertyChanged
{
bool IsChangingProgrammatically { get; }
}
您必须记录的每个视图模型(很可能是每个视图模型)都将实现此接口(包括由PropertyChanged
定义的事件INotifyPropertyChanged
)。当您创建视图模型时(一个非常好的解决方案是 DI,例如使用 Prisms ViewModelLocator
- 也许您必须手动注册视图模型)您使用订阅PropertyChanged
事件的类注册它们。
IsChangingProgrammatically
在以编程方式更改任何属性之前,您设置true
并在之后重置它(可能在finally
-block 中,以防止在发生异常时不会重置属性)。每当PropertyChangedEvent
引发 时,都会调用记录器上的处理程序。然后记录器检查IsChangingProgrammatically
发件人,如果它false
假定更改是由用户启动的并记录活动。
编辑:
为了让它正常工作,不能IsChangingProgrammatically
在开始长时间运行操作之前设置,然后再重新设置,只能围绕设置值进行,否则不会记录长时间运行操作期间的用户交互。
private async void UpdateData()
{
try
{
var data = await _repository.GetData();
this.IsChangingProgrammatically = true;
Data = data;
}
finally
{
this.IsChangingProgrammatically = false;
}
}
编辑2:
有一种方法可以避免这些时间问题。您可以从中创建一个衍生品PropertyChangedEventArgs
,以指示属性已以编程方式更改
class PropertyChangedProgrammaticallyEventArgs : PropertyChangedEventArgs
{
public PropertyChangedProgrammaticallyEventArgs (string propertyName) : base(propertyName) { }
}
在您的基本视图模型中,您声明类似
void ChangePropertyBackingField<T>(ref T backingField, string propertyName, T value)
{
backingField = value;
PropertyChanged?.Invoke(this, new PropertyChangedProgrammaticallyEventArgs(propertyName));
}
当属性以编程方式更改时创建特殊PropertyChangedEventArgs
实现,但仍会导致 UI 更新。通过这种方式,您可以根据记录器中的其他更改更改编程更改
void OnPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
{
if(!(eventArgs is PropertyChangedProgrammaticallyEventArgs ))
{
// log user interaction
}
}
推荐阅读
- scala - 并行转换和持久化 Spark DStream 到几个不同的位置?
- javascript - 合并两个 JSONata 表达式
- ios - iOS 13.1 不接收静默 CKQuerySubscription 通知
- javascript - vuejs - 如何捕获输入名称中的值?
- javascript - Firebase 返回 [object Object]
- javascript - 发送给 DM.player() 的第一个参数无效,该元素已经是一个播放器
- kubernetes - 在 knative 服务定义中更改公共 url
- python - 根据部分标签更改饼图颜色(pandas/matplotlib)
- javascript - 如何将元素传递给 setTimeOut 函数
- sql - 同一行内连接两次