首页 > 解决方案 > xamarin.forms:仅跟踪用户发起的更改

问题描述

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

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

后台任务时不时地向 Web 服务查询“名称”,如果找到,名称会在屏幕和持久性存储中被覆盖。不会跟踪这两个更改,因为它们不是用户发起的。

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

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

有谁能帮忙吗?谢谢!

标签: xamarin.forms

解决方案


如果您使用的是 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
    }
}

推荐阅读