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

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

任何在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(); } 

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

例如:

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

 public class Adventurer { public string FirstName { get; set; } public string LastName { get; set; } public string Rank { get; set; } //Knight, Warlock, Whatever } 

您的MainViewModel可能如下所示:

(不要担心ViewModelBase ,只是假设为了这个例子的目的,它包含一些代码,允许你的MainViewModel实现INotifyPropertyChangedINotifyPropertyChanged它与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 } } 

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

      

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

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