Как правильно реализовать MVC с использованием C # .NET в приложениях Windows Forms

Я искал в Интернете, например, реализации настройки MVC в .NET. Я нашел много примеров, но все они, кажется, отличаются в определенных аспектах. У меня есть книга по шаблонам проектирования, в которой описано, что MVC зародился на Smalltalk, поэтому я прочитал несколько человек, обсуждающих его реализацию на этом языке. Ниже приводится пример проекта, который я написал, используя то, что я собрал, было правильной реализацией, но меня сбили с толку некоторые детали.

Одна проблема, с которой я столкнулся, - это правильный порядок построения объектов. Вот пример в моем Program.cs

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

The 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
}

Контроллер: Моя единственная реальная проблема с тем, как я реализовал контроллер, заключается в том, что мне кажется немного странным, что можно сконструировать контроллер, не имея определенного представления, назначенного ему. Я мог бы полностью игнорировать представление, но это означало бы, что я передал бы параметры функциям контроллера для обновления модели, которая, кажется, полностью упускает суть.

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
}

В заключение этого tl; dr, я предполагаю, что я ищу ибо это некоторые рекомендации относительно того, представляет ли то, что я здесь делаю, истинную реализацию MVC и, возможно, для кого-то, чтобы пролить свет на вышеупомянутые проблемы. Будем признательны за любые советы.

8
задан geek_factorial 15 July 2011 в 19:17
поделиться