【问题标题】:Storing objects in IsolatedStorageSettings在 IsolatedStorageSettings 中存储对象
【发布时间】:2013-04-17 03:04:49
【问题描述】:

我有一个对象要存储在 IsolatedStorageSettings 中,我不想在应用程序重新启动时重复使用它。

我的问题在于我编写的代码由于某种原因在重新启动时尝试访问密钥时不记得该对象。

namespace MyNameSpace
{
    public class WindowsPhoneSettings
    {
        private const string SelectedSiteKey = "SelectedSite";
        private IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;

        private T RetrieveSetting<T>(string settingKey)
        {
            object settingValue;
            if (isolatedStore.TryGetValue(settingKey, out settingValue))
            {
                return (T)settingValue;
            }
            return default(T);
        }

        public bool AddOrUpdateValue(string Key, Object value)
        {
            bool valueChanged = false;

            if (isolatedStore.Contains(Key))
            {
                if (isolatedStore[Key] != value)
                {
                    isolatedStore[Key] = value;
                    valueChanged = true;
                }
            }
            else
            {
                isolatedStore.Add(Key, value);
                valueChanged = true;
            }
            return valueChanged;
        }

        public MobileSiteDataModel SelectedSite
        {
            get
            {
                return RetrieveSetting<MobileSiteDataModel>(SelectedSiteKey);
            }
            set
            {
                AddOrUpdateValue(SelectedSiteKey, value);
                isolatedStore.Save();
            }
        }
    }
}

然后我在 App.xaml.cs 中实例化 WindowsPhoneSettings 并为其创建一个公共 getter 和 setter。能够在整个应用程序中访问它。调试这表明正确的对象存储在隔离存储中,但是当关闭应用程序并重新打开它时,隔离存储似乎是空的。我在模拟器和真实设备上都试过了。如您所见,我在设置对象时确实调用了 save 方法。

我在这里做错了什么?

【问题讨论】:

  • 我在这里遇到了同样的问题。可以轻松保存字符串、布尔值或整数等简单对象。但是,如果我尝试保存 Song 对象,则似乎在重新启动时会删除所有内容(包括其他值),而不会出现任何错误消息。这可能是一些奇怪的错误,我认为这是一个内部序列化问题。

标签: c# silverlight windows-phone-7 object isolatedstorage


【解决方案1】:

我最终将设置保存到隔离存储中的文件中,因为 IsolatedStorageSettings 似乎从来没有工作过。

所以我的代码最终是这样的:

public class PhoneSettings
{
    private const string SettingsDir = "settingsDir";
    private const string SettingsFile = "settings.xml";

    public void SetSettings(Settings settings)
    {
        SaveSettingToFile<Settings>(SettingsDir, SettingsFile, settings);
    }

    public Settings GetSettings()
    {
        return RetrieveSettingFromFile<Settings>(SettingsDir, SettingsFile);
    }

    private T RetrieveSettingFromFile<T>(string dir, string file) where T : class
    {
        IsolatedStorageFile isolatedFileStore = IsolatedStorageFile.GetUserStoreForApplication();
        if (isolatedFileStore.DirectoryExists(dir))
        {
            try
            {
                using (var stream = new IsolatedStorageFileStream(System.IO.Path.Combine(dir, file), FileMode.Open, isolatedFileStore))
                {
                    return (T)SerializationHelper.DeserializeData<T>(stream);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Could not retrieve file " + dir + "\\" + file + ". With Exception: " + ex.Message);
            }
        }
        return null;
    }

    private void SaveSettingToFile<T>(string dir, string file, T data)
    {
        IsolatedStorageFile isolatedFileStore = IsolatedStorageFile.GetUserStoreForApplication();
        if (!isolatedFileStore.DirectoryExists(dir))
            isolatedFileStore.CreateDirectory(dir);
        try
        {
            string fn = System.IO.Path.Combine(dir, file);
            if (isolatedFileStore.FileExists(fn)) isolatedFileStore.DeleteFile(fn); //mostly harmless, used because isolatedFileStore is stupid :D

            using (var stream = new IsolatedStorageFileStream(fn, FileMode.CreateNew, FileAccess.ReadWrite, isolatedFileStore))
            {
                SerializationHelper.SerializeData<T>(data, stream);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("Could not save file " + dir + "\\" + file + ". With Exception: " + ex.Message);
        }
    }
}

还有一个设置类,其中只包含我要保存的内容。这可能是:

class Settings
{
    private string name;
    private int id;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Id
    {
        get { return id; }
        set { id = value; }
    }
}

编辑:如何实现SerializationHelper 的示例

public static class SerializationHelper
{
    public static void SerializeData<T>(this T obj, Stream streamObject)
    {
        if (obj == null || streamObject == null)
            return;

        var ser = new DataContractJsonSerializer(typeof(T));
        ser.WriteObject(streamObject, obj);
    }

    public static T DeserializeData<T>(Stream streamObject)
    {
        if (streamObject == null)
            return default(T);

        var ser = new DataContractJsonSerializer(typeof(T));
        return (T)ser.ReadObject(streamObject);
    }
}

【讨论】:

  • 什么是 SerializationHelper?它来自其他图书馆吗?如果可以,请您提一下。
  • SerializationHelper 只是一个简单的类,负责对对象进行序列化和反序列化的繁重工作。在这种情况下,这是我的一位同事编写的,因为我们使用的实现也需要支持压缩和解压缩文件。虽然您可以使用默认的 System.Xml.Serialization 方法或一些 JSON 序列化程序。
  • 添加了一个使用 Json 的 SerializationHelper 示例。
【解决方案2】:

存储在 IsolatedStorageSettings 中的对象使用DataContractSerializer 进行序列化,因此必须是可序列化的。在添加到 ISS 之前(以及从 ISS 中移除之后),确保它们可以自己序列化(和反序列化)它们。

如果在尝试检索时项目不存在,则可能是一开始就无法添加它们(由于序列化问题)。

【讨论】:

  • 如果我自己序列化对象并将其放入IsolatedStorageFile 中,它可以正常工作。只需使用 XmlSerializer 来执行此操作,它就可以在不修改我尝试序列化的对象的情况下工作。
  • 我不确定如何在保存到 ISS 之前对对象进行序列化和反序列化,请提供一些提供更多信息的链接,最好是示例。
【解决方案3】:

这是我用来将对象保存到隔离存储并从隔离存储加载对象的代码 -

private void saveToIsolatedStorage(string keyname, object value)
{
  IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
  isolatedStore.Remove(keyname);
  isolatedStore.Add(keyname, value);
  isolatedStore.Save();
}

private bool loadObject(string keyname, out object result)
{
  IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;

  result = null;
  try
  {
    result = isolatedStore[keyname];
  }
  catch
  {
    return false;
  }
  return true;
}

这是我用来调用上述代码的代码 -

private void SaveToIsolatedStorage()
{
  saveToIsolatedStorage("GameData", GameData);
}

private void LoadFromIsolatedStorage()
{
  Object temp;
  if (loadObject("GameData", out temp))
  {
    GameData = (CGameData)temp;
  }
  else
  {
    GameData.Reset();
  }
}

请注意,我这样保存和恢复的对象很小且可序列化。如果我的对象包含二维数组或其他不可序列化的对象,那么我会在使用 iso 存储之前执行自己的序列化和反序列化。

【讨论】:

    【解决方案4】:

    如果你把 RetrieveSetting&lt;T&gt; 改成这样会怎样:

    private T RetrieveSetting<T>(string settingKey)
    {
      T settingValue;
      if(isolatedStore.TryGetValue(settingKey, out settingValue))
      {
        return (T)settingValue;
      }
      return default(T);
    }
    

    请注意,正在获取的对象被声明为类型 T 而不是 object

    【讨论】:

    • 这没有帮助。正如在问题中试图说的那样,当使用调试器单步执行时,IsolatedStorage 根本不包含任何键。
    • @Cheesebaron 您是否使用 Rebuild All 来构建项目?还是使用应用程序部署工具来部署 XAP 文件?这两个操作都卸载现有应用程序并重新安装它,从而消除隔离存储。使用 Build 选项并在 Visual Studio 中按 F5。
    猜你喜欢
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多