在MVVM中进行序列化有很多麻烦

Jas*_*n D 1 c# serialization mvvm

我正在WPF中开发一个基于文本的游戏,我正在探索MVVM.目前我的项目中有2个模型,Adventurer和GameDate(我不关心这个应该或不应该是什么模型.我稍后会解决这个问题).我有一个viewmodel MainViewModel和一个视图MainView.MainView有按钮绑定保存/加载命令......这就是我被卡住的地方.我非常想实现一种二进制序列化的形式; 我有一个ObjectSerializer函数类,其中相应的部分在Save和Load命令中MainViewModel,但我不知道如何'获取'访问需要序列化的类的实例(在这种情况下是模型因为我从来没有手动实例化它们中的任何一个.此外,我想找到一种方法将它们全部序列化在一个文件中(游戏的典型"保存"文件).

任何在MVVM中处理过序列化的人都应该引导我完成这个过程吗?我一直坚持这一切,但没有取得任何进展,这让我发疯.如果有人可以提供某种例子,我将永远负债累累.先感谢您; 一个能让我超越这个驼峰的答案不会得不到重视.我真的在这里尝试......

ObjectSerializer.cs

    protected IFormatter iformatter;

    public ObjectSerializer()
    {
        this.iformatter = new BinaryFormatter();
    }

    public T GetSerializedObject(string filename)
    {
        if (File.Exists(filename))
        {
            Stream inStream = new FileStream(
                filename,
                FileMode.Open,
                FileAccess.Read,
                FileShare.Read);
            T obj = (T)this.iformatter.Deserialize(inStream);
            inStream.Close();
            return obj;
        }
        return default(T);
    }

    public void SaveSerializedObject(T obj, string filename)
    {
        Stream outStream = new FileStream(
            filename,
            FileMode.Create,
            FileAccess.Write,
            FileShare.None);
        this.iformatter.Serialize(outStream, obj);
        outStream.Close();
    }
Run Code Online (Sandbox Code Playgroud)

mcl*_*129 7

处理MVVM时,您的模型(M)将封装在ViewModel(VM)中,并仅通过您在ViewModel上显式公开的方法和属性公开给View(V).您的ViewModel将主要用作模型和View之间的适配器.您与应用程序层交互的所有逻辑(例如您可能需要的任何序列化)也将存放在ViewModel中,并与任何特定于UI的代码分开.这样可以更轻松地测试您的核心应用程序代码,而不会陷入您不一定关心的事情中,例如,如果某些内容显示在a TextBox或a中Label.这比在xaml.cs文件中发生类似对象序列化更为可取.

例如:

考虑一下你的Adventurer类看起来像这样:

public class Adventurer { 
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Rank { get; set; } //Knight, Warlock, Whatever
}
Run Code Online (Sandbox Code Playgroud)

MainViewModel可能看起来像这样:

(不要担心ViewModelBase,只是假设为了这个例子的目的,它包含一些允许你MainViewModel实现的代码INotifyPropertyChanged,要求让它与WPF的绑定子系统一起玩得很好)

public class MainViewModel : ViewModelBase {

    // When the ViewModel is created, populate _selectedAdventurer
    // with an empty Adventurer so that your form has something to  
    // bind to (and it can also be used as a "New" adventurer)
    private Adventurer _selectedAdventurer = new Adventurer();

    public string FirstName {
        get {
            return _selectedAdventurer.FirstName;
        }
        set {
            _selectedAdventurer.FirstName = value;
            // The following is implemented in our fictional
            // ViewModelBase, and essentially raises a notification
            // event to WPF letting it know that FirstName has changed
            OnPropertyChanged("FirstName");
        }
    }

    /*
       The remaining properties are implemented in a similar fashion, and in 
       this simple case are mainly acting as passthroughs to the view plus 
       a little bit of binding code
    */

    // These methods will house your save/load logic. I will assume
    // for simplicity that you already know how to wrap this logic in a
    // Command that can be bound to the view
    public void SaveAdventurer() {
       if(_selectedAdventurer != null) {
           SerializeToFile(_selectedAdventurer);
       }
    }

    public void LoadAdventurer() {
       _selectedAdventurer = LoadFromFile();
    }

    private void SerializeToFile(Adventurer adventurer) {
       // Use your serializer and save to file
    }

    private Adventurer LoadFromFile() {
       // Load from file and deserialize into Adventurer
    }

}
Run Code Online (Sandbox Code Playgroud)

现在您已经有一个基本的ViewModel包装模型,一旦将UI控件设置为DataContext视图,就可以轻松地将UI控件绑定到VM上的属性.

<TextBox Text="{Binding FirstName}" />
<TextBox Text="{Binding LastName}" />
<TextBox Text="{Binding Rank}" />
<Button Value="Save" Command="{Binding SaveCommand}" />
<Button Value="Load" Command="{Binding LoadCommand}" />
Run Code Online (Sandbox Code Playgroud)

由于您已设置ViewModel来包装模型,并且已将ViewModel属性正确绑定到View,因此当用户在绑定到的文本框中输入值时FirstName,_selectedAdventurer.FirstName将使用该输入直接更新值.实质上,底层模型的状态将始终与UI中显示的值同步.然后,当用户单击标记的按钮时Save,您SaveCommand将执行并将触发代码将底层序列Adventurer化为文件,数据库或其他任何内容.

这当然是一个非常简单的例子,主要用作数据输入表格,但希望它能帮助你掌握这个概念.为了更好地封装Adventurer绑定逻辑,您可以选择创建一个AdventurerViewModel将暴露给View 的子节点,而不是直接放置属性MainViewModel.也许您会想要添加一个IEnumerable<SaveGameFile> SavegameFiles可以绑定到a 的属性DropDownList,并允许用户选择要加载的文件.