xamarin.forms:仅跟踪用户初始化的更改

xamarin.forms:仅跟踪用户初始化的更改,xamarin.forms,Xamarin.forms,我找不到满足以下要求的Xamarin.Forms应用程序的概念: 用户直接发起的对任何值的任何更改都需要加上时间戳,并在“更改表”中进行跟踪 对用户未直接启动的任何值的任何更改(例如,应用程序启动时屏幕初始化引起的更改,或后台任务拉入的更新)可能不会被跟踪。然而,它们需要出现在屏幕上 示例:屏幕上有一个“名称”输入。在应用程序首次加载时,输入的姓氏将从某个本地持久性存储中提取,并写入屏幕,但不会记录此更改 偶尔有一个后台任务向web服务查询“名称”,如果它找到了一个,名称就会在屏幕上和持久性

我找不到满足以下要求的Xamarin.Forms应用程序的概念:

  • 用户直接发起的对任何值的任何更改都需要加上时间戳,并在“更改表”中进行跟踪

  • 对用户未直接启动的任何值的任何更改(例如,应用程序启动时屏幕初始化引起的更改,或后台任务拉入的更新)可能不会被跟踪。然而,它们需要出现在屏幕上

示例:屏幕上有一个“名称”输入。在应用程序首次加载时,输入的姓氏将从某个本地持久性存储中提取,并写入屏幕,但不会记录此更改

偶尔有一个后台任务向web服务查询“名称”,如果它找到了一个,名称就会在屏幕上和持久性存储中被覆盖。这两个更改都不会被跟踪,因为它们不是由用户发起的

但是,一旦用户输入了一个名称,该值就会存储在持久性存储中,并且更改会被跟踪(时间戳)并写入本地持久性存储中的“更改表”

相同的原则必须适用于所有Xamarin.forms控件,例如开关。如果“完成”绑定到bool属性的开关由用户翻转,需要跟踪更改,如果开关是在初始化期间或通过后台更新设置的,则不得跟踪。我提到了开关控件,因为我已经遇到了SO和其他地方描述的Xamarin.forms开关控件的特定问题(如果以编程方式更改基础值,则OnToggled意外激发)


有谁能帮忙吗?Thx!

如果您使用的是MVVM模式,您可以执行以下操作:

为记录的视图模型创建抽象

public interface ILoggedViewModel : INotifyPropertyChanged
{
    bool IsChangingProgrammatically { get; }
}
必须记录的每个viewmodel(很可能是每个viewmodel)都将实现此接口(包括
PropertyChanged
事件,该事件由
INotifyPropertyChanged
定义)(一个非常好的解决方案是DI,例如,使用Prisms
ViewModelLocator
-可能需要手动注册viewmodels)您将它们注册到订阅
PropertyChanged
事件的类中

在以编程方式更改任何属性之前,请将
ischangingprogrammetically
设置为
true
,然后将其重置(可能在
finally
-块中,以防止出现异常时不重置属性)。每当引发
PropertyChangedEvent
时,将调用记录器上的处理程序。然后记录器以编程方式检查发送方上的
ischanging
,如果为
false
,则假定更改已由用户启动并记录活动

编辑:

为了使其正常工作,您不能在开始长时间运行操作之前以编程方式设置
ischanging
,然后再重置它,而只能在设置值的前后进行设置,否则长时间运行操作期间的用户交互将不会被记录

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) { }
}
在基本viewmodel中声明如下内容

void ChangePropertyBackingField<T>(ref T backingField, string propertyName, T value)
{
    backingField = value;
    PropertyChanged?.Invoke(this, new PropertyChangedProgrammaticallyEventArgs(propertyName));
}

我已经有过这样的方法,失败有两个原因:-一旦后台任务启动并开始更新项目,就会设置IsCachChange编程标志。虽然任务尚未完成,但用户更改的项目不会记录。-应用程序对数据库进行初始读取时也会出现同样的问题。根据您上次的edit:围绕每个单独的项进行编程设置是否确实解决了丢失用户更新日志记录的问题?我想这种方法只会减少日志中丢失用户更改的可能性。您不会100%确定不会发生这种情况,但我认为Xamarin.Forms在任何方面都不具备执行更新的能力无论如何,用户交互的日志记录。这种可能性有多大,取决于许多因素,例如,值以编程方式更改的频率。@Nimral还有另一种可能性,请参阅我的第二次编辑。通过这种方式,您应该能够区分用户交互和编程交互。感谢Paul提供的Edit2,还没有尝试过,但它看起来是v非常有希望。如果我测试它,我会让你知道会发生什么。
void OnPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
{
    if(!(eventArgs is PropertyChangedProgrammaticallyEventArgs ))
    {
        // log user interaction
    }
}