1

我正在 WPF 中开发基于文本的游戏,并且正在探索 MVVM。目前我的项目中有 2 个模型,Adventurer 和 GameDate(此时我并不关心什么应该或不应该是模型。我稍后会解决这个问题)。我有一个 viewmodelMainViewModel和一个 view MainViewMainView有绑定到保存/加载命令的按钮......这就是我卡住的地方。我非常想实现一种二进制序列化的形式;我有一个类ObjectSerializer,它的功能和适当的部分在保存和加载命令中MainViewModel,但我不知道如何“获取”对需要序列化的类的实例(在本例中为模型)的访问,因为我从未手动实例化它们中的任何一个。此外,我想找到一种方法将它们全部序列化到一个文件中(游戏的典型“保存”文件)。

任何在 MVVM 中处理过序列化的人都可以指导我完成这个过程吗?我整天都被困在这个问题上,却没有任何进展,这让我发疯。如果有人可以提供某种例子,我将永远欠你的债。先感谢您; 一个能让我克服困难的答案不会被忽视。我真的在这里尝试...

对象序列化器.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();
    }
4

1 回答 1

8

在处理 MVVM 时,您的 Models(M) 将被封装在您的 ViewModel(VM) 中,并且仅通过您在 ViewModel 上显式公开的方法和属性公开给 View(V)。您的 ViewModel 将主要用作您的模型和您的视图之间的适配器。与应用程序层交互的所有逻辑,例如您可能需要的任何序列化,也将位于 ViewModel 中,并与任何特定于 UI 的代码分开。这样可以更轻松地测试您的核心应用程序代码,而不会陷入您不一定关心的事情中,例如某些内容是否显示在 aTextBox或 aLabel中。这比在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实现的代码,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
    }

}

现在您已经有了一个包装模型的基本 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}" />

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

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

于 2013-05-30T23:59:45.083 回答