MVVM与webservice

时间:2010-06-26 09:14:13

标签: c# wpf mvvm web-services

我打算用MVVM做一个wpf应用程序(它基于http://www.codeproject.com/KB/WPF/MVVMQuickTutorial.aspx )。

此应用程序将每月与webservice连接一次。

在webservice上我有合同

public class Student
{
        public string Name {get; set;}
        public int Score {get; set;}
        public DateTime TimeAdded {get; set;}
        public string Comment {get; set;}
}

在WPF应用程序中添加和删除学生将保存到xml文件。

所以在wpf应用程序学生会是这样的:

public class Student
{
    public string Name {get; set;}
    public int Score {get; set;}
    public DateTime TimeAdded {get; set;}
    public string Comment {get; set;}

    public Student(string Name, int Score,
        DateTime TimeAdded, string Comment) {
        this.Name = Name;
        this.Score = Score;
        this.TimeAdded = TimeAdded;
        this.Comment = Comment;
    }
}

public class StudentsModel: ObservableCollection<Student>
{
    private static object _threadLock = new Object();
    private static StudentsModel current = null;

    public static StudentsModel Current {
        get {
            lock (_threadLock)
            if (current == null)
                current = new StudentsModel();

            return current;
        }
    }

    private StudentsModel() 
    {

        // Getting student s from xml
        }
    }

    public void AddAStudent(String Name,
        int Score, DateTime TimeAdded, string Comment) {
        Student aNewStudent = new Student(Name, Score,
            TimeAdded, Comment);
        Add(aNewStudent);
    }
}

如何连接这两个类?

最糟糕的想法我想是来自webservice的合同学生将在这个wpf应用程序中使用来从xml获取学生,其他应用程序集合中的学生将从数据库中获取。

我是设计模式的新手,所以对我来说很难:/

示例:我单击AddUser,在应用程序A中调用webservice方法将用户添加到数据库,在应用程序B中将用户添加到XML文件,并在应用程序中。 基类是webservice的合同。

下一个解释:

第一个应用程序使用webservice在数据库中保存数据。第二个应用程序永远不会在xmls中保存数据,每个perm月将此xmls发送到webservice并将其转换为学生的内容并将其保存在数据库中

3 个答案:

答案 0 :(得分:7)

从您的问题中不清楚实际问题是什么。但是,我想我可以解决一些问题并向您展示解决问题的方法。

1)我在你的项目中看到的主要问题是你有Student类的两个定义。您可以轻松地将它们合并为单个定义。 (我会告诉你如何...)

2)目前还不清楚您是希望WPF客户端将数据保存到Data SourceXML?)还是Web Service应该这样做。如果WPF客户端应该保存Student,那么Web Service是什么?

3)ViewModel类的任何地方都没有定义Student,在这种情况下为Model

我创建了一个包含3个项目的示例。

1)WebService - WCF服务项目

2)StudentLib - 一个类库项目(其中定义了Student类)

3)DesktopClient - WPF应用项目

以下是源代码:

WebService.IStudentService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using StudentLib;

namespace WebService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IStudentService" in both code and config file together.
    [ServiceContract]
    public interface IStudentService
    {
        [OperationContract]
        StudentLib.Student GetStudentById(Int32 id);

        [OperationContract]
        void AddStudent(StudentLib.Student student);
    }
}

WebService.StudentService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using StudentLib;

namespace WebService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "StudentService" in code, svc and config file together.
    public class StudentService : IStudentService
    {
        public StudentLib.Student GetStudentById(int id)
        {
            return new StudentLib.Student() { Name = "John Doe", Score = 80, TimeAdded = DateTime.Now, Comment = "Average" };
        }

        public void AddStudent(StudentLib.Student student)
        {
            // Code to add student
        }
    }
}

WebService's Web.Config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <bindings />
    <client />
    <services>
      <service name="WebService.StudentService" behaviorConfiguration="metaDataBehavior">
        <endpoint address="basic" binding="basicHttpBinding" contract="WebService.IStudentService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metaDataBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

StudentLib.Student.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace StudentLib
{
    [DataContract]
    public class Student
    {
        [DataMember]
        public String Name { get; set; }

        [DataMember]
        public Int32 Score { get; set; }

        [DataMember]
        public DateTime TimeAdded { get; set; }

        [DataMember]
        public String Comment { get; set; }
    }
}

DesktopClient.StudentViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesktopClient
{
    class StudentViewModel
    {
        protected StudentLib.Student Student { get; set; }

        public StudentViewModel(StudentLib.Student student)
        {
            this.Student = student;
        }

        public String Name { get { return Student.Name; } }
        public Int32 Score { get { return Student.Score; } }
        public DateTime TimeAdded { get { return Student.TimeAdded; } }
        public String Comment { get { return Student.Comment; } }
    }
}

DesktopClient.MainWindow.xaml

<Window x:Class="DesktopClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="400"
        Height="300"
        Loaded="Window_Loaded">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Column="0"
                   Grid.Row="0">Name :</TextBlock>
        <TextBlock Grid.Column="1"
                   Grid.Row="0"
                   Text="{Binding Name}"></TextBlock>
        <TextBlock Grid.Column="0"
                   Grid.Row="1">Score :</TextBlock>
        <TextBlock Grid.Column="1"
                   Grid.Row="1"
                   Text="{Binding Score}"></TextBlock>
        <TextBlock Grid.Column="0"
                   Grid.Row="2">Time Added :</TextBlock>
        <TextBlock Grid.Column="1"
                   Grid.Row="2"
                   Text="{Binding TimeAdded}"></TextBlock>
        <TextBlock Grid.Column="0"
                   Grid.Row="3">Comment :</TextBlock>
        <TextBlock Grid.Column="1"
                   Grid.Row="3"
                   Text="{Binding Comment}"></TextBlock>
    </Grid>
</Window>

DesktopClient.MainWindow.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DesktopClient.StudentService;
using StudentLib;

namespace DesktopClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            IStudentService client = new StudentServiceClient();

            Student student = client.GetStudentById(1);
            DataContext = new StudentViewModel(student);

            client.AddStudent(new StudentLib.Student() { Name = "Jane Doe", Score = 70, TimeAdded = DateTime.Now, Comment = "Average" });
        }
    }
}

这里解决了上述所有问题:

1)Student类在StudentLib项目和WebService项目引用的公共程序集(DesktopClient)中定义。因此,在添加Service Reference时,代码生成器会重用该类。

2)我建议所有与存储相关的操作都在Web Service,而Client应用只应使用Web Service来存储数据。

3)使用StudentViewModel类而不是Student类来显示MainWindow中的数据。

答案 1 :(得分:0)

您可以使用以下架构。

1)带有app.config的WPF应用程序(应用程序A和B),其中包含Web服务URL或XML文件路径

2)业务/数据层    为Web服务URL创建代理类,并创建您在帖子中提到的Student Model类。    修改Add方法以支持这两种功能。如果app.config具有webservice url(App A),则调用Webservice中的Add方法,如果appsetting具有XML文件路径(App B),则调用add to XML方法

答案 2 :(得分:0)

幸运的是,这些类已经“链接”了,至少在形式上是这样的:因为ViewModel只是一堆模型。

在MVVM模式中,您需要在ViewModel中处理数据绑定功能。这包括以下内容:

  • StudentModel构造函数(private StudentsModel() { ...)应该使用所有Student实例加载自身。 (或者,您可以使用单独的Load()函数 - 如果您还有Save()方法,这似乎是最合乎逻辑的。)在这里,您可能会读取XML文件,使用XmlSerializer来deserialize将XML数据转换为学生集合(可能是List),然后使用base constructor(对于整个列表)或Add() method(一次一个,例如在循环中)将它们添加到自身。
  • 您需要将学生添加到集合中的功能,如教程示例中所示。在桌面应用程序上,您可以在此处调用Web服务上的“添加”功能,如果成功,则将其添加到内存中的自己的集合中。然后,您必须决定是否要立即将(序列化的)数据保存到XML文件中,或者稍后一起完成(例如,卸载对象或调用Save()方法时)。
  • 您可能还希望包含一个方法来从集合中删除Student对象。 ObservableCollection的公共方法在这里会有一些帮助,但是您可能需要/需要比选择要删除的对象更多的逻辑。而且,在这里,您必须通知Web服务有关已删除的项目,并知道您是要立即保存更改还是等待单独的事件。
  • 继承ObservableCollection是明智的,因为这会让你获得很多使得绑定动态的魔力 - 我的意思是,随着数据的变化,UI会随之更新。只要您使用Add()和Remove()等基本方法,您就可以获得IEnumerableINotifyPropertyChangedINotifyCollectionChanged的好处。

您可能会注意到我在上面的解释中大部分都提到了XML序列化,但是为了制作具有类似功能的Web服务,您可以将“序列化XML并保存到文件中”等想法换成“将更改保存到数据库中” ”。模式是一样的,只是实际的行动(实施)是不同的。

简而言之,ViewModel就是您要实现所有加载和放置的东西的地方。处理内存中的数据并将其保存到文件,数据库或Web服务中。