我无法找到符合以下要求的Xamarin.Forms应用程序的概念:
对用户直接发起的任何值的任何更改都需要在“更改表”中加上时间戳和跟踪
对用户未直接启动的任何值的任何更改(例如,应用程序启动时屏幕初始化引起的更改,或后台任务引入的更新)都可能无法跟踪。然而,他们需要出现在屏幕上。
示例:在屏幕上,有一个“名称”输入。在应用程序首次加载时,输入的姓氏将从某个本地持久性存储中提取,并写入屏幕,但不会记录此更改。
后台任务会不时地向Web服务查询“名称”,如果找到,则在屏幕上和持久性存储中覆盖名称。两个更改都不会被跟踪,因为它们不是用户启动的。
但是,一旦用户键入名称,该值就会存储在持久性存储中,并且会跟踪更改(加时间戳并写入本地持久性存储中的“更改表”。
同样的原则必须适用于所有Xamarin.forms控件,例如:开关也是。如果用户翻转了绑定到bool属性的“done”开关,则需要跟踪更改,如果在初始化期间设置了开关,或者通过后台更新,则不能跟踪它。我提到了开关控制,因为我已经遇到了在SO和其他地方描述的Xamarin.forms开关控件的特定问题(如果以编程方式更改了基础值,OnToggled意外触发)。
任何可以提供帮助的人? THX!
答案 0 :(得分:0)
如果您使用的是MVVM模式,则可以执行以下操作:
为已记录的视图模型创建抽象
public interface ILoggedViewModel : INotifyPropertyChanged
{
bool IsChangingProgrammatically { get; }
}
您必须记录的每个viewmodel(可能是每个viewmodel)都将实现此接口(包括由PropertyChanged
定义的INotifyPropertyChanged
事件)。当您创建视图模型时(一个非常好的解决方案是DI,例如使用Prisms ViewModelLocator
- 也许你必须手动注册视图模型)你用一个订阅{{1}的类注册它们事件。
在以编程方式更改任何属性之前,将PropertyChanged
设置为IsChangingProgrammatically
并在之后重置(可能在true
- 块中,以防止在异常情况下不重置属性) 。每当引发finally
时,都会调用记录器上的处理程序。然后记录器检查发件人PropertyChangedEvent
,如果IsChangingProgrammatically
,则假定更改已由用户启动并记录活动。
修改强>
为了使其正常工作,您无法在开始长时间运行操作之前设置false
并在之后重置它,但只能设置值,否则在长时间运行操作期间的用户交互将赢得不记录了。
IsChangingProgrammatically
编辑2:
有一种方法可以避免这些时间问题。您可以创建一个private async void UpdateData()
{
try
{
var data = await _repository.GetData();
this.IsChangingProgrammatically = true;
Data = data;
}
finally
{
this.IsChangingProgrammatically = false;
}
}
的衍生物,该衍生物被抛出以指示某个属性已经过编程更改
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));
}
实现,但仍会导致UI更新。这样,您可以更改记录器中其他更改的程序更改
PropertyChangedEventArgs