猿问

属性初始化后,有没有办法在 Xamarin ViewModel 中设置脏标志?

我想为视图模型中的任何必需属性设置脏标志。我IsDirty在构造函数中初始化为 false。不幸的是,我的属性中的所有设置器都是在构造函数之后调用的。有没有办法IsDirty在所有设置器之后将其设置为 false?二传手都有一条线IsDirty=true;


我将 Prism 框架与 Xamarin 4.0 一起使用,但 Prism 文档没有有关 ViewModel 生命周期的任何内容。


我的编辑构造函数如下所示:


public SomeDetailsViewModel(INavigationService navigationService) : base(navigationService)

{

    Sample = new SampleDTO();


    InitializeLookupValues();


    _samplesService = new SampleService(BaseUrl);


    TextChangedCommand = new Command(() => OnTextChanged());

    AddSampleCommand = new Command(() => AddCurrentSample());

    CancelCommand = new Command(() => Cancel());


    IsDirty = false;


}

编辑3:


构造函数调用InitializeLookupValues(). 这些似乎是罪魁祸首。


private async Task InitializeLookupValues()

        {

            App app = Prism.PrismApplicationBase.Current as App;

            string baseUrl = app.Properties["ApiBaseAddress"] as string;


            _lookupService = new LookupDataService(baseUrl);


            int TbId = app.CurrentProtocol.TbId;

            int accessionId = CollectionModel.Instance.Accession.AccessionId;

            Parts = await _lookupService.GetParts(accessionId);//HACK


            Containers = await _lookupService.GetSampleContainers(TbId);

            Additives = await _lookupService.GetAdditives(TbId);

            UnitsOfMeasure = await _lookupService.GetUnitsOfMeasure();

            

            // with a few more awaits not included.

        }

退出构造函数后,每个属性都会被设置。他们看起来像这个。


public ObservableCollection<PartDTO> Parts

{

    get

    {

        return parts;

    }

    set

    {

        SetProperty(ref parts, value);

    }

}

private PartDTO part;

public PartDTO SelectedPart

{

    get

    {

        return part;

    }

    set

    {

        SetProperty(ref part, value);

        

        IsDirty = true;

    }

}

其中 IsDirty 定义如下:


private bool isDirty;

public bool IsDirty

{

    get

    {

        return isDirty;

    }

    set

    {

        SetProperty(ref isDirty, value);

        Sample.DirtyFlag = value;

    }

}

饮歌长啸
浏览 118回答 2
2回答

慕码人2483693

有没有办法IsDirty在所有设置器之后将其设置为 false?setter 不是自己调用的,必须有人调用他们。您应该确定是谁在这样做,并且要么阻止他在没有充分理由的情况下设置内容(首选),要么让他在完成后重置脏标志。正如评论中所建议的,在设置器中添加断点并查看堆栈跟踪是查找设置来源的一个很好的起点......如果我不得不猜测,我会怀疑一些与导航相关的回调。但是您应该尝试确保视图模型在构造函数之后初始化,这IsDirty实际上意味着“已通过视图更改”而不是“可能由用户更改,也可能只是延迟初始化的一部分”。经过多次编辑后,我的编辑:您应该修改架构以考虑视图模型的异步初始化。仅仅并行运行所有事情并希望得到最好的结果很少会奏效。例如,您可以将属性设置为只读,直到初始化完成,然后IsDirty在.falseInitializeLookupValues伪代码:Constructor(){&nbsp; &nbsp; Task.Run( async () => await InitializeAsync() );}string Property{&nbsp; &nbsp; get => _backingField;&nbsp; &nbsp; set&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (_isInitialized && SetProperty( ref _backingField, value ))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _isDirty = true;&nbsp; &nbsp; }}private async Task InitializeAsync(){&nbsp; &nbsp; await SomeAsynchronousStuff();&nbsp; &nbsp; _isInitialized = true;}private bool _isInitialized;private bool _isDirty;也许,您想将_isInitialized其作为属性公开给视图以显示一些沙漏,并使用 aManualResetEvent而不是简单的bool... 但您明白了。

慕田峪7331174

由于这些SetProperty方法是可重写的,因此您可以注入一些自定义逻辑。当您需要验证对象是否已被更改时,这可能非常有用。public class StatefulObject : Prism.Mvvm.BindableBase{&nbsp; &nbsp; private bool _isDirty;&nbsp; &nbsp; public bool IsDirty&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; get => _isDirty;&nbsp; &nbsp; &nbsp; &nbsp; private set => SetProperty(ref _isDirty, value);&nbsp; &nbsp; }&nbsp; &nbsp; protected override bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var isDirty = base.SetProperty(ref storage, value, onChanged, propertyName);&nbsp; &nbsp; &nbsp; &nbsp; if(isDirty && propertyName != nameof(isDirty))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IsDirty = true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return isDirty;&nbsp; &nbsp; }&nbsp; &nbsp; public void Reset() => IsDirty = false;}请记住,当您初始化字段时,此IsDirty值为 true,因此在绑定之前,您需要调用该Reset方法将其设置IsDirty回 false,这样您就可以可靠地知道字段何时已更改。请注意,如何处理这个问题在某种程度上取决于您。例如,您可以使用 Linq 执行此操作...var fooDTOs = someService.GetDTOs().Select(x => { x.Reset(); return x; });您还可以强制执行如下模式:public class FooDTO : StatefulObject{&nbsp; &nbsp; public FooDTO(string prop1, string prop2)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Set the properties...&nbsp; &nbsp; &nbsp; &nbsp; Prop1 = prop1;&nbsp; &nbsp; &nbsp; &nbsp; // Ensure IsDirty is false;&nbsp; &nbsp; &nbsp; &nbsp; Reset();&nbsp;&nbsp; &nbsp; }}
随时随地看视频慕课网APP
我要回答