在学习 IssueVision 过程中,提到过观察者模式的用户控件(ChartPanel?),我按自己的设计思路也做了个不伦不类的观察者模式+用户控件,记录下来。
首先,建立一个观察者模式的接口 IObserver.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace IssueVision


{
public interface IObserver //接口声明

{
void NotifyDataChange(ChartData nChartData); //事件,当数据改变时
}

//ChartData 类,表示三类事务,open,work,close
public class ChartData

{
private int n_open;
private int n_work;
private int n_close;
private int n_max;

public int open

{
get

{
return n_open;
}
set

{
n_open = value > 0 ? value : 0;
n_max = value > n_max ? value : n_max;
}
}

public int work

{
get

{
return n_work;
}
set

{
n_work = value > 0 ? value : 0;
n_max = value > n_max ? value : n_max;
}
}

public int close

{
get

{
return n_close;
}
set

{
n_close = value > 0 ? value : 0;
n_max = value > n_max ? value : n_max;
}
}

public int max

{
get

{
return n_max;
}
set

{
n_max = value > 0 ? value : 0;
}
}

}
}

接着声明主体 ISubject.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace IssueVision


{
public interface ISubject //声明主体接口

{
// 需实现这两个,实现注册和反注册
void Register(IObserver anObject);
void UnRegister(IObserver anObject);
}
}

现在新建一个用户控件,放上一个 lbltitle 表示标题,三个 label 分别表示 open , work , close,再放三个 progressbar 表示数量,因为懒得画条形图,所以直接用 progressbar , 不过,用 progressbar 很难看倒是真的:(。,用户控件叫 ChartPanel.cs,代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace IssueVision.UserControls


{
public partial class ChartPanel : UserControl , IObserver //指定 IObserver ,表示实现它

{
private string m_title;
private int n_max;
private int n_open;
private int n_working;
private int n_closed;

[Description("图表标题")]
public string Title

{
get

{
return m_title;
}
set

{
m_title = value;
Invalidate();
}
}

[Description("最大数量")]
public int NMAX

{
get

{
return n_max;
}
set

{
n_max = value > 0 ? value : 0;
Invalidate();
}
}

[Description("打开任务数量")]
public int NOpen

{
get

{
return n_open;
}
set

{
n_open = value > 0 ? value : 0;
Invalidate();
}
}

[Description("进行的任务数量")]
public int NWorking

{
get

{
return n_working;
}
set

{
n_working = value > 0 ? value : 0;
Invalidate();
}
}

[Description("关闭的任务数量")]
public int NClosed

{

get

{
return n_closed;
}
set

{
n_closed = value > 0 ? value : 0;
Invalidate();
}
}

public void NotifyDataChange(ChartData nChartData) //实现观察者的 NotifyDataChage,表示当接受到数据变更时应用的动作。

{
//
n_max = nChartData.max;
n_open = nChartData.open;
n_working = nChartData.work;
n_closed = nChartData.close;
Invalidate();
}

public ChartPanel()

{
InitializeComponent();
}

private void ChartPanel_Paint(object sender, PaintEventArgs e)

{
this.lbTitle.Text = m_title;
pbOpen.Minimum = 0;
pbWorking.Minimum = 0;
pbClosed.Minimum = 0;

pbOpen.Maximum = n_max;
pbWorking.Maximum = n_max;
pbClosed.Maximum = n_max;

pbOpen.Value = n_open > n_max ? n_max : n_open;
pbWorking.Value = n_working > n_max ? n_max : n_working;
pbClosed.Value = n_closed > n_max ? n_max : n_closed;
}
}
}

下面是设计器形成的,ChartPanel的设计代码,一并留下
namespace IssueVision.UserControls


{
partial class ChartPanel

{

/**//// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;


/**//// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)

{
if (disposing && (components != null))

{
components.Dispose();
}
base.Dispose(disposing);
}


组件设计器生成的代码#region 组件设计器生成的代码


/**//// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()

{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChartPanel));
this.pnlTop = new System.Windows.Forms.Panel();
this.lbTitle = new System.Windows.Forms.Label();
this.lblOpen = new System.Windows.Forms.Label();
this.lblWorking = new System.Windows.Forms.Label();
this.lblclosed = new System.Windows.Forms.Label();
this.pbOpen = new System.Windows.Forms.ProgressBar();
this.pbWorking = new System.Windows.Forms.ProgressBar();
this.pbClosed = new System.Windows.Forms.ProgressBar();
this.pnlTop.SuspendLayout();
this.SuspendLayout();
//
// pnlTop
//
this.pnlTop.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pnlTop.BackgroundImage")));
this.pnlTop.Controls.Add(this.lbTitle);
this.pnlTop.Dock = System.Windows.Forms.DockStyle.Top;
this.pnlTop.Location = new System.Drawing.Point(0, 0);
this.pnlTop.Name = "pnlTop";
this.pnlTop.Size = new System.Drawing.Size(205, 16);
this.pnlTop.TabIndex = 0;
//
// lbTitle
//
this.lbTitle.AutoSize = true;
this.lbTitle.BackColor = System.Drawing.Color.Transparent;
this.lbTitle.Dock = System.Windows.Forms.DockStyle.Fill;
this.lbTitle.Location = new System.Drawing.Point(0, 0);
this.lbTitle.Name = "lbTitle";
this.lbTitle.Size = new System.Drawing.Size(77, 12);
this.lbTitle.TabIndex = 0;
this.lbTitle.Text = "标题标题标题";
this.lbTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// lblOpen
//
this.lblOpen.AutoSize = true;
this.lblOpen.Location = new System.Drawing.Point(9, 39);
this.lblOpen.Name = "lblOpen";
this.lblOpen.Size = new System.Drawing.Size(29, 12);
this.lblOpen.TabIndex = 1;
this.lblOpen.Text = "打开";
//
// lblWorking
//
this.lblWorking.AutoSize = true;
this.lblWorking.Location = new System.Drawing.Point(9, 77);
this.lblWorking.Name = "lblWorking";
this.lblWorking.Size = new System.Drawing.Size(29, 12);
this.lblWorking.TabIndex = 2;
this.lblWorking.Text = "进行";
//
// lblclosed
//
this.lblclosed.AutoSize = true;
this.lblclosed.Location = new System.Drawing.Point(9, 112);
this.lblclosed.Name = "lblclosed";
this.lblclosed.Size = new System.Drawing.Size(29, 12);
this.lblclosed.TabIndex = 3;
this.lblclosed.Text = "关闭";
//
// pbOpen
//
this.pbOpen.Location = new System.Drawing.Point(44, 28);
this.pbOpen.Name = "pbOpen";
this.pbOpen.Size = new System.Drawing.Size(155, 23);
this.pbOpen.Step = 1;
this.pbOpen.TabIndex = 4;
//
// pbWorking
//
this.pbWorking.Location = new System.Drawing.Point(44, 66);
this.pbWorking.Name = "pbWorking";
this.pbWorking.Size = new System.Drawing.Size(155, 23);
this.pbWorking.TabIndex = 5;
//
// pbClosed
//
this.pbClosed.Location = new System.Drawing.Point(45, 101);
this.pbClosed.Name = "pbClosed";
this.pbClosed.Size = new System.Drawing.Size(154, 23);
this.pbClosed.TabIndex = 6;
//
// ChartPanel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.pbClosed);
this.Controls.Add(this.pbWorking);
this.Controls.Add(this.pbOpen);
this.Controls.Add(this.lblclosed);
this.Controls.Add(this.lblWorking);
this.Controls.Add(this.lblOpen);
this.Controls.Add(this.pnlTop);
this.Name = "ChartPanel";
this.Size = new System.Drawing.Size(205, 135);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.ChartPanel_Paint);
this.pnlTop.ResumeLayout(false);
this.pnlTop.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.Panel pnlTop;
private System.Windows.Forms.Label lbTitle;
private System.Windows.Forms.Label lblOpen;
private System.Windows.Forms.Label lblWorking;
private System.Windows.Forms.Label lblclosed;
private System.Windows.Forms.ProgressBar pbOpen;
private System.Windows.Forms.ProgressBar pbWorking;
private System.Windows.Forms.ProgressBar pbClosed;
}
}

新建一个窗体,放上刚才的用户控件 chartpanel1,放置 textbox2,3,4 ,放一个按钮。
public class SubjectImpl:ISubject //被观察者的实现

{
protected Hashtable _observerContaind = new Hashtable();

public void Register(IObserver anObserver)

{
_observerContaind.Add(anObserver,anObserver);
}

public void UnRegister(IObserver anObserver)

{
_observerContaind.Remove(anObserver);
}

public void NotifyObservers(ChartData n_data)

{
foreach (IObserver anObserver in _observerContaind.Keys)

{
anObserver.NotifyDataChange(n_data);
}
}
}

public class MyData :SubjectImpl

{
private ChartData _cd = new ChartData();

public ChartData CD

{
get

{
return _cd;
}
set

{
_cd = value;
base.NotifyObservers(_cd);
}
}

}

private void button1_Click(object sender, EventArgs e)

{
ChartData mycd=new ChartData();
mycd.open=Convert.ToInt16(textBox2.Text);
mycd.work=Convert.ToInt16(textBox3.Text);
mycd.close=Convert.ToInt16(textBox4.Text);
MyData md = new MyData();
md.Register(chartPanel1);
md.CD = mycd;

}

呼,终于完了,点此 button 后,chartpanel 将会更改,不过,这么做会不会太麻烦了?