ViewModel数据为每个页面共享,同时为不同的视图重用单个ViewModel



这在某种程度上类似于为同一个ViewModel绑定两个不同的视图这样的重复问题但是我在AppShell上显示页面并有与数据相关的问题:

<FlyoutItem Title="News &amp; Updates" Icon="icon_feed.png" >
<Tab x:Name="UriUpdates" Title="News &amp; Updates" >
<ShellContent Title="News" Route="NewsPage" ContentTemplate="{DataTemplate local:NewsPage}" />
<ShellContent Title="Notifications" Route="NotificationsPage" ContentTemplate="{DataTemplate local:NotificationsPage}" />           
</Tab>        
</FlyoutItem>

两个页面都使用类型为ContentView的自定义控件.在页面的代码后面,我提供了BindingContext

BindingContext = _viewModel = new UpdatesViewModel("news");
BindingContext = _viewModel = new UpdatesViewModel("notifications");

ViewModel有一个属性UpdateType,它在构造函数中更新,它的值在命令(ExecuteLoadItemsCommand)中用于填写列表(项):

Items = new ObservableCollection<UpdatesModel>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());

事件ExecuteLoadItemsCommand()导致虚拟机从数据存储中填充数据

public IDataStore<UpdatesModel> DataStore => DependencyService.Get<IDataStore<UpdatesModel>>();

ExecuteLoadItemsCommand按预期调用,并每次填充相应的项。

async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Items.Clear();
var items = await DataStore.GetItemsAsync(UpdateType);
if(items!=null)
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}

GetItemsAsync返回所需项列表的数据存储:

public async Task<IEnumerable<UpdatesModel>> GetItemsAsync(string updateType, bool forceRefresh = false)
{
if (forceRefresh || items == null || items.Count == 0)
{
Uri uri = new Uri(Constants.GetUpdatesUrl(updateType));
try
{
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
items = (List<UpdatesModel>)JsonConvert.DeserializeObject<IEnumerable<UpdatesModel>>(content);
}
}
catch (Exception ex)
{
Debug.WriteLine(@"tERROR {0}", ex.Message);
}
}   
return await Task.FromResult(items);
}

我认为无论何时为页面News/Notifications填充项,它都不能一次又一次地为每个选项卡更改单击调用Rest-Service。它应该在需要时更新项目。因此,为此目的,我在DataStore的方法GetItemsAsync中应用了一个条件(这是IDataStore的实现)作为

if (forceRefresh || items == null || items.Count == 0)
{
//Rest Service Call to fill items list
}

问题是项(这是VM中的属性)总是非空的,并且填充了第一页数据(新闻项)。在新闻页面NotificationsPage时,我不知道为什么项目不是空的,并且填充了NewsPage数据正在加载

请帮助我,我是否有一个坏的做法,以共享VM不同的观点,或者有一些问题,导致页面有数据是由第一页填写项目?

错误是什么,我指责ViewModel导致数据在VM中定义的Items List的每个页面上共享:

public ObservableCollection<UpdatesModel> Items { get; }

但是数据正在被共享,因为DependencyService:

public IDataStore<UpdatesModel> DataStore => DependencyService.Get<IDataStore<UpdatesModel>>();

所以它有共享代码这意味着它是一个单独的实例,并被共享给VM。

我通过引入Dictionary解决了这个问题在DataStore (IDataStore的实现为DependencyService)作为

private Dictionary<string, List<UpdatesModel>> itemsDict;

不是

private List<UpdatesModel> items;

和修改后的GetItemsAsync(从Rest Service返回数据):

public async Task<IEnumerable<UpdatesModel>> GetItemsAsync(string updateType, bool forceRefresh = false)
{
if (itemsDict == null || itemsDict.Count == 0) itemsDict = new Dictionary<string, List<UpdatesModel>>();
if (forceRefresh || itemsDict == null || itemsDict.Count == 0 || !itemsDict.ContainsKey(updateType))
{
Uri uri = new Uri(Constants.GetUpdatesUrl(updateType, startDate));
try
{
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
itemsDict[updateType] = (List<UpdatesModel>)JsonConvert.DeserializeObject<IEnumerable<UpdatesModel>>(content);
}
}
catch (Exception ex)
{
Debug.WriteLine(@"tERROR {0}", ex.Message);
}
}
return await Task.FromResult(itemsDict[updateType]);
}

所以对于所有不同的updateTypes传递给GetItemsAsync从ViewModel,一个字典值(itemsDict[updateType])正在返回,我不必一次又一次地重新填充项目,因为字典只被填充一次,或者当强制重新填充任何updateType作为键时。

最新更新