Event Bubbling и MVP: ASP.NET - PullRequest
       25

Event Bubbling и MVP: ASP.NET

2 голосов
/ 13 января 2012

Я пытаюсь выучить MVP

Он использует веб-формы в ASP.NET. У меня есть два пользовательских элемента управления CurrentTimeView.ascx и MonthViewControl.ascx. CurrentTimeView отображает время. Существует текстовое поле для добавления дней в одном элементе управления. Вновь полученная дата называется «итоговой датой». При нажатии кнопки для добавления дней возникает событие «myBtnAddDaysClickedEvent».

В MonthViewControl есть метка, которая показывает месяц «результирующей даты». В настоящее время я устанавливаю пример значения для переменной «monthValueToPass» (поскольку я не знаю, как это сделать правильно). Как установить значение переменной monthValueToPass, чтобы оно соответствовало модели MVP?

string monthValueToPass = "TEST";
monthPresenter.SetMonth(monthValueToPass);

Ожидается создание MVP, который будет легко выполнять модульное тестирование и не нарушает архитектуру MVP.

Примечание. Хотя это простой пример, я ожидаю, что ответ масштабируется на привязку данных в элементе управления GridView с использованием MVP и механизмов проверки.

Примечание. Может ли представление быть полностью независимым от докладчика?

Примечание. Каждый пользовательский элемент управления имеет отдельные представления

Примечание. Может ли быть несколько представлений для одного докладчика (например, различные элементы управления для разных пользователей в зависимости от разрешения?)

РУКОВОДЯЩИЕ

  1. Presenter Model View - Руководство

- ПОЛНЫЙ КОД -

using System;
public interface ICurrentTimeView
{
    //Property of View
    DateTime CurrentTime 
    {
        set; 
    }
    //Method of View
    void AttachPresenter(CurrentTimePresenter presenter);
}

using System;
public interface IMonthView
{
    //Property of View
    string MonthName 
    {
        set; 
    }

    //Method of View
    //View interface knows the presenter
    void AttachPresenter(MonthPresenter presenter);     
}

using System;
public class CurrentTimePresenter 
{
    private ICurrentTimeView view;

    //Constructor for prsenter
    public CurrentTimePresenter(ICurrentTimeView inputView) 
    {
        if (inputView == null)
        {
            throw new ArgumentNullException("view may not be null");
        }
    }
    this.view = inputView;
}

//Method defined in Presenter
public void SetCurrentTime(bool isPostBack) 
{
    if (!isPostBack) 
    {
        view.CurrentTime = DateTime.Now;
    }
}

//Method defined in Presenter
public void AddDays(string daysUnparsed, bool isPageValid) 
{
    if (isPageValid) 
    {
        view.CurrentTime = DateTime.Now.AddDays(double.Parse(daysUnparsed));           
    }
}

using System;
public class MonthPresenter
{
    private IMonthView monthView;

    //Constructor for prsenter
    public MonthPresenter(IMonthView inputView)
    {
        if (inputView == null)
        {
           throw new ArgumentNullException("view may not be null");
        }
        this.monthView = inputView;
    }


    //Method defined in Presenter
    //How does presenter decides the required value.
    public void SetMonth(string monthValueInput) 
    {
       if (!String.IsNullOrEmpty(monthValueInput))
       {
          monthView.MonthName = monthValueInput;
       }
       else
       {

       }        
    }   
}

Контроль пользователя 1

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CurrentTimeView.ascx.cs" Inherits="Views_CurrentTimeView" %>

<asp:Label id="lblMessage" runat="server" /><br />
<asp:Label id="lblCurrentTime" runat="server" /><br />
<br />

<asp:TextBox id="txtNumberOfDays" runat="server" />
<asp:Button id="btnAddDays" Text="Add Days" runat="server" OnClick="btnAddDays_OnClick" ValidationGroup="AddDays" />

using System;
using System.Web.UI;
public partial class Views_CurrentTimeView : UserControl, ICurrentTimeView
{
   //1. User control has no method other than view defined method for attaching presenter
   //2. Properties has only set method

   private CurrentTimePresenter presenter;

   // Delegate 
   public delegate void OnAddDaysClickedDelegate(string strValue);

   // Event 
   public event OnAddDaysClickedDelegate myBtnAddDaysClickedEvent;

   //Provision for getting the presenter in User Control from aspx page.
   public void AttachPresenter(CurrentTimePresenter presenter)
   {
       if (presenter == null)
       {
         throw new ArgumentNullException("presenter may not be null");
       }
       this.presenter = presenter;
   }

   //Implement View's Property
   public DateTime CurrentTime
   {
      set
      {
        //During set of the property, set the control's value
        lblCurrentTime.Text = value.ToString();
      }
   }

   //Event Handler in User Control
   protected void btnAddDays_OnClick(object sender, EventArgs e)
   {
      if (presenter == null)
      {
         throw new FieldAccessException("presenter null");
      }

      //Ask presenter to do its functionality
      presenter.AddDays(txtNumberOfDays.Text, Page.IsValid);

      //Raise event
      if (myBtnAddDaysClickedEvent != null)
      {
        myBtnAddDaysClickedEvent(string.Empty);
      }
   }     
}

Контроль пользователя 2

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MonthViewControl.ascx.cs" Inherits="Views_MonthViewControl" %>

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Views_MonthViewControl : System.Web.UI.UserControl, IMonthView
{
   //1. User control has no method other than view defined method for attaching presenter
   //2. Properties has only set method

   private MonthPresenter presenter;

   //Provision for gettng the presenter in User Control from aspx page.
   public void AttachPresenter(MonthPresenter presenter)
   {
      if (presenter == null)
      {
         throw new ArgumentNullException("presenter may not be null");
      }
      this.presenter = presenter;
   }

   //Implement View's Property
   public string MonthName
   {
      set
      {
        //During set of the popert, set the control's value
        lblMonth.Text = value.ToString();
      }
   }

   protected void Page_Load(object sender, EventArgs e)
   {

   }    
}

ASPX Page

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ShowMeTheTime.aspx.cs"      Inherits="ShowTime" %>

<%@ Register TagPrefix="mvpProject" TagName="CurrentTimeView" Src="Views/CurrentTimeView.ascx" %>

<%@ Register TagPrefix="month" TagName="MonthView" Src="Views/MonthViewControl.ascx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>PAGE TITLE </title>
</head>
<body>
<form id="form1" runat="server">

    <mvpProject:CurrentTimeView id="ucCtrlcurrentTimeView" runat="server" 
    />
    <br />
    <br />
    <month:MonthView id="ucCtrlMonthView" runat="server" />

</form>
</body>
</html>

using System;
using System.Web.UI;

public partial class ShowTime : Page
{
    CurrentTimePresenter currentTimePresenter;
    MonthPresenter monthPresenter;

    protected void Page_Load(object sender, EventArgs e) 
    {
       HelperInitCurrentTimeView();
       HelperInitMonth();
    }

    private void HelperInitMonth()
    {
       //Create presenter
       monthPresenter = new MonthPresenter(ucCtrlMonthView);

       //Pass the presenter object to user control
       ucCtrlMonthView.AttachPresenter(monthPresenter);
    }

    private void HelperInitCurrentTimeView() 
    { 
       //Cretes presenter by passing view(user control) to presenter.
       //User control has implemented IView
       currentTimePresenter = new CurrentTimePresenter(ucCtrlcurrentTimeView);

        //Pass the presenter object to user control
        ucCtrlcurrentTimeView.AttachPresenter(currentTimePresenter);

        //Call the presenter action to load time in user control.
        currentTimePresenter.SetCurrentTime(Page.IsPostBack);

        //Event described in User Control ???? Subsribe for it.
        ucCtrlcurrentTimeView.myBtnAddDaysClickedEvent += new Views_CurrentTimeView.OnAddDaysClickedDelegate(CurrentTimeViewControl_AddButtonClicked_MainPageHandler);        
    }

    void CurrentTimeViewControl_AddButtonClicked_MainPageHandler(string strValue)
    {
       string monthValue = "l";
       monthPresenter.SetMonth("SAMPLE VALUE");
       //myGridCntrl.CurentCharacter = theLetterCtrl.SelectedLetter;
       //myGridCntrl.LoadGridValues();
    }
}

Некоторые обсуждения MVP:

Presenter Model View - Руководство

В MVP, куда писать валидации

MVP - Должны ли представления вызывать методы презентатора напрямую или всегда вызывать события?

События MVP или свойство

Модель в MVP - События

MVP - должен ли докладчик использовать сеанс?

Почему докладчики присоединяются к событиям View, а не View, вызывая методы Presenter в большинстве реализаций ASP.NET MVP?

Публичные методы или подписка на просмотр событий

Шаблон MVP, сколько просмотров докладчику?

MVP и UserControls и вызов

ASP.NET Web Forms - модель представления Presenter и пользовательские элементы управления управление

Ограничить нарушение архитектуры - asp.net MVP

Управление модификацией в уровне представления

Разделение представления, представления и веб-форм ASP.NET веб-форма

Ответы [ 3 ]

2 голосов
/ 23 января 2012

Спасибо за вклад.Я передал MVP Quickstarts http://msdn.microsoft.com/en-us/library/ff650240.aspx. Model can raise events.Я думаю, я должен пойти с этим подходом.Любые мысли приветствуются.

Кроме того, я опубликовал http://forums.asp.net/t/1760921.aspx/1?Model+View+Presenter+Guidelines, чтобы собрать общие правила для MVP.

Цитата

Разработка Presenter, которая может взаимодействовать как с View, так и с Model.Ведущий может знать только интерфейс просмотра.Даже если конкретное представление изменяется, оно не влияет на докладчика.

В конкретном представлении обработчики событий элемента управления будут просто вызывать методы докладчика или вызывать события, на которые докладчик подписался бы.Не должно быть никакого правила / логики представления, написанного в конкретном представлении.

Представитель должен иметь только интерфейсный объект модели;не конкретная модель.Это для удобства модульного тестирования

Просмотр может ссылаться на бизнес-объекты.Однако не должно быть написанной логики, связанной с объектами сущности.Он может просто передать объект сущности предъявителю.

Интерфейс представления должен быть абстракцией.Он не должен иметь никакого контроля или ссылки System.Web.В конкретном представлении не должно быть никакого метода, кроме методов, определяемых интерфейсом.

«Модель» никогда не знает о конкретном представлении, а также о представлении интерфейса.События.Presenter может подписаться на эти события, вызываемые моделью.

Публичные методы в Presenter должны быть без параметров.Просмотр объекта должен иметь доступ только к беспараметрическим методам презентатора.Другой вариант - представление может определять события, на которые может подписаться докладчик.В любом случае, не должно быть передачи параметров.

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

View может использовать модель напрямую (без использования Presenter).Например, ObjectDataSource's SelectMethod.Но контроллер никогда не знает ни о конкретном представлении, ни о представлении интерфейса.

Презентатор ссылается на интерфейс представления вместо конкретной реализации представления.Это позволяет вам заменить фактический вид на макет при запуске модульных тестов.

2 голосов
/ 16 января 2012

TLDR код.

Вот как бы я это сделал.Вы говорите, что на одной странице есть 2 элемента управления.Так что это может обслуживаться ContainerVM со ссылками (членами) TimeVM и MonthVM.

  1. TimeVM обновляет вспомогательное свойство ResultantDate всякий раз, когда вы делаете свою вещь.измененные уведомления для TimeVM.ResultantDate.Всякий раз, когда он получает уведомление об изменении, он вызывает MonthVM.SetMonth ()

Теперь это можно проверить без использования каких-либо представлений - только на уровне докладчика.

1 голос
/ 17 января 2012

У меня нет опыта работы с ASP.net, но я думаю, что понимаю суть того, что вы пытаетесь сделать.

Похоже, что вы снижаете уровень до своего докладчика, делая докладчиков для отдельных элементов пользовательского интерфейса.В этом случае Месяц и Время.Я бы подумал об этом больше как период ShowTime.ShowTime имеет возможность отображения месяца и времени.

Для использования с MVP.Тогда вам понадобится IShowTimeView, который будет реализован на странице.(Не контролирует).А затем напишите ShowTimePresenter, который использует IShowTimeView для отправки и получения значений.

У вас будет ShowTime для реализации интерфейса IShowTimeView.Он будет перенаправлять такие элементы, как время, события AddDay и месяц, к фактическим элементам управления на странице и обратно.

Так что, если я понимаю вашу рецензию.Последовательность событий будет выглядеть примерно так:

Пользователь вводит дни, которые нужно добавить.Пользователь нажимает кнопку добавления дней. Добавить дни запускает событие, которое вызывает метод для добавления дней.Метод в презентаторе, который добавляет дни, сделает его расчет и другие необходимые шаги.Затем метод добавления дней будет использовать указатель представления в Presenter, чтобы сообщить представлению обновить месяц с вычисленным значением.Затем представление примет вычисленное значение, установив правильное свойство в элементе управления.

Чтобы выполнить модульное тестирование, необходимо создать фиктивный объект, реализующий IShowTimeView, и использовать его вместо реального объекта страницы.

...