You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AppShell多页面复用ViewModel时数据缓存逻辑异常问题求助

Fixing Data Duplication Between Tabs in AppShell with Shared DataStore

Let's break down exactly what's going wrong here and walk through the fixes:

Root Cause

The core issue isn't with how you're instantiating ViewModels (each page having its own UpdatesViewModel instance is actually a perfectly valid approach here) — it's with your DataStore's caching logic combined with DependencyService's default singleton behavior.

Here's the play-by-play:

  1. DependencyService returns a single instance of your DataStore by default. So both your NewsPage and NotificationsPage ViewModels are using the same DataStore object.
  2. When NewsPage loads, it calls GetItemsAsync("news"), which populates the DataStore's global items variable with news data.
  3. When you switch to NotificationsPage, its ViewModel calls GetItemsAsync("notifications"), but your cache check forceRefresh || items == null || items.Count == 0 fails: items already has data (from the news load), so it skips fetching new data and returns the existing news list instead.

Your cache doesn't distinguish between different updateType values — it's using one single variable to store all types of updates, which is why you're seeing cross-page data leakage.

Solution 1: Update DataStore to Cache by Update Type

The cleanest fix is to modify your DataStore to cache data separately for each updateType. Use a dictionary to map each type to its corresponding data list:

// Replace your single 'items' variable with a dictionary
private Dictionary<string, List<UpdatesModel>> _cachedItems = new Dictionary<string, List<UpdatesModel>>();

public async Task<IEnumerable<UpdatesModel>> GetItemsAsync(string updateType, bool forceRefresh = false)
{
    // Check if we need to refresh or if there's no cached data for this type
    if (forceRefresh || !_cachedItems.ContainsKey(updateType) || _cachedItems[updateType] == null || _cachedItems[updateType].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();
                var fetchedItems = (List<UpdatesModel>)JsonConvert.DeserializeObject<IEnumerable<UpdatesModel>>(content);
                
                // Update the cache for this specific update type
                if (_cachedItems.ContainsKey(updateType))
                    _cachedItems[updateType] = fetchedItems;
                else
                    _cachedItems.Add(updateType, fetchedItems);
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(@"\tERROR {0}", ex.Message);
        }
    }

    // Return the cached data for the requested type (or null if none exists)
    return await Task.FromResult(_cachedItems.TryGetValue(updateType, out var result) ? result : null);
}

Solution 2: Force Refresh When Switching Tabs (Quick Fix)

If you want a quicker temporary fix without modifying the DataStore's caching structure, you can modify your ExecuteLoadItemsCommand to pass forceRefresh=true when fetching data. This skips the cache check every time the command runs:

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

Note: This will hit your REST API every time you switch tabs, which negates your caching benefit — so Solution 1 is far better for production use.

Final Note on ViewModel Usage

To answer your original question: Instantiating a separate ViewModel for each page is not a bad practice here. Since each tab represents a distinct data set with its own state (like IsBusy), having independent ViewModels keeps your code clean and maintainable. The issue was purely with the DataStore's untyped caching, not your ViewModel structure.

内容的提问来源于stack exchange,提问作者M.Waseem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 09:32:42