Ninject之旅之十二:Ninject在Windows Form程序上的应用(附程序下载)
摘要:
下面的几篇文章介绍如何使用Ninject创建不同类型的应用系统。包括:
- Windows Form应用系统
- ASP.NET MVC应用系统
- ASP.NET Web Form应用系统
尽管对于不同类型的应用系统,Ninject向应用组件注入依赖项的方式是相同的。但是根据不同应用系统架构不同,创建这些应用系统是不同的。一些新的框架例如ASP.NET MVC被设计成支持DI的,然而一些旧的框架例如ASP.NET是不支持所有DI模式。
前面已经介绍了Ninject提供的大多数功能,下面我们将在一个工程里应用这些功能。我们将实现一些应用,每一个应用都包含一个数据访问层,一个业务层,一个表现层,前面两层将在所有应用中共享。
准备工作
1. 在网上下载Northwind数据库,并Restore或Attach到本地数据库。
2. 用Visual Studio 2015创建空解决方案Demo.Northwind。
3. 在解决方案Demo.Northwind里创建数据访问层工程:Demo.Northwind.Core。
在工程Demo.Northwind.Core内,用NuGet Manager添加引用EntityFramework和Ninject。
在工程Demo.Northwind.Core内添加如下文件/文件夹。
Customer.cs:
namespace Demo.Northwind.Core.Model
{
public class Customer
{
public string CustomerID { get; set; } public string CompanyName { get; set; } public string City { get; set; } public string PostalCode { get; set; } public string Phone { get; set; }
}
}
ICustomerRepository.cs:
using Demo.Northwind.Core.Model;
using System.Collections.Generic; namespace Demo.Northwind.Core.Interface
{
public interface ICustomerRepository
{
IEnumerable<Customer> GetAll(); Customer Get(string customerID); void Add(Customer customer);
}
}
NorthwindContext.cs:
using Demo.Northwind.Core.Model;
using System.Data.Entity; namespace Demo.Northwind.Core.SqlDataAccess
{
public class NorthwindContext : DbContext
{
public NorthwindContext() { } public DbSet<Customer> Customers { get; set; }
}
}
SqlCustomerRepository.cs:
using System.Collections.Generic;
using Demo.Northwind.Core.Interface;
using Demo.Northwind.Core.Model; namespace Demo.Northwind.Core.SqlDataAccess
{
public class SqlCustomerRepository : ICustomerRepository
{
private readonly NorthwindContext _context; public SqlCustomerRepository()
{
_context = new NorthwindContext();
} public void Add(Customer customer)
{
_context.Customers.Add(customer);
_context.SaveChanges();
} public Customer Get(string customerID)
{
return _context.Customers.Find(customerID);
} public IEnumerable<Customer> GetAll()
{
return _context.Customers;
}
}
}
创建工程Demo.Northwind.Winforms
Windows Forms是实现DI的一个最直接的应用系统类型。像Console应用程序一样,它不需要特别的Ninject配置。在Program类里的Main方法注册依赖项,框架里的组件例如Form类不需要一个无参数的构造函数,这使得实现构造函数注入变得很简单。
1. 在工程Demo.Northwind.Winforms内使用NutGet Manager添加如下引用:
2. 在工程Demo.Northwind.Winforms内添加到Demo.Northwind.Core的引用。
修改App.config,添加数据库连接字符串:
<connectionStrings>
<add name="NorthwindContext" providerName="System.Data.SqlClient" connectionString="Data Source=localhost;Initial Catalog=NORTHWND;Integrated Security=True" />
</connectionStrings>
3. 在MainForm里添加一个DataGrid控件,一个BindingSource控件。绑定DataGrid控件的数据源到BindingSource控件。
代码:
using Demo.Northwind.Core.Interface;
using Demo.Northwind.Core.Model;
using System;
using System.Linq;
using System.Windows.Forms; namespace Demo.Northwind.Winforms
{
public partial class MainForm : Form
{
private readonly ICustomerRepository _repository; public MainForm(ICustomerRepository repository)
{
this._repository = repository;
InitializeComponent();
} private void MainForm_Load(object sender, EventArgs e)
{
LoadCustomers();
} private void LoadCustomers()
{
var customers = _repository.GetAll();
customerBindingSource.DataSource = customers.ToList<Customer>();
}
}
}
ICustomerRepository是这个类唯一的依赖项,在构造函数内引入和注入。
4. 既然MainForm的构造函数注入了一个ICustomerRepository对象,需要在Ninject中完成依赖注入,并使用kernel.Get<CustomerForm>()得到MainForm窗口对象,修改Program.cs:
using System;
using System.Windows.Forms;
using Ninject;
using Ninject.Extensions.Conventions; namespace Demo.Northwind.Winforms
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); using (var kernel = new StandardKernel())
{
kernel.Bind(x => x.FromAssembliesMatching("Demo.Northwind.*")
.SelectAllClasses()
.BindAllInterfaces()); var mainForm = kernel.Get<MainForm>();
Application.Run(mainForm);
}
}
}
}
5. 如果要在MainForm窗口上加一个“Create”按钮,点击按钮打开一个CustomerForm窗口用来添加新Customer并保存到数据库。CustomerForm窗口类也应该在构造函数中注入一个ICustomerRepository对象。
新建Windows Form:CustomerForm。
代码:
using Demo.Northwind.Core.Interface;
using Demo.Northwind.Core.Model;
using System;
using System.Windows.Forms; namespace Demo.Northwind.Winforms
{
public partial class CustomerForm : Form
{
private readonly ICustomerRepository repository; public CustomerForm(ICustomerRepository repository)
{
this.repository = repository;
InitializeComponent();
customerBindingSource.Add(new Customer());
} private void saveButton_Click(object sender, EventArgs e)
{
customerBindingSource.EndEdit();
var customer = customerBindingSource.Current as Customer;
repository.Add(customer);
this.DialogResult = DialogResult.OK;
} private void closeButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
}
}
}
6. 在MainForm.cs中添加Create按钮事件:createButton_Click:
private void createButton_Click(object sender, EventArgs e)
{ }
问题来了,CustomerForm窗口类只有一个注入ICustomerRepository对象的构造函数,不能使用new无参数的构造函数创建CustomerForm窗口类对象,也不能在MainForm窗口类里再新创建一个kernal对象,使用Get方法得到CustomerForm对象。
因此,我们怎么办呢?这个时候应该使用Ninject动态工厂。多亏了Ninject工厂功能,我们只需要简单地定义如下的接口:
using System.Windows.Forms; namespace Demo.Northwind.Winforms
{
public interface IFormFactory
{
T Create<T>() where T : Form;
}
}
在MainForm类里添加IFormFactory对象:
private readonly IFormFactory _formFactory;
修改MainForm类createButton_Click事件:
private void createButton_Click(object sender, EventArgs e)
{
var customerForm = _formFactory.Create<CustomerForm>();
if (customerForm.ShowDialog(this) == DialogResult.OK)
{
LoadCustomers();
}
}
修改MainForm类构造函数,添加IFormFactory对象注入:
public MainForm(ICustomerRepository repository, IFormFactory formFactory)
{
this._repository = repository;
this._formFactory = formFactory;
InitializeComponent();
}
最后是在Program类的Main方法里添加注册我们的动态工厂服务:
kernel.Bind(x => x.FromThisAssembly()
.SelectAllInterfaces()
.EndingWith("Factory")
.BindToFactory()
.Configure(c => c.InSingletonScope()));
运行系统,测试系统运行情况。
Ninject之旅之十二:Ninject在Windows Form程序上的应用(附程序下载)的更多相关文章
- Ninject之旅之十:Ninject自定义提供者
摘要 提供者是特殊的工厂类,Ninject使用它来实例化解析类型.任何时候我们绑定一个服务类型到一个组件,我们都隐式地关联那个服务类型到一个可以实例化那个组件的提供者.这个隐藏的提供者被称为Stand ...
- JAVA之旅(十二)——Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口
JAVA之旅(十二)--Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口 开始挑战一些难度了,线程和I/O方面的操作了,继续坚持 一. ...
- Ninject之旅之十一:Ninject动态工厂(附程序下载)
摘要 如果我们已经知道了一个类所有的依赖项,在我们只需要依赖项的一个实例的场景中,在类的构造函数中引入一系列的依赖项是容易的.但是有些情况,我们需要在一个类里创建依赖项的多个实例,这时候Ninject ...
- Ninject之旅之十三:Ninject在ASP.NET MVC程序上的应用(附程序下载)
摘要: 在Windows客户端程序(WPF和Windows Forms)中使用Ninject和在控制台应用程序中使用Ninject没什么不同.在这些应用程序里我们不需要某些配置用来安装Ninject, ...
- Ninject之旅之十四:Ninject在ASP.NET Web Form程序上的应用(附程序下载)
摘要 ASP.NET Web Forms没有像MVC那样的可扩展性,也不可能使它创建UI页面支持没有构造函数的的激活方式.这个Web Forms应用程序的的局限性阻止了它使用构造函数注入模式,但是仍能 ...
- Ninject之旅之九:Ninject上下文绑定(附程序下载)
摘要 既然在插件模型里,每一个服务类型可以被映射到多个实现,绑定方法不用决定要返回哪个实现.因为kernel应该返回所有的实现.然而,上下文绑定是多个绑定场景,在这个场景里,kernel需要根据给定的 ...
- Sql Server之旅——第十二站 sqltext的参数化处理
说到sql的参数化处理,我也是醉了,因为sql引擎真的是一个无比强大的系统,我们平时做系统的时候都会加上缓存,我想如果没有缓存,就不会有什么 大网站能跑的起来,而且大公司一般会在一个东西上做的比较用心 ...
- Python学习之旅(十二)
Python基础知识(11):高级特性 一.分片(切片) 通过索引来获取一定范围内的元素 #字符串 s="Alice" s[0:4:2] 结果: 'Ai' #列表 l=[1,2,3 ...
- 前端编程提高之旅(十二)----position置入值应用
这次内推项目用到的遮罩及其页面下方button都涉及一个概念position置入值得概念.效果图例如以下: 一个元素position属性不是默认值static.那么该元素被称为定位元素. 定位的元素生 ...
随机推荐
- list集合怎么转化成一个javaBean对象,及常见的使用方法(全)
一.List集合的用法 1.list集合添加实体并输出 for (int i = 0; i < list.size(); i++) { javabean obj= (javabean)list. ...
- 基础数据结构之(Binary Trees)
从头开始刷ACM,真的发现过去的很多漏洞,特别越是基础的数据结构,越应该学习得精,无论是ACM竞赛,研究生考试,还是工程上,对这些基础数据结构的应用都非常多,深刻理解非常必要.不得不说最近感触还是比较 ...
- 设计模式笔记之一:MVP架构模式入门(转)
写在前面:昨天晚上,公司请来专家讲解了下MVP,并要求今后各自负责的模块都要慢慢的转到MVP模式上来.以前由于能力有限,没有认真关注过设计模式.框架什么的,昨晚突然兴趣大发,故这两天空闲时间一直在学习 ...
- 【转】iOS开发路线简述
简单看了下楼主说的很详细,尤其是最后面那个图描述很直观,让想学习ISO开发的程序猿很清晰每个步骤学习的内容,在此收藏下. iOS系统以及iPhone的出来都要感谢乔布斯,一个完美主义者,从如此优秀的i ...
- 【转】50条大牛C++编程开发学习建议
每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真 ...
- 【NOIP2015】反思+题解
D1T1> 神奇的幻方 模拟即可. #include <cstdio> #include <cstring> #include <algorithm> #de ...
- jstree使用小结(一)
项目中用到tree结构,使用了jstree做个笔记如下: 1. 官网: http://www.jstree.com/ 有时候打不开,那就只能等打得开的时候再看了...O(∩_∩)O [PS: 一 ...
- radioButton添加试题选项webview(二)
由于项目里radioGroup里,4个选项里加载的是webview,而不是radiobutton本身自己可设置的text类型,并且每个webview都需要和radiobutton对齐,所以这个布局有点 ...
- bzoj2555
开始时间:19:40 完成时间:21:00 传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2555 题目大意:(1):在当前字符串的后面插入一 ...
- JavaSE学习总结(一)——Java基础
一.Java是什么 Java 是由 Sun Microsystems 在 1995 年首先发布的编程语言和计算平台.Java 是一项用于开发应用程序的技术,可以让 Web 变得更有意思和更实用.有许多 ...