0

WP7アプリのアップデートを送信しましたが、アップデート後にデータが消去されたという苦情がユーザーに寄せられました。ViewModelクラスをIsolatedStorageのXMLファイルとしてシリアル化してデータを保存しています。テスト中に、アプリを更新すると、設定ファイルがViewModelオブジェクトの新しいインスタンス(デフォルト値)のシリアル化されたコピーで部分的に上書きされることに気付きました。XMLファイルに書き込むときにFileMode.Createを使用して問題を解決したと思いましたが、そうではないと思います。

ViewModelオブジェクトに新しいプロパティを追加し、既存のXMLファイルからの逆シリアル化が失敗したため、シリアル化がうまくいかなかった可能性がありますか?XMLファイルから読み取れない場合に新しいViewModelオブジェクトをインスタンス化するようにコードを設定しています。この場合、ViewModelオブジェクトに新しいプロパティを追加できないということですか?

編集:
これが私のViewModelの構造ですが、それほど複雑ではありません:

public class MyClass: INotifyPropertyChanged
{
    public MyClass()
    {
        // Set defaults
        this.Items= new ObservableCollection<Item>();
        this.TextTemplate = "default";
        this.HasSeenSomething = false;
    }

    public ObservableCollection<Item> Items { get; set; }
    // New properties added in app update
    public string TextTemplate { get; set; }
    public bool HasSeenSomething { get; set; }
}

これが、ViewModelをシリアル化/逆シリアル化するために使用しているコードです。私はそれがかなり標準的だと思いますが、多分私は何かを失敗させました:

public static void WriteToXml<T>(T data, string path)
{
    var xmlWriterSettings = new XmlWriterSettings { Indent = true };
    using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Create))
        {
            var serializer = new XmlSerializer(typeof(T));
            using (var xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
            {
                serializer.Serialize(xmlWriter, data);
            }
        }
    }
}

public static T ReadFromXml<T>(string path)
{
    T data = default(T);
    try
    {
        using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (myIsolatedStorage.FileExists(path))
            {
                using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Open))
                {
                    try
                    {
                        var serializer = new XmlSerializer(typeof(T));
                        object instance = serializer.Deserialize(stream);
                        if (instance != null) data = (T)instance;
                    }
                    catch (System.Exception ex)
                    {
                        var e = ex;
                    }
                }
            }
        }
    }
    catch(System.Exception ex) 
    {
        var e = ex;
    }
    return data;
}
4

1 に答える 1

0

できますが、いくつかの落とし穴があります。

  1. 逆シリアル化するときに破損するような方法でプロパティを変更していないことを確認する必要があります。したがって、IntをStringに変更することは問題ありませんが(私は提案しませんが)、その逆が機能しない可能性があります。
  2. オブジェクトを逆シリアル化するときに、ctorが呼び出されないことを覚えておく必要があります。つまり、ctorで行う場合、次のようになります。

    public MyClass(){MyV2Collection = new Collection(); }

また、コレクションがnullの場合にコレクションを更新するメカニズムは他にありません。プロパティに初めてアクセスしようとすると、NullRefで停止します。

ドルにダイム、私はあなたがpt#2を打っていると思います。

修正はかなり簡単ですが、忘れずに修正する必要があります。オプションは次のとおりです。

  1. プロパティアクセサーで、バッキングフィールドがnullかどうかを確認し、nullの場合はインスタンス化します。
  2. それを飾る属性を持つ関数(public)を作成します。[OnDeserialized]そのコードは、逆シリアル化が完了すると実行され、そこでメンバーをインスタンス化できます。
于 2012-04-04T22:38:48.277 に答える