2010-05-03 3 views
3

Я изучаю применение MVP к простому приложению WinForms (только одна форма) на C# и столкнулся с проблемой при создании главного ведущего в static void Main(). Является ли хорошей идеей выставить представление из презентатора, чтобы предоставить его в качестве параметра Application.Run()?Как вызывать Application.Run() для основного ведущего приложения MVP WinForms?

В настоящее время я реализовал подход, который позволяет мне не подвергать View как свойство Выступающий:

static void Main() 
    { 
     IView view = new View(); 
     Model model = new Model(); 
     Presenter presenter = new Presenter(view, model); 
     presenter.Start(); 
     Application.Run(); 
    } 

пуска и останова методы в Выступающий:

public void Start() 
    { 
     view.Start(); 
    } 

    public void Stop() 
    { 
     view.Stop(); 
    } 

The Start и Stop в представлении (форма Windows):

public void Start() 
    { 
     this.Show(); 
    } 

    public void Stop() 
    { 
     // only way to close a message loop called 
     // via Application.Run(); without a Form parameter 
     Application.Exit(); 
    } 

Вызов Application.Exit() кажется неэлегантным способом закрыть форму (и приложение). Другой альтернативой было бы разоблачить представление как общедоступное свойство Ведущего, чтобы вызвать Application.Run() с параметром Form.

static void Main() 
    { 
     IView view = new View(); 
     Model model = new Model(); 
     Presenter presenter = new Presenter(view, model); 
     Application.Run(presenter.View); 
    } 

Методы «Пуск» и «Стоп» в Presenter остаются неизменными. Дополнительное свойство добавлено вернуть вид как форма:

public void Start() 
    { 
     view.Start(); 
    } 

    public void Stop() 
    { 
     view.Stop(); 
    } 

    // New property to return view as a Form for Application.Run(Form form); 
    public System.Windows.Form View 
    { 
     get { return view as Form(); } 
    } 

пуска и останова методы View (в форме Windows) затем записывается, как показано ниже:

public void Start() 
    { 
     this.Show(); 
    } 

    public void Stop() 
    { 
     this.Close(); 
    } 

Может кто-нибудь предложить, какие лучший подход и почему? Или есть еще лучшие способы решения этой проблемы?

+0

Я благодарю Роджер, Heinzi и Николь за их ценный вклад, но я выбрал ответ Heinzi, наконец, потому, что я приспособил его ответ для моего фактического применения с использованием двух дополнительных интерфейсов IMainPresenter и IMainView. – anonymous

ответ

9

Что можно сказать о следующем:

// view 
public void StartApplication() // implements IView.StartApplication 
{ 
    Application.Run((Form)this); 
} 

// presenter 
public void StartApplication() 
{ 
    view.StartApplication(); 
} 

// main 
static void Main()  
{  
    IView view = new View();  
    Model model = new Model();  
    Presenter presenter = new Presenter(view, model);  
    presenter.StartApplication();  
}  

Таким образом, вам не нужно подвергать вид снаружи. Кроме того, представление и ведущий знают, что это представление было начато как «основная форма», что может быть полезной информацией.

+1

IMO. Ни один из презентаторов или интерфейсов представления не должен знать, как запускать насос сообщений Windows. Вы только раздуваете интерфейс IView с помощью метода, который не должен существовать, который вам нужно будет реализовать, если вы пишете тесты против поддельных представлений. –

+1

Создал бы другой интерфейс для представления и презентатора, например IMainView, IMainPresenter, чтобы специально обрабатывать только StartApplication() и StopApplication(). Таким образом, View будет реализовывать Iview и IMainView, Presenter будет реализовывать IMainPresenter. – anonymous

+1

@Mr Roys: Это хорошая идея. Вы даже можете создавать подинтерфейсы IMainView и IMainPresenter для IView и IPresenter, так как IMainView всегда будет IView (тот же для Presenter). – Heinzi

5

Я бы пошел на второй подход. Вы также можете избавиться от дополнительной собственности, просто нарисуя вид, чтобы сформировать в void Main, так как вы знаете, что это форма в любом случае в этот момент (я не вижу причин, чтобы сделать его более общим, чем это, поскольку он только начинает winform приложение)

Application.Run(view as Form); 
1

Все становится немного сложнее, если вы разрешаете несколько способов выхода из приложения (например, пункт меню для выхода) или если вы не закрываете приложение при определенных условиях. В любом случае фактический вызов закрытия приложения обычно должен вызываться из кода презентатора, а не просто закрывать конкретный вид. Это может быть достигнуто с использованием перегрузок Application.Run() или Application.Run (ApplicationContext) и отображения действия выхода приложения с помощью инверсии элемента управления.

Точный подход к регистрации и использованию действия выхода приложения будет зависеть от механизма IoC (например, локатора сервисов и/или зависимостей), который вы используете.Так как вы не упомянули, что может быть ваш текущий IoC подход, вот пример, это не зависит от каких-либо конкретных рамок IoC:

internal static class Program 
{ 
    [STAThread] 
    private static void Main() 
    { 
     ApplicationActions.ExitApplication = Application.Exit; 

     MainPresenter mainPresenter = new MainPresenter(new MainView(), new Model()); 
     mainPresenter.Start(); 

     Application.Run(); 
    } 
} 

public static class ApplicationActions 
{ 
    public static Action ExitApplication { get; internal set; } 
} 

public class MainPresenter : Presenter 
{ 
    //... 

    public override void Stop() 
    { 
     base.Stop(); 

     ApplicationActions.ExitApplication(); 
    } 
} 

Этот базовый подход может быть адаптирован достаточно легко предпочитаемого IoC подход. Например, если вы используете локатор сервисов, вы, вероятно, захотите рассмотреть удаление хотя бы сеттера в свойстве ApplicationActions.ExitApplication и вместо этого сохраните делегат в локаторе службы. Если геттер ExitApplication должен был остаться, это обеспечило бы простой фасад ретривера экземпляра сервиса локатора. например .:

public static Action ExitApplication 
{ 
    get 
    { 
     return ServiceLocator.GetInstance<Action>("ExitApplication"); 
    } 
} 
+0

Первоначально я намеревался разместить Application.Exit() в presenter.Stop(), но затем решил против него, потому что это создало бы зависимость от технологии, используемой для реализации представления, например WinForms в презентаторе. Я посмотрю в IoC тем временем - каким-либо образом проиллюстрировать его каким-то псевдокодом? – anonymous

+0

Для каких частей реализации вы хотели бы привести пример? –

+0

Часть IoC для раздела Application.Exit() будет приятной. Благодаря! – anonymous