锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / C#开源 / MVVMLight / 向导式学习MVVMLight包含服务数据接口
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

锐英源精品原创,禁止全文或局部转载,禁止任何形式的非法使用,侵权必究。点名“简易百科”和闲暇巴盗用锐英源原创内容。

向导式学习MVVMLight包含服务数据接口


锐英源软件在使用MVVMLight开发了企业信息化软件MIS软件,对于MVVMLight有一套自己的使用模式,但是在英文网站上找到了个超详细用法步骤说明,还包含服务数据接口,一时心喜,翻译下供自己提高,也提供给同行给共同提高。

一直想找个自动生成Model类的工具,看本文里讲到VS向导生成新 ADO.NET 实体数据模型是功能类似的,后面研究下。

MVVMLight工具包可以生成视图,我以前是手工拷贝的,后面可以注意下MVMMLight工具包功能。

下面是正文:

 

MVVM Light 工具包提供了大量样板代码来快速实现基于模型-视图-视图模型的应用程序,并为用户提供了自定义和设计应用程序的自由。本文介绍如何开始为 WPF 应用程序进行 MVVM 开发。

 

关注点分离(解耦)或 SoC 是促进软件架构最佳实践的原则。可以将“关注”视为软件功能的一个方面。例如:UI 可以是一个关注点,业务逻辑可以是另一个关注点,等等。这个想法是确保每个关注点都有一个单一的、明确定义的目的,并找到一种平衡的方式将这些特性和概念分成不同的模块。这最终减少了重复代码并保持模块相互解耦,使我们的应用程序可维护和可管理。作为 SoC 的一个非常基本的例子,想想 HTML、CSS 和 JavaScript,所有这些技术都有一个明确的用途。HTML 定义内容结构,CSS 定义内容呈现,JavaScript 定义内容如何与用户交互和行为。

本文发表自DotNetCurry .NET 杂志 - 面向 .NET 专业人士的免费高质量数字杂志,每两个月出版一次。免费订阅此电子杂志并获得专家提供的数百个免费 .NET 教程

为了实现 SoC 原理,多年来出现了许多设计模式。例如,Model-View-Presenter (MVP) 适用于 Windows 窗体;用于 ASP.NET MVC 的模型-视图-控制器 (MVC);Model-View-ViewModel (MVVM) 可以很好地与 WPF 等配合使用。对于那些感兴趣的人,Martin Fowler 有一篇很好的文章解释了这些模式的差异

什么是模型-视图-视图模型 (MVVM)?

XAML通过将应用程序的 GUI 与编程逻辑(用 C#或 VB.NET 编码)分离,在 WPF、Silverlight、Windows Phone 和 Windows 8 应用程序中启用SoC。Model-View-ViewModel (MVVM) 是一种设计模式,通过允许将业务逻辑与视图 (UI) 分离来解决SoC,这最终使编写单元测试和实现并行开发和设计变得更加容易。它利用 XAML 平台的丰富数据绑定功能通过视图的DataContext属性向 UI 公开视图模型。业务层也称为模型,而视图模型层负责使用 DataBinding 将模型中的数据对象公开给 UI。这ViewModel包含 View 显示逻辑,其中 UI 上的操作可以使用ViewModel中声明的 Commands 属性来处理。

为什么选择 MVVM Light?

为了实现 MVVM,您需要首先了解命令、消息传递和绑定。然后,您需要了解 MVVM 原则并实施这些原则,以在您的开发中保持功能和简单性的良好平衡。您还需要提供单元测试支持。总而言之,这需要相当多的时间和精力。幸运的是,有一些不错的 MVVM 框架可供选择,例如 Prism、Cailburn、nRoute 和 Galasoft 的 MVVM Light Toolkit。我们将探索如何使用 Laurent Bugnion 的 MVVM Light Toolkit 在 WPF 应用程序中实现 MVVM。

MVVM Light 工具包的主要目的是加速在 WPF、Silverlight、Windows Store (RT) 和 Windows Phone 中创建和开发 MVVM 应用程序

本文中解释的步骤专门针对那些想要开始 MVVM 开发并需要现成工具包来开发其 WPF 应用程序的人。

安装 MVVMLight

 MVVM Light 工具包可以从https://mvvmlight.codeplex.com/下载。

Visual Studio 2012 和 2013 的项目模板可以在http://mvvmlight.codeplex.com/releases/view/115541下载。目前,模板仅为 Visual Studio 2012 和 2013 Pro、Premium 和 Ultimate 版提供。MvvmLight.VS2012.vsix 适用于 Visual Studio 2012,MvvmLight.VS2013.vsix 适用于 Visual Studio 2013。根据您的 Visual Studio 版本,安装相应模板后,项目模板将可用,如图 1 所示:

wpf项目模板

图 1:VS 2013 中的 MVVM Light Toolkit 模板

这些项目模板默认为 MVVM Light Framework 提供必要的库,项目结构包含 ViewModel 类、模型,如图 2 所示:

mvvm项目结构

图 2:Visual Studio 中的 MVVM Light 库

这些库提供了用于实现具有可通知属性、命令等的 ViewModel 的类。

如果我们需要在已经存在的项目中添加 MVVM Light 库,那么我们可以使用 NuGet 包来获取这些库。为此,请在 Visual Studio 中打开一个现有 WPF 项目 > 右键单击​​该项目 > 选择Manage NuGet Package > 并从 NuGet 窗口中选择 MVVM Light 库,如图 3 所示:

nugetmvvmlight

图 3:MVVM Light NuGet 包

在 WPF 4.5 中使用 MVVM Light

在接下来的步骤中,我们将使用 MVVM Light 来实现一个 WPF 应用程序,该应用程序执行一些基本的数据库操作。在这些步骤中,我们将利用 MVVM Light 的以下功能:

  • 使用ViewModelBase类创建 ViewModel 。
  • 在 ViewModel 类中定义 Notifiable 属性并使用 ViewModelBase 类中的RaisedPropertyChanged方法引发 PropertyChanged 事件。
  • 使用Commanding提供的RelayCommand类来执行基于在 UI 上执行的操作的方法。
  • 使用Commanding提供的EventToCommand类来定义默认情况下不支持 Command 属性的 WPF 元素上的命令。
  • 用于跨对象交换消息的Messenger功能。

对于此应用程序,我们将在示例 SQL Server Company 数据库中使用下表:

sql表

图 4:SQL Server 员工表

第 1 步:打开 Visual Studio 并创建一个 WPF 应用程序并将其命名为“WPF_MVVMLight_CRUD”。到此项目中,使用 NuGet 包添加 MVVM Light Libraries,如安装部分所述。该项目将添加必要的库和具有以下两个类的“ViewModel”文件夹:

- MainViewModel.cs - 此类继承自 ViewModelBase 类,它提供对RaisedPropertyChanged方法的访问权限,用于通知属性。

- ViewModelLocator.cs - 此类用于包含应用程序中所有视图模型的静态引用。此类的构造函数提供了一个非常简单的 IOC 容器,用于注册和解析实例。代码如下所示:

ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);  

可以在此处找到有关服务定位器的信息:http: //msdn.microsoft.com/en-us/library/ff648968.aspx

该类在其构造函数的 IOC 容器中注册MainViewModel类:

SimpleIoc.Default.Register();  

它还使用只读属性提供了 MainViewModel 的实例,如下所示:

public MainViewModel Main
{
    get
    {
        return ServiceLocator.Current.GetInstance();
    }
}

ViewModelLocator实例将在 App.Xaml 资源中注册:

    

这将用于应用程序中跨视图的 DataBinding。

第 2 步:在项目中,添加一个名为“Model”的新文件夹。在此文件夹中,添加一个名为“CompanyEDMX”的新 ADO.NET 实体数据模型 > 选择 SQL Server 数据库和 EmployeeInfo 表。向导完成后,将显示下表映射:

员工表映射

图 5:员工表映射

第 3 步:现在添加一个名为“Services”的新文件夹,并在此文件夹中添加一个包含以下代码的类文件:

using System.Collections.ObjectModel;
using WPF_MVVMLight_CRUD.Model;

namespace WPF_MVVMLight_CRUD.Services
{

    /// 

    /// The Interface defining methods for Create Employee and Read All Employees  
    /// 

    public interface IDataAccessService
    {
        ObservableCollection GetEmployees();
        int CreateEmployee(EmployeeInfo Emp);
    }
    
    /// 

    /// Class implementing IDataAccessService interface and implementing
    /// its methods by making call to the Entities using CompanyEntities object
    /// 

    public class DataAccessService : IDataAccessService
    {
        CompanyEntities context;
        public DataAccessService()
        {
            context = new CompanyEntities();
        }
        public ObservableCollection GetEmployees()
        {
            ObservableCollection Employees = new ObservableCollection() ;
            foreach (var item in context.EmployeeInfoes)
            {
                Employees.Add(item);
            }
            return Employees;
        }

        public int CreateEmployee(EmployeeInfo Emp)
        {
            context.EmployeeInfoes.Add(Emp);
            context.SaveChanges();
            return Emp.EmpNo;
        }
        
    }
}

此代码定义了一个接口,用于使用实体框架访问数据库中的数据。

注:这是结合ADO.NET和SQLServer数据库的形式,用MySQL和MySQL的连接库可能要修改。

第 4 步:要在 IoC 中注册数据访问服务,我们需要在其中注册DataAccessService类。为此,请打开ViewModelLocator类,并添加以下行:

SimpleIoc.Default.Register();  

DataAccessService 类的命名空间必须在 ViewModelLocator 类中使用。

第 5 步:让我们实现从表中读取所有员工的逻辑。

在 MainViewModel 类中,添加以下 Public 通知属性:

ObservableCollection _Employees;

public ObservableCollection Employees
{
    get { return _Employees; }
    set
    {
        _Employees = value;
        RaisePropertyChanged("Employees");
    }
}

此属性将向 UI 公开。属性的设置器调用RaisedPropertyChanged方法,该方法将在集合中的数据发生更改时在内部引发PropertyChanged事件。

在 ViewModel 类级别定义IDataAccessService对象,如下所示:

IDataAccessService _serviceProxy;  

在 ViewModel 类中,声明以下方法来获取员工数据:

/// 

/// Method to Read All Employees
/// 

void GetEmployees()
{
    Employees.Clear();
    foreach (var item in _serviceProxy.GetEmployees())
    {
        Employees.Add(item);
    }
}

上述方法从DataAccessService类中调用GetEmployees()方法,并将所有员工放入员工可观察集合中。

在 ViewModel 类中,现在定义RelayCommand对象如下:

public RelayCommand ReadAllCommand { get; set; }  

使用构造函数依赖项将IDataAccessService传递给 ViewModel 的构造函数。DataAccessService 的对象可以从我们在第 4 步中注册的 IOC 获得。同时实例化 Employees 可观察集合和ReadAllCommand对象:

public MainViewModel(IDataAccessService servPxy)
{
    _serviceProxy = servPxy;
    Employees = new ObservableCollection();
    ReadAllCommand = new RelayCommand(GetEmployees);
}

ReadAllCommand与 GetEmployees() 方法一起传递

第 6 步:在项目中,添加由 MVVM Light 工具包提供的新 MVVM 视图,如下所示:

mvvmlight视图模式

图 6:MvvmView 模板

将此视图命名为“EmployeeInfoView.xaml”。

注意:默认情况下,MVVM Light View 添加 WPF 窗口,因此对于此应用程序,我们将用 UserControl 替换 Window。将视图的根标记从 Window 更改为 UserControl 后,在视图后面的代码中,将基类从 Window 更改为 UserControl。

第 7 步:在此视图中,添加一个 DataGrid、TextBlock 和一个 Button,如图所示:

员工视图

图 7:我们应用程序的 UI 设计

在 XAML 部分中,将 UserControl 的DataContext属性设置为ViewModelLocator类公开的“Main”属性:

DataContext="{Binding Main, Source={StaticResource Locator}}"  

“定位器”在 App.Xaml 资源中声明。Main是 ViewModelLocator 类公开的公共属性,它返回 MainViewModel 类的对象。上面的表达式意味着 MainViewModel 现在与 UserControl 绑定。这意味着所有公共声明(可通知的属性和命令)都可以与视图上的 XAML 元素绑定。

将 MainViewModel 的ReadAllCommand命令和Employees 集合属性分别绑定到Button 和DataGrid :


              

第 8 步:打开 MainWindow.xaml 并将其宽度更改为 1300。将 Grid 元素的宽度设置为 1290,并在其中创建两列,每列宽度为 640。在第零 (0) 列中,添加EmployeesInfo视图。

要在 MainWindow.xaml 中添加视图,必须在 Window 标记中注册视图的命名空间:

xmlns:Views="clr-namespace:WPF_MVVMLight_CRUD.Views"

现在将视图添加到网格:

    

第 9 步:运行项目并显示一个视图。点击“List All Employees”,结果如图8所示:

列出所有员工

图 8:列出所有员工

将参数从 View 传递到 ViewModel

在前面的步骤中,我们讨论了如何创建 ViewModel、定义可通知属性和 RelayCommand。在本节中,我们将讨论如何将数据从 View 发送到 View Model 并写入我们的数据库表中。

第 1 步:在 MainViewModel 中,声明以下属性:

EmployeeInfo _EmpInfo;

public EmployeeInfo EmpInfo
{
get { return _EmpInfo; }
set
{
_EmpInfo = value;
RaisePropertyChanged("EmpInfo");
}
}

EmployeeInfo对象将用于添加新的员工记录。

定义以下方法,该方法接受 EmployeeInfo 对象,并通过调用DataAccessService 类的CreateEmployee()方法将其保存到表中。

void SaveEmployee(EmployeeInfo emp)
{
EmpInfo.EmpNo = _serviceProxy.CreateEmployee(emp);
if(EmpInfo.EmpNo!=0)
{
Employees.Add(EmpInfo);
RaisePropertyChanged("EmpInfo");
}
}

CreateEmployee 方法返回 EmpNo。如果这不为零,那么 emp 对象将被添加到 Employees 可观察集合中。

现在在 ViewModel 类中定义 RelayCommand 对象属性:

public RelayCommand SaveCommand { get; set; }

中继命令声明泛型类型属性,其中T表示输入参数;在我们的例子中,T 属于 EmployeeInfo 类型。

在 ViewModel 构造函数中实例化 EmpInfo 和 RelayCommand:

EmpInfo = new EmployeeInfo();
SaveCommand = new RelayCommand(SaveEmployee);

RelayCommand 通过SaveEmployee()方法传递。这是可能的,因为 SaveEmployee 方法接受 EmployeeInfo 作为其输入参数。这与通用 RelayCommand 属性的声明中定义的对象相同。

第 2 步:打开 App.Xaml 并在resources中,为 TextBlock 和 TextBoxes 添加样式:

        

由于这些样式是在 App.Xam 中定义的,因此没有任何键,它们将应用于应用程序中的所有 TextBlock 和 TextBox。

第 3 步:在项目的 Views 文件夹中,添加一个新的 UserControl(您也可以使用 MVVM Light View),并将其命名为“SaveEmployeeView.xaml”。在视图中,添加文本块、文本框和一个按钮。将 UserControl 的 DataContext 设置为 MainViewModel 的 Main 属性。

DataContext="{Binding Main, Source={StaticResource Locator}}"  

对于所有的 TextBox,将它们的Text属性绑定到EmpInfo属性,并将Button的command属性绑定到Main ViewModel公开的SaveCommand 。同时,将 EmpInfo 属性绑定到按钮的CommandParameter属性。这是将从 View 传递到 ViewModel 的实际参数。XAML 如下所示:

          
              

该视图现在看起来如图 9 所示:

保存员工视图

第 4 步:在第二列(列索引 1)中添加我们刚刚在 MainWindow.xaml 中创建的 UserControl:

  

第 5 步:运行应用程序,单击“列出所有员工”以在 DataGrid 中显示所有员工。

mvvm-视图

图 10:列出所有员工视图

我没有添加任何验证来保持本文范围的简洁,但你应该这样做。输入员工数据(EmpNo 除外)并单击“保存员工”按钮。记录被添加。现在滚动到 DataGrid 的底部,你会发现我们新添加的记录:

添加新记录

图 11:新增记录

我们已经看到了如何使用通用命令将参数从 UI 传递到 ViewModel。

 

在没有 Command 属性的 UI 元素上定义命令

 

UI 元素(如 Button、RadioButton 等)公开了 command 属性,使用 ViewModel 中的哪些方法可以执行。但是如果我们需要在 UI 上有一个搜索文本框,当输入数据时,文本框中的匹配数据会从集合中搜索并显示在 UI 上。在这种情况下,我们需要更改文本框的行为以支持命令。

当我们在项目中添加 MVVM Light 库时,项目也添加了System.Windows.Interactivity.dll程序集。这个程序集允许我们定义 UI 元素的行为。

MVVM Light 库在GalaSoft.MvvmLight.Command命名空间下提供了一个EventToCommand类。此类允许我们将任何 FrameworkElement 的任何事件绑定到 ICommand。在我们的例子中,我们将使用EventToCommand通过在 TextBox 的 TextChanged 事件上定义命令来执行 ViewModel 类的方法。

第 1 步:打开 MainViewModel 并在其中添加以下属性、方法和命令:

public string EmpName
{
get { return _EmpName; }
set
{
_EmpName = value;
RaisePropertyChanged("EmpName");
}
}

字符串属性将与视图中的文本框绑定。在文本框中输入文本时将设置此属性。

void SearchEmployee()
{
    Employees.Clear();
    var Res = from e in _serviceProxy.GetEmployees()
              where e.EmpName.StartsWith(EmpName)
              select e;
    foreach (var item in Res)
    {
        Employees.Add(item);
    }
}

该方法根据 EmpName 从集合中过滤员工。现在在 ViewModel 中定义 RelayCommand 对象:

public RelayCommand SearchCommand { get; set; }

通过将 SearchEmployee 方法传递给它,在 MainViewModel 的构造函数中实例化 Command 对象:

SearchCommand = new RelayCommand(SearchEmployee);  

第 2 步:打开 EmployeeInfoView.xaml 并向其中添加一个 TextBlock 和 TextBox。要将 Interactivity 和 EventToObject 注册到 XAML,我们需要 UserControl 标记中的以下程序集:

xmlns:i=http://schemas.microsoft.com/expression/2010/interactivity
xmlns:mvvm="http://www.galasoft.ch/mvvmlight"  

定义 DataBinding,在 TextBox 上进行命令的交互性如下:

在 XAML 中,TextBox 与 MainViewModel 的 EmpName 属性绑定。Binding 类的UpdateSourceTrigger属性设置为PropertyChanged 事件;这意味着当在文本框中输入文本时,将使用文本框中的文本设置 EmpName 属性。事件触发器在TextChanged事件的文本框中定义。这意味着当触发 TextChanged 事件时,EventToCommand 将执行 MainViewModel 中定义的 SearchCommand 方法。

第 3 步:运行应用程序,单击“列出所有员工”按钮,所有员工将显示在 DataGrid 中:

搜索员工

图 12:列出所有员工

在 EmpName 中输入一些文本以搜索 TextBox。DataGrid 将由所有具有 EmpName 的 Employee 记录填充,该记录以文本框中输入的文本开头:

搜索员工文本

图 13:搜索 DataGrid

因此使用EventToCommand,我们可以轻松地将命令绑定到 FrameworkElement。

跨两个视图管理消息传递

通常,当开发阶段涉及多个团队时,他们可能会设计单独的视图,并且这些视图存在于同一个容器中。例如,以显示所有员工列表的EmployeeInfoView和执行 Create、Update 等操作的SaveEmployeeView 为例。现在的要求是,当从 EmployeeInfoView 中选择一个 Employee 时,它​​应该显示在 SaveEmployeeView 中以进行更新。由于这两个视图都有自己的 ViewModel,因此可能会通过这些 ViewModel 发送数据。

由于两个视图是分开的,我们如何将选定的员工从一个视图发送到另一个视图?传统上,这可以使用事件处理机制来实现。选择员工时,请提高事件并将员工信息传递给本事件,然后在其他观点中收听此事件。这种方法要求两个视图都应该通过访问彼此的对象来直接相互通信。这是紧耦合的场景。那么现在的问题是如何以松散耦合的方式实现相同的功能?

答案是使用MVVM Light Messenger。这个信使提供了一种松散绑定的方式来将消息(数据)从一个 ViewModel 发送到另一个 ViewModel。

从图表上看,信使可以解释如下:

mvvm-光信使

图 14:MVVMLight信使

Messenger 是一个存在于整个应用程序中的单例对象。发送方 ViewModel 只需调用静态的“发送”方法。接收者 ViewModel 需要向 messenger 注册才能接收对象。它提供了一个回调函数,在收到新消息时调用该函数。让我们看看这是如何做到的。

第 1 步:在项目中添加一个新文件夹并将其命名为“MessageInfrastructure”。在此文件夹中,添加一个新的类文件:

using WPF_MVVMLight_CRUD.Model;

namespace WPF_MVVMLight_CRUD.MessageInfrastructure
{
    public class MessageCommunicator
    {
        public EmployeeInfo Emp { get; set; }
    }
}

上面的类定义了 EmployeeInfo 类型的Emp属性。这将用作从一个视图传递到另一个视图的消息(数据)。

第 2 步:在 MainViewModel 中添加以下方法:

void SendEmployeeInfo(EmployeeInfo emp)
{
    if(emp!=null)
    { 
        Messenger.Default.Send(new MessageCommunicator() { 
          Emp = emp
        });
    }
}

注意:请在 MainViewModel 中添加“GalaSoft.MvvmLight.Messaging”命名空间。

上述方法接受一个EmployeeInfo 对象并调用Messenger 的Send() 方法,该方法被键入到MessageCommunicator 类中。这意味着调用上述方法的 View 必须传递 EmployeeInfo 对象。

在 ViewModel 中定义以下RelayCommand对象:

public RelayCommand SendEmployeeCommand { get; set; }

RelayCommand 使用EmployeeInfo 类型的参数定义。这意味着它将执行具有 EmployeeInfo 类型的输入参数的方法。

在 ViewModel 的构造函数中,定义 RelayCommand 的实例,如下所示:

SendEmployeeCommand = new RelayCommand(SendEmployeeInfo);
 

第 2 步:打开 EmployeeInfoView 并为 DataGrid 定义 EventToCommand。由于DataGrid与员工收藏集约束,因此选择数据杂志时,它将选择员工Iinfo对象。我们将 DataGrid 的 SelectionChanged 事件映射到 EventToCommand,如下所示:

 

上面的 XAML 显示 Command 属性与 ViewModel 中声明的SendEmployeeCommand绑定。从 UI 发送到 ViewModel 的参数是SelectedItem,它是一个 EmployeeInfo 对象。由于 SendEmployeeCommand 执行SendEmployeeInfo方法,因此 EmployeeInfo 对象将被传递给该方法。

第3步:现在我们需要注册信使。为此,在 MainViewModel 添加以下方法:

void ReceiveEmployeeInfo()
{
    if (EmpInfo != null)
    { 
        Messenger.Default.Register(this,(emp)=>{
            this.EmpInfo = emp.Emp;
        });
    }
}

上述方法注册到 messenger 并接受接收到的 Emp 消息。然后将此消息设置为 ViewModel 类中定义的 EmpInfo 通知属性。在 ViewModel 的构造函数中调用此方法。由于 EmpInfo 属性与 SaveEmployeeView 绑定,因此将在其中显示 Employee 数据。

第 4 步:运行应用程序,单击“加载所有员工”按钮,DataGrid 将显示所有员工。从 DataGrid 中选择 Row,选中的员工信息将显示在 SaveEmployeeView 中,如下所示:

mvvm 信使

这表明我们可以轻松地在两个单独的视图中建立 Messenger 基础通信。

结论

MVVM 有很多优点,但它可能需要你自己设置很多东西。MVVM Light 工具包提供了大量样板代码来快速实现基于 MVVM 的应用程序,并为用户提供了自定义和设计应用程序的自由。使用 MVVM Light 工具包中的 ViewModelBase,我们不再需要实现 INotifyPropertyChanged。此外,MVVM 轻工具包提供了 Visual Studio 模板、信使、IoC 容器和一些有用的代码片段,可以让我们的 WPF 应用程序大放异彩!


友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内