我一直在网上寻找.NET中MVC框架设置的示例实现。我找到了许多示例,但它们似乎在某些方面存在不同。我有一本关于设计模式的书,其中描述了MVC起源于Smalltalk,所以我阅读了几篇关于该语言实现的讨论。接下来是我编写的一个示例项目,利用我收集到的正确实现,但我对其中的一些细节感到困惑。
我遇到的一个问题是对象构建的正确顺序。这是我Program.cs中的实现。
控制器: 我对我实现的控制器的唯一真正问题是,似乎可以在没有明确分配视图的情况下构建控制器。我可以完全忽略视图,但这意味着我将向控制器的函数传递参数来更新模型,这似乎完全错过了重点。
在这篇文章的结尾,我想说的是,我需要一些指导,告诉我我所做的是否代表了真正的MVC实现,并希望有人能够解决上述问题。非常感谢您的任何建议。
我遇到的一个问题是对象构建的正确顺序。这是我Program.cs中的实现。
Model mdl = new Model();
Controller ctrl = new Controller(mdl);
Application.Run(new Form1(ctrl, mdl));
视图: 我有几个问题不确定。首先,如果视图只是从模型中读取数据进行更新,但包含对其的引用,那么有什么阻止我从视图调用控制器对模型的调用?程序员应该忽略他们暴露给模型成员函数的事实吗?另一个想法是,通知视图模型已更新的事件是否会发送某种状态对象以供视图进行更新。
public interface IView
{
double TopSpeed { get; }
double ZeroTo60 { get; }
int VehicleID { get; }
string VehicleName { get; }
}
/// <summary>
/// Assume the form has the following controls
/// A button with a click event OnSaveClicked
/// A combobox with a selected index changed event OnSelectedIndexChanged
/// A textbox that displays the vehicles top speed named mTextTopSpeed
/// A textbox that displays the vehicles zero to 60 time named mTextZeroTo60
/// </summary>
public partial class Form1 : Form, IView
{
private IController mController;
private IModel mModel;
public Form1(IController controller, IModel model)
{
InitializeComponent();
mController = controller;
mController.SetListener(this);
mModel = model;
mModel.ModelChanged += new ModelUpdated(mModel_ModelChanged);
}
void mModel_ModelChanged(object sender, EventArgs e)
{
mTextTopSpeed.Text = mModel.TopSpeed.ToString();
mTextZeroTo60.Text = mModel.ZeroTo60.ToString();
}
public double TopSpeed { get { return Double.Parse(mTextTopSpeed.Text); } }
public double ZeroTo60 { get { return Double.Parse(mTextZeroTo60.Text); } }
public int VehicleID { get { return (int)mComboVehicles.SelectedValue; } }
public string VehicleName { get { return mComboVehicles.SelectedText; } }
#region Form Events
private void OnFormLoad(object sender, EventArgs e)
{
mComboVehicles.ValueMember = "Key";
mComboVehicles.DisplayMember = "Value";
mComboVehicles.DataSource = new BindingSource(mModel.VehicleList, null);
}
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
mController.OnSelectedVehicleChanged();
}
private void OnSaveClicked(object sender, EventArgs e)
{
mController.OnUpdateVehicle();
}
#endregion
}
控制器: 我对我实现的控制器的唯一真正问题是,似乎可以在没有明确分配视图的情况下构建控制器。我可以完全忽略视图,但这意味着我将向控制器的函数传递参数来更新模型,这似乎完全错过了重点。
public interface IController
{
void OnUpdateVehicle();
void OnSelectedVehicleChanged();
void SetListener(IView view);
}
class Controller : IController
{
private IModel mModel;
private IView mView = null;
public Controller(IModel model)
{
mModel = model;
}
public void OnUpdateVehicle()
{
if(mView == null)
return;
mModel.UpdateVehicle(mView.VehicleID, mView.TopSpeed, mView.ZeroTo60);
}
public void SetListener(IView view)
{
mView = view;
}
public void OnSelectedVehicleChanged()
{
if (mView == null)
return;
mModel.SelectVehicle(mView.VehicleID);
}
}
模型: 在我的表单中,我有一个下拉框,其中列出了我的伪数据库中提供的车辆列表。因此,我觉得我的表单实际上应该实现多个视图/模型。一个视图专门用于列出可能的车辆,并带有相应的控制器/模型,另一个视图用于显示所选车辆的信息,具有自己的控制器/模型。
public delegate void ModelUpdated(object sender, EventArgs e);
public interface IModel
{
event ModelUpdated ModelChanged;
void UpdateVehicle(int id, double topSpeed, double zeroTo60);
void SelectVehicle(int id);
double TopSpeed { get; }
double ZeroTo60 { get; }
IDictionary<int, string> VehicleList { get; }
}
// class for the sake of a pseudo database object
class Vehicle
{
public int ID { get; set; }
public string Name { get; set; }
public double TopSpeed { get; set; }
public double ZeroTo60 { get; set; }
public Vehicle(int id, string name, double topSpeed, double zeroTo60)
{
ID = id;
Name = name;
TopSpeed = topSpeed;
ZeroTo60 = zeroTo60;
}
}
class Model : IModel
{
private List<Vehicle> mVehicles = new List<Vehicle>()
{
new Vehicle(1, "Civic", 120.0, 5.0),
new Vehicle(2, "Batmobile", 9000.0, 1.0),
new Vehicle(3, "Tricycle", 5.0, 0.0)
};
private Vehicle mCurrentVehicle;
public Model()
{
mCurrentVehicle = mVehicles[0];
}
public event ModelUpdated ModelChanged;
public void OnModelChanged()
{
if (ModelChanged != null)
{
ModelChanged(this, new EventArgs());
}
}
public double TopSpeed { get { return mCurrentVehicle.TopSpeed; } }
public double ZeroTo60 { get { return mCurrentVehicle.ZeroTo60; } }
public IDictionary<int, string> VehicleList
{
get
{
Dictionary<int, string> vDict = new Dictionary<int, string>();
foreach (Vehicle v in mVehicles)
{
vDict.Add(v.ID, v.Name);
}
return vDict as IDictionary<int, string>;
}
}
#region Pseudo Database Calls
public void SelectVehicle(int id)
{
foreach (Vehicle v in mVehicles)
{
if (v.ID == id)
{
mCurrentVehicle = v;
OnModelChanged(); // send notification to registered views
break;
}
}
}
public void UpdateVehicle(int id, double topSpeed, double zeroTo60)
{
foreach (Vehicle v in mVehicles)
{
if (v.ID == id)
{
mCurrentVehicle.TopSpeed = topSpeed;
mCurrentVehicle.ZeroTo60 = zeroTo60;
OnModelChanged(); // send notification to registered views
break;
}
}
}
#endregion
}
在这篇文章的结尾,我想说的是,我需要一些指导,告诉我我所做的是否代表了真正的MVC实现,并希望有人能够解决上述问题。非常感谢您的任何建议。