Model View Controller (MVC) Using C#, Delegates and Events in .NET

转载 2004年09月18日 11:19:00

Introduction

During my third year at the Fontys University in Holland I bumped into a concept called Model-View-Controller. We created a small test project containing the MVC pattern and incorporated different data structures to get experienced with different programming techniques. I embraced the power of patterns and filled my days and nights reading material produced by the Gang of Four. While I was fooling around with .NET during my traineeship at KSE group BV in Holland I decided to experiment with different patterns like MVC, Singleton, Factory etc. This article explains the MVC pattern's basics and clears the big implementation question up with a decent practical example written in my favorite programming language, C#.

Model View Controller

The actual pattern employed in this example, is Model View Controller (MVC). The Windows Forms component will act as the View. There's a book class which represents the Model. The actual Controller logic isn't separated from the View/Model because of my primary design goals. I will publish an extensive MVC-system in the near future which will be reusable for all kind of .NET applications.

Delegates

A delegate is a type-safe method reference. With usage of delegates, programs can dynamically call methods at runtime. In contrast to our MVC pattern delegates provide a solid infrastructure to implant the publish-subscribe notification pattern. For those who have experience with Java, I'm referring to the Observer/Observable registration functionality witch the JDK 1.3 provides for exploiting the MVC pattern in the Java environment.

Events

An event is common in modern programming languages. The basic usage of events is indicating certain user-defined occurrences inside your program. Events are used to notify certain listeners during the program lifetime. A very good example is button clicks or other dynamic actions in your programs. Events are again powered by the publish/subscriber pattern.

The model

While coding this basic example in order to explore MVC pattern I thought of books obviously. Below displayed is a basic book class implementation. This Book class contains a private member called bookPrice. The basic functionality I want to provide for all object who wish to instantiate my book class is an actual book price, in the case that the price changes, my views will update their views in order to display the actual book price. The idea is simple so lets move on… see the comments in the code.

using System;
namespace MVC
{
    public class Book
    {
        // declare a delegate for the bookpricechanged event
        public delegate void BookPriceChangedHandler(objectsender,
        BookPriceChangedEventArgs e);
        
        // declare the bookpricechanged event using the bookpricechangeddelegate
        public event BookPriceChangedHandlerBookPriceChanged;
        
        // instance variable for book price
        object _bookPrice;
        
        // property for book price
        public object BookPrice
        {
            set
            {
                // set the instance variable
                _bookPrice=value;
                
                // the price changed so fire the event!
                OnBookPriceChanged();
            }
        }
        
        // method to fire price canged event delegate with proper name
        // this is the method our observers should be implenting!
        protected void OnBookPriceChanged()
        {
            BookPriceChanged(this, new BookPriceChangedEventArgs(_bookPrice));
        }
    }
}

So what happened here; we'd structured the basic layout for the book class. Notice the declared delegate and event BookPriceChangedHandler and BookPriceChanged. The delegate encapsulates the BookPriceChanged method. Later we'll see why, but for know its enough to know that the BookPriceChanged method will be implemented in the object that wishes to observe this book class. As you can see, the method gets called with the BookPriceChangedEventArgs. This argument object contains the public properties the book object encapsulates. This is just the standard way for transporting multiple parameters towards methods. Kind of basic programming, so this should be self explanatory. Lets take a brief look at the BookPriceChangedEventArgs class.

namespace MVC
{
    // specialized event class for the bookpricechanged event
    public class BookPriceChangedEventArgs : EventArgs
    {
        // instance variable to store the book price
        private object _bookPrice;

        // constructor that sets book price
        public BookPriceChangedEventArgs(objectbookPrice)
        {
            _bookPrice=bookPrice;
        }

        // public property for the book price
        public object BookPrice
        {
            get
            {
                return _bookPrice;
            }
        }
    }
}

Maybe you noticed that I used the object (like in Java the "any") instead of string declaration for my price value. The main reason for this is that while creating this model I didn't know what kind of GUI representation I wished to use to show my book price value. In case you wish to add more members to the Book class, for instance a name, author, you should extend this EventArgs class. I would consider giving the class a more abstract name like BookChanged.

The view

Now our model is functional so let's move on to the View. Below is a listing of the view object BookView which subscribes to the book model using a delegate. This way the observer gets notified when the price change events is thrown in the model (the observable). You could pass the private book object through reference to multiple views (think of those smart Adobe Photoshop panels, which are views on the underlying model). In this demo I created a simple two-view system making use of a textbox and a basic label to visualize the book model.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
 
namespace MVC
{
    public class BookView : System.Windows.Forms.Form
    {
        private System.ComponentModel.Container components = null;
 
        // Declare our delagate and book object
        private Book.BookPriceChangedHandler bookDelegate;
        private Book book;
 
        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.TextBox textBox2;
        private System.Windows.Forms.GroupBox groupBox2;
        private System.Windows.Forms.Label label1;
 
        public BookView()
        {
            InitializeComponent();
 
            //create new book instance
            book=new Book();
   
            // create a new delegate, instance and bind it
            // to the observer's bookpricechanged method
            bookDelegate = new Book.BookPriceChangedHandler(this.BookPriceChanged);    
            //add the delegate to the event
            book.BookPriceChanged += bookDelegate;
        }
 
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if(components != null)
                {
                     components.Dispose();
                }
            }
            base.Dispose( disposing );
        }
 
        #region Windows Form Designer generated code
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.textBox2 = new System.Windows.Forms.TextBox();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.label1 = new System.Windows.Forms.Label();
            this.groupBox1.SuspendLayout();
            this.groupBox2.SuspendLayout();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(120, 16);
            this.button1.Name = "button1";
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(8, 16);
            this.textBox1.Name = "textBox1";
            this.textBox1.TabIndex = 1;
            this.textBox1.Text = "";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.AddRange(new System.Windows.Forms.Control[] {
            this.textBox2});
            this.groupBox1.Location = new System.Drawing.Point(8, 104);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(120, 64);
            this.groupBox1.TabIndex = 2;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "View 1";
            // 
            // textBox2
            // 
            this.textBox2.Location = new System.Drawing.Point(8, 32);
            this.textBox2.Name = "textBox2";
            this.textBox2.TabIndex = 0;
            this.textBox2.Text = "";
            // 
            // groupBox2
            // 
            this.groupBox2.Controls.AddRange(new System.Windows.Forms.Control[] {
            this.label1});
            this.groupBox2.Location = new System.Drawing.Point(8, 176);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(120, 64);
            this.groupBox2.TabIndex = 3;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "View 2";
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(8, 32);
            this.label1.Name = "label1";
            this.label1.TabIndex = 0;
            // 
            // BookView
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
            this.groupBox2,
            this.groupBox1,
            this.textBox1,
            this.button1});
            this.Name = "BookView";
            this.Text = "BookView";
            this.groupBox1.ResumeLayout(false);
            this.groupBox2.ResumeLayout(false);
            this.ResumeLayout(false);
 
        }
        #endregion
 
        [STAThread]
        static void Main() 
        {
            Application.Run(new BookView());
        }
 
        public void BookPriceChanged(object sender, MVC.BookPriceChangedEventArgs e) 
        {
            // update bookprice views
            object bookPrice;
            bookPrice = e.BookPrice;         
            this.textBox2.Text = bookPrice.ToString();
            this.label1.Text = bookPrice.ToString();
        }
 
        private void button1_Click(object sender, System.EventArgs e)
        {
            // change book price
            book.BookPrice = this.textBox1.Text;
        }
    }
}

As soon you make changes to the book price, the BookPriceChanged will be triggered in the model. Because the view is registered to the OnBookPriceChanged method, the BookPricechanged will be invoked from the model. The View (observer) implements the BookPriceChanged method so the views get updated according to the rules as specified in the view upon the book model. Confused? Then start toying with this code because you now know the basics concerning a simple MVC! The book class code is reusable for whatever functionality you wish to provide to the outside world from out your model. Have fun!

Conclusion

I'm sure I've explained the MVC mechanism in the .NET world using C# extensively. In my opinion .NET is a fantastic environment for both starting coders and more experienced coders. You'll need some basic knowledge concerning object oriented programming to make a jump start into the .NET Framework. I enjoyed writing this article and hope it was a useful addition for those who read it.

MVC传值--从Controller想View传递List集合

在MVC中,传值是一个很重要的内容之一。前面的博客中,我们了解了如何从Controller中向View传递单个的变量值以及从View向Controller的反向传递。        这次我们来看看,...
  • u010191243
  • u010191243
  • 2015年02月16日 17:08
  • 5515

ASP.NET MVC3中Controller与View之间的数据传递总结

在ASP.NET MVC中,经常会在Controller与View之间传递数据,因此,熟练、灵活的掌握这两层之间的数据传递方法就非常重要。本文从两个方面进行探讨: 1 Controller向View...
  • sknice
  • sknice
  • 2015年01月01日 22:59
  • 43667

SpringMVC学习记录(二)--controller和view的联系

对于SpringMVC来说,controller由两个部分构成,分别是分发器和控制器,分发器DispatcherServlet决定着请求使用哪个控制器,并且决定着控制器返回哪个视图,整体结构如下. ...
  • u012706811
  • u012706811
  • 2016年04月04日 16:51
  • 5044

MVC 各种传值方式 ASP.NET MVC view与controller传值方式

MVC 各种传值方式 ViewData传值. HomeController.cs Co de: public ActionResult Index() {       ViewDat...
  • u013045437
  • u013045437
  • 2015年12月23日 11:10
  • 2013

强类型视图中提交表单,把View中的Model数据传递给Controller

若要实现强类型视图中提交表单,把View中的Model数据传递给Control,那么必须要确保一件事——表单中的input标签元素的name属性的值必须与model中的属性名相同,不区分大小写。 示例...
  • wangzl1163
  • wangzl1163
  • 2016年09月09日 11:20
  • 1527

[.NET MVC4 入门系列04]Controller和View间交互原理

一、Edit Action和其所对应的Edit View: 1.Edit 链接: 在Index页中的Edit链接是由代码生成:@Html.ActionLink("Edit","Edit",...
  • u011978814
  • u011978814
  • 2017年03月15日 15:24
  • 404

MVC中Controller间的传值、Controller到View的传值方法

从做了考试以来,和别人也进行了交流,发现系统内部的传值算是一个比较费劲的问题。这篇博客讲解两种传值的情况——MVC中Controller间的传值,这里包括了第二种Controller到View的传值。...
  • u010191243
  • u010191243
  • 2015年01月30日 21:20
  • 2150

MVC 各种传值方式 ASP.NET MVC view与controller传值方式

MVC 各种传值方式 ViewData传值. HomeController.cs Co de: public ActionResult Index() {       ViewData["Titl...
  • deepwishly
  • deepwishly
  • 2013年08月08日 15:06
  • 21991

asp.net MVC前台View页面向后台Controller控制器传递数据的几种方式

上一篇文章讲解了后台控制器如何向前台页面传递数据,今天就接着为大家讲解前台View页面向后台Controller控制器传递数据的几种方式。在此声明,这几种方式是我在实际使用过程中遇到并总结的,如果那个...
  • ydm19891101
  • ydm19891101
  • 2015年03月17日 08:37
  • 8150

Asp.net mvc 创建一个带有集合的View

阅读了前几节内容,感觉似乎很简单,没有多大技术含量,从现在开始接触一些稍微深点的东西。在本节中,尝试用View显示一个Teacher的列表。 1、修改TeacherViewModel类,删除掉Use...
  • u013108485
  • u013108485
  • 2016年04月13日 11:38
  • 417
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Model View Controller (MVC) Using C#, Delegates and Events in .NET
举报原因:
原因补充:

(最多只允许输入30个字)