gpt4 book ai didi

c# - 如何在 Windows 窗体应用程序中使用 C#.NET 正确实现 MVC

转载 作者:太空狗 更新时间:2023-10-29 19:41:45 25 4
gpt4 key购买 nike

我一直在网上寻找 .NET 中 MVC 设置的示例实现。我找到了很多例子,但它们在某些方面似乎都不同。我有一本关于设计模式的书,它描述了 MVC 起源于 Smalltalk,所以我读了几个人讨论它在该语言中的实现。下面是我编写的一个示例项目,利用我收集到的内容是一个正确的实现,但我对一些细节感到困惑。

我遇到的一个问题是构建对象的正确顺序。这是我的 Program.cs 中的实现

Model mdl = new Model();
Controller ctrl = new Controller(mdl);
Application.Run(new Form1(ctrl, mdl));

观点:我立即有几个不确定的问题。首先,如果 View 应该只从模型中读取数据进行更新,但包含对它的引用,那么是什么阻止我从视​​图中调用 Controller 对模型所做的调用?程序员是否应该忽略他们暴露于模型成员函数的事实?我的另一个想法是,通知 View 模型更新的事件可能会发送某种状态对象,以便 View 使用它来更新自身。

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
}

Controller :我实现 Controller 的方式的唯一真正问题是,在没有明确分配 View 的情况下构建 Controller 对我来说似乎有点奇怪。我可以完全忽略 View ,但这意味着我会将参数传递给 Controller ​​的函数以更新模型,这似乎完全忽略了要点。

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);
}
}

模型:在我的表单中,我有一个组合框,它是我的伪数据库中给出的车辆列表。因此,我觉得我的表单实际上应该实现多个 View /模型。一个特定于列出具有相应 Controller /模型的可能车辆的 View ,以及一个用于显示有关具有自己的 Controller /模型的所选车辆的信息的 View 。

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
}

在此 tl;dr 的结论中,我想我正在寻找的是关于我在这里所做的是否代表真正的 MVC 实现的一些指导,也许有人可以阐明上述问题.任何建议将不胜感激。

最佳答案

我们会根据你想做什么来决定。您目前有一个监督 Controller 的实现。如果您希望从 View (和任何数据绑定(bind))中删除模型,您可以改为实现被动 View 模式。参见 this有关更多差异的文章。

Passive View and Supervising Controller
(来源:microsoft.com)

Martin Fowler 是国王(GUI Architectures)。

关于c# - 如何在 Windows 窗体应用程序中使用 C#.NET 正确实现 MVC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6712099/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com