有许多麻烦与MVVM系列化 [英] Having lots of trouble with serialization in MVVM

查看:114
本文介绍了有许多麻烦与MVVM系列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作在WPF基于文本的游戏,我探索MVVM。目前,我有2个型号在我的项目,冒险家和GameDate(我不担心在这一点上什么应该或不应该是一个典范。以后我会处理)。我有一个视图模型 MainViewModel 和一个视图的MainView 的MainView 已绑定按钮保存/载入命令......这就是那种在那里我卡住了。我非常想实现二进制序列化的一种形式;我有一个类 ObjectSerializer ,其功能及相应的零部件,其中在保存和载入命令在 MainViewModel ,但我不知道如何获得因为我从来没有手动实例化其中的任何访问需要被序列化(在这种情况下,模型)的类的实例。此外,我想找到一种方法来序列化它们都在同一个文件(一个游戏一个典型的保存文件)。



会有人谁处理了系列化在MVVM请仁慈地指导我通过这个过程?我一直停留在这个整天,而没有取得什么进展,它的驾驶我疯狂。如果有人可以提供一些例子我将永远感激你。先谢谢你;这将让我在这个驼背的答案不会去赏识。我真的在努力在这里...



ObjectSerializer.cs

 保护iFormatter iformatter; 

公共ObjectSerializer()
{
this.iformatter =新的BinaryFormatter();
}

公共牛逼GetSerializedObject(字符串文件名)
{
如果(File.Exists(文件名))
{
流inStream =新的FileStream(
文件名,
FileMode.Open,
FileAccess.Read,
FileShare.Read); $ B $(B T)= OBJ(T)this.iformatter.Deserialize(插播广告);
inStream.Close();
返回OBJ;
}
返回默认值(T);
}

公共无效SaveSerializedObject(T OBJ,字符串文件名)
{
流outStream =新的FileStream(
文件名,
的FileMode。创建,
FileAccess.Write,
FileShare.None);
this.iformatter.Serialize(outStream,OBJ);
outStream.Close();
}


解决方案

在与MVVM处理,你的模型(M)打算只通过方法和属性,你明确你的ViewModel揭露你的视图模型(VM)进行封装和暴露在查看(V)。您的视图模型将主要作为模型(S)和您之间查看适配器。所有你的逻辑与应用程序层,如任何可能需要的系列化交互,也将在视图模型内安置,并从该特定用户界面的任何代码分开。这使得它更容易在没有东西,你不一定在意,比如如果事情是显示在文本框或陷入困境测试你的核心应用程序代码标签。这是在具有类似对象序列化在 xaml.cs 文件发生更可取的。



例如:



想想看,你的冒险家类看起来是这样的:

 公共类冒险家{
公共字符串名字{获得;组; }
公共字符串名字{获得;组; }
公共字符串等级{搞定;组; } //骑士,术士,无论
}

MainViewModel 可能是这个样子:



(不要担心 ViewModelBase ,只假设这个例子的目的,它设有一些代码,让你的 MainViewModel 实施 INotifyPropertyChanged的,获取的要求它发挥好与WPF的绑定子系统)

 公共类MainViewModel:ViewModelBase {

//当创建视图模型,填充_selectedAdventurer
//用空冒险使你的形式有某种
//结合(和它也可以被用作一个新的冒险)
民营冒险家_selectedAdventurer =新的冒险();

公共字符串名字{
获得{
返回_selectedAdventurer.FirstName;
}
集合{
_selectedAdventurer.FirstName =价值;
//以下是在我们的虚构
// ViewModelBase实现,并且基本上引发通知
//事件于WPF让它知道姓已经改变
OnPropertyChanged(姓);
}
}

/ *
其余性能以类似的方式实现的,并且在
。这种简单的情况,主要充当快速导入到结合代码
* /

//这些方法将容纳您的保存/载入逻辑视图另加
A点点。我将承担
//为简单起见,你已经知道如何在
//命令可以绑定到视图
公共无效SaveAdventurer包装这个逻辑(){
如果(!_selectedAdventurer = NULL){
SerializeToFile(_selectedAdventurer);
}
}

公共无效LoadAdventurer(){
_selectedAdventurer = LoadFromFile();
}

私人无效SerializeToFile(冒险家冒险家){
//使用你的序列化,并保存到文件
}

私人冒险家LoadFromFile (){
//从文件加载和反序列化到冒险家
}

}

现在,你有一个基本的视图模型包装模型,您可以轻松地绑定,一旦它被设置为的DataContext 为您的视图

 <文本框的文本={结合姓}/> 
<文本框的文本={结合姓氏}/>
<文本框的文本={结合}排名/>
<按键值=保存命令={结合SaveCommand}/>
<按键值=装载命令={结合LoadCommand}/>



既然你已经设置了您的视图模型来包装你的模型,并正确绑定视图模型属性您查看,当用户输入值成必然文本框,在 _selectedAdventurer.FirstName 的价值将直接与该输入更新。从本质上讲,你的基本模型的状态将始终在用户界面中显示的值同步。然后,当用户点击按钮标记保存,您 SaveCommand 将执行,这将火码序列化的基本冒险家到文件或数据库,或什么的。



这当然是一个很简单的例子,功能主要是作为一个数据输入形式,但希望它会帮助你掌握的概念。为了更好的封装冒险家绑定逻辑,你可以选择创建一个 AdventurerViewModel 将被暴露在视图,而不是直接把性能上 MainViewModel 。也许你会想添加一个属性的IEnumerable< SaveGameFile> SavegameFiles 您可以绑定到的DropDownList ,并允许用户选择他们想要加载的文件。


I am working on a text-based game in WPF and I'm exploring MVVM. Currently I have 2 models in my project, Adventurer and GameDate (I am not concerned at this point with what should or should not be a model. I'll tackle that later). I have a viewmodel MainViewModel and a view MainView. MainView has buttons bound to save/load commands... And that's sort of where I'm stuck. I would very much like to implement a form of binary serialization; I have a class ObjectSerializer that functions and the appropriate parts of which are in the Save and Load commands in MainViewModel, but I don't know how to 'obtain' access to the instances of the classes that need to be serialized (in this case the models) since I never manually instantiated any of them. Furthermore, I would like to find a way to serialize them all in one file (a typical 'save' file for a game).

Would anybody who has dealt with serialization in MVVM please be kind enough to guide me through this process? I've been stuck on this all day while making no progress and it's driving me crazy. If somebody can provide some sort of example I will be forever in your debt. Thank you in advance; an answer that would get me over this hump will not go unappreciated. I really am trying here...

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

解决方案

When dealing with MVVM, your Models(M) are going to be encapsulated in your ViewModel(VM) and exposed to the View(V) only through the methods and properties that you explicitly expose on your ViewModel. Your ViewModel will function mainly as an adapter between your Model(s) and you View. All of your logic interacting with your application layer, such as any of the serialization you might need, will also be housed within the ViewModel and separated from any code that is UI specific. This makes it easier to test your core application code without getting bogged down in things that you don't necessarily care about, such as if something is displayed in a TextBox or a Label. This is much more preferable over having something like object serialization happening in your xaml.cs file.

For Example:

Consider that your Adventurer class looks something like this:

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

Your MainViewModel might look something like this:

(Don't worry about ViewModelBase, just assume that for the purposes of this example it houses some code which allows your MainViewModel to implement INotifyPropertyChanged, a requirement for getting it to play nice with WPF's binding subsystem)

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
    }

}

Now that you have a basic ViewModel wrapping your Model, you can easily bind UI controls to the properties on your VM once it is set as the DataContext for your view.

<TextBox Text="{Binding FirstName}" />
<TextBox Text="{Binding LastName}" />
<TextBox Text="{Binding Rank}" />
<Button Value="Save" Command="{Binding SaveCommand}" />
<Button Value="Load" Command="{Binding LoadCommand}" />

Since you've set up your ViewModel to wrap your Model, and have properly bound the ViewModel properties to your View, when a user enters values into the textbox bound to FirstName, the value in _selectedAdventurer.FirstName will be directly updated with that input. Essentially, the state of your underlying model will always be in sync with the values displayed in the UI. Then when a user clicks the button labeled Save, your SaveCommand will execute and that will fire the code serialize the underlying Adventurer into a file, or database, or whatever.

This of course is a very simple example and functions mostly as a data entry form, but hopefully it will help you grasp the concept. In order to better encapsulate the Adventurer binding logic, you may choose to create a child AdventurerViewModel that will be exposed to the View, rather than putting the properties directly on MainViewModel. Perhaps you will want to add a property IEnumerable<SaveGameFile> SavegameFiles which you could bind to a DropDownList, and allow users to select which file they want to load.

这篇关于有许多麻烦与MVVM系列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆