Как связать одно представление с несколькими действиями в mvc5?

#c# #asp.net-mvc-5

#c# #asp.net-mvc-5

Вопрос:

Привет, я создаю панель мониторинга для своего приложения. Он содержит несколько действий в контроллере. Я хочу связать одно представление с несколькими действиями, потому что я хочу отображать другой тип результата в представлении. Но моделируйте в одной модели.Эта же модель используется для каждого действия.

Моя модель (ViewModel типа Customer)

 public class CustomerTypeViewModel
{
    public System.Guid CustomerID { get; set; }
    public string CustomerName { get; set; }
    public DateTime CreatedDate { get; set; }
    public string SalesCount { get; set; }
    public string CustomerType { get; set; }

    public List<View_VisitorsForm> Visits { get; set; }
}
}
  

Мой контроллер (здесь есть два действия)

Здесь я создал два действия, и эти два действия выполняют разные вычисления, и модель для этих двух действий одинакова (то есть CustomerTypeViewModel), а также эти два действия перенаправляются на одно и то же представление.

    public ActionResult Dashboard()
    {
        List<Customer> n = (from c in db.Customers where c.IsDeleted == false select c).ToList();
        var customertype = string.Empty;
        List<CustomerTypeViewModel> obj = new List<CustomerTypeViewModel>();
        for (var i = 0; i < n.Count; i  )
        {
            var objCustomerName = n[i].DisplayName;
            var objCustomerID = n[i].CustomerID;
            var objCusCreatedDate = n[i].CreatedDate;
            var objNextDate = objCusCreatedDate.GetValueOrDefault().AddDays(120);
            var ObjTodayDate = DateTime.Now.Date;
            var salescount = (from sc in db.SalesOrders where sc.CustomerID == objCustomerID amp;amp; sc.CreatedDate >= objCusCreatedDate amp;amp; sc.CreatedDate <= objNextDate select sc.SalesOrderID).Count();
            var ordercount = (from oc in db.SalesOrders where oc.CustomerID == objCustomerID amp;amp; oc.CreatedDate >= objCusCreatedDate amp;amp; oc.CreatedDate <= ObjTodayDate select oc.SalesOrderID).Count();
            if (ordercount >= 3)
            {
                customertype = "Existing Customer";
            }
            else if (ordercount == 0 amp;amp; ordercount <= 0)
            {
                customertype = "New Customer";
            }
            else if (ordercount <= 2 amp;amp; ordercount >= 1)
            {
                customertype = "Potential Customer";
            }
            obj.Add(new CustomerTypeViewModel()
            {
                CustomerName = objCustomerName,
                CustomerType = customertype,
                SalesCount = ordercount.ToString()
            });
        }
        return View("Dashboard",obj);
    }
    public ActionResult NextFollowup()
    {
        var userID = System.Web.HttpContext.Current.Session["UserID"].ToString();
        var objEmpDepUTID = db.UserRightsSettings.Where(u => u.UserID.ToString() == userID).Select(e => new
        {
            objemployeeID = e.EmployeeID,
            objdepartmentID = e.DepartmentID,
            objusertypeID = e.UserTypeID
        }).FirstOrDefault();

        var EmployeeID = objEmpDepUTID.objemployeeID;
        var DepartmentID = objEmpDepUTID.objdepartmentID;
        var UserTypeID = objEmpDepUTID.objusertypeID;
        var TodayDate = DateTime.Now.Date;

        List<View_VisitorsForm> objVisitorsList = new List<View_VisitorsForm>();
        if (DepartmentID == new Guid("47D2C992-1CB6-44AA-91CA-6AA3C338447E") amp;amp;
           (UserTypeID == new Guid("106D02CC-7DC2-42BF-AC6F-D683ADDC1824") ||
           (UserTypeID == new Guid("B3728982-0016-4562-BF73-E9B8B99BD501"))))
        {
            objVisitorsList = db.View_VisitorsForm.Where(X => X.NextAppointment == TodayDate).ToList();
        }
        else
        {
            objVisitorsList = db.View_VisitorsForm.Where(x => x.NextAppointment == TodayDate amp;amp; x.EmployeeID == EmployeeID).ToList();
        }
        CustomerTypeViewModel objvvm = new CustomerTypeViewModel();
        objvvm.Visits = objVisitorsList;
        return View("Dashboard",objvvm);
    }
  

Мой взгляд

В этом представлении я дал модель так, как это означает, что она показывает ошибку

    @model CostToWafe.Areas.Sales.Models.CustomerTypeViewModel
   @using CostToWafe.Areas.Sales.Models
  

Он показывает ошибку, близкую к

  @Model.Select(x => x.CustomerName).Count()
  

если я дам имя модели с помощью IEnumerable, например

    @model IEnumerable<CostToWafe.Areas.Sales.Models.CustomerTypeViewModel>
   @using CostToWafe.Areas.Sales.Models
  

он показывает ошибку рядом с таблицей (Model.Visits), которая

          @foreach (View_VisitorsForm item in Model.Visits)
  

Мой полный вид

 @model CostToWafe.Areas.Sales.Models.CustomerTypeViewModel
@using CostToWafe.Areas.Sales.Models
@{
ViewBag.Title = "Dashboard";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container body">
<div class="main_container">
  <div class="right_col" role="main">
        <!-- top tiles -->
   <div class="row tile_count">

   <div class="right">
   <span class="count_top"><i class="fa fa-user"></i> Total Customer</span>
   <div class="count">@Model.Select(x => x.CustomerName).Count()</div>
   </div>

  <div class="right">
  <span class="count_top"><i class="fa fa-user"></i> Existing Customer</span>
  <div class="count">@Model.Where(x => x.CustomerType == "Existing Customer").Count()</div>
  </div>

  <div class="row">
  <table>
  <thead>
         <tr>
                <th>Employee </th>
                <th>Customer Name</th>
                <th>Purpose of Visit</th>
         </tr>
  <thead>
 <tbody>
          @foreach (View_VisitorsForm item in Model.Visits)
          {
          <tr>
               <td>@item.Employee;</td>
               <td>@item.CustomerName;</td>
               <td>@item.POVisit;</td>
          </tr>
          }
 <tbody>
 </table>
  </div>
  </div>
  </div>
  </div>
  </div>
  

Мой вопрос немного длинный.Я изо всех сил старался объяснить эту проблему. Кто-нибудь понимает мой вопрос и помогает мне решить эту проблему.

Спасибо..

Комментарии:

1. чего вы на самом деле пытаетесь достичь? @Model.Select(x => x.CustomerName).Count() не имеет смысла, CustomerName — это строка, вы не можете ее посчитать. И если вы сделаете модель своего представления списком, вы не сможете перебирать посетителей, не выбирая, из каких элементов модели вы хотите получать посетителей (т.Е. Model.Visits больше не существует, потому что Model — это список, вам понадобится цикл foreach для элементов в Model)

2. Кроме того, превращение модели представления в список не имеет смысла, потому что оба ваших действия возвращают ему только один объект, а не список

3. @ADyson Смотрите это изображение . Прежде чем я создал отдельный контроллер и отдельный вид, и в соответствии с этим количеством я вывожу вывод [![Count][1]][1] [1]: i.stack.imgur.com/LNNIq.jpg

4. извините, я не понимаю, насколько это актуально? Вы показываете мне вывод из того же представления, что и в вашем примере кода? И что такое [![Count][1]][1] [1] — я не узнаю этот синтаксис?

5. в вашем представлении отображаются сведения об одном клиенте. Если вы хотите что-то, что показывает количество множества клиентов, то я думаю, вам нужен отдельный запрос к базе данных, чтобы подсчитать их и поместить результат в виде элемента данных в ViewBag, который вы можете использовать на странице, отдельно от модели. Или, если эти данные будут заголовком на множестве экранов, реализуйте их как частичное представление, которое затем можно использовать на многих страницах.

Ответ №1:

На основе комментариев и предоставленного скриншота (https://i.stack.imgur.com/DomTM.jpg ) Думаю, теперь я понимаю, чего вы хотите достичь.

Проблема в том, что ваш подход имеет ряд логических недостатков.

1) Модель вашего представления определена как CostToWafe.Areas.Sales.Models.CustomerTypeViewMo‌​del , но ваше Dashboard действие пытается предоставить a IEnumerable<CostToWafe.Areas.Sales.Models.CustomerTypeViewMo‌​del> в качестве модели. Эти два типа несовместимы.

2) В вопросе вы спросили о том, можете ли вы использовать несколько действий с одним представлением. Ответ на этот вопрос — да (при условии, что они оба предоставляют правильный тип модели). Однако вы не можете вызвать два действия в одном и том же представлении одновременно (т. Е. Во время одного и того же запроса). Исходя из ваших требований, похоже, вы хотите, чтобы данные, возвращаемые методами Dashboard and NextFollowUp и Action, были видны в одном представлении одновременно. Это невозможно при использовании двух методов действия. Вы бы использовали несколько методов действий, только если бы хотели, чтобы представление имело разное содержимое в разное время.

3) В CustomerTypeViewMo‌​del классе, который вы определили List<View_VisitorsForm> Visits как свойство класса. Это означает, что список посещений каким-то образом связан с конкретным CustomerType , т. Е. посещениями, содержащимися в этом списке в любом экземпляре CustomerTypeViewMo‌​del , будут те, которые относятся только к CustomerType, представленному этим экземпляром. Теперь из требований ясно, что это не так. Вместо этого данные, содержащиеся в списке посещений, определяются не типом клиента, а тем, кто является текущим пользователем системы. Поэтому создание этого списка свойством CustomerType является нелогичной ассоциацией, которая вызвала некоторую путаницу.

4) В коде представления, потому что @model ошибочно определен как единственный экземпляр CustomerTypeViewMo‌​del вместо IEnumerable<CustomerTypeViewMo‌​del> . Несмотря на это, вы пытались как-то подсчитать количество объектов в списке с помощью @Model.Select(x => x.CustomerName).Count() . Это не работает, потому что представление не считает @Model a IEnumerable<T> , поэтому вы не можете выполнить a Select для него.

5) CustomerTypeViewModel Класс также, по-видимому, является скорее представлением клиента, чем типом клиента — он содержит такие поля, как имя клиента и количество продаж, которые даже не нужны для этого представления. Итак, это еще одна логическая проблема. Если вызывается ViewModel CustomerType , то он должен полностью представлять тип клиента, а не клиента, и не должен содержать несвязанных полей.

Учитывая все это, ваш дизайн нуждается в полном переосмыслении. Вам нужен объект ViewModel более высокого уровня, который будет включать в себя как список CustomerTypes, так и список посещений. Затем это можно вернуть в представление, и вы можете

а) перебрать список пользовательских типов для отображения всей статистики

б) просмотрите список посещений, чтобы отобразить всех посетителей.

Поэтому Dashboard действие создаст этот DashboardViewModel объект и вернет его в представление. NextFollowUp Действие больше не требуется и может быть удалено.

Код должен выглядеть примерно следующим образом. Я не тестировал его, поэтому приношу извинения, если есть какие-либо синтаксические ошибки или похожие.

Модель представления

 //This no longer includes Visits, because they aren't specific to a CustomerType
public class CustomerType
{
  public string CustomerTypeDescription { get; set; }
  public int CustomerCount { get; set; }
}

//This is now the ViewModel used by the View:
public class DashboardViewModel
{
   public List<CustomerType> CustomerTypes { get; set; }
   public List<View_VisitorsForm> Visits { get; set; }
}
  

Метод действия

 public ActionResult Dashboard()
{
    //first work out the customer type statistics
    List<Customer> customers = (from c in db.Customers where c.IsDeleted == false select c).ToList();

    CustomerType allCustomers = new CustomerType();
    allCustomers.CustomerTypeDescription = "Total Customers";
    allCustomers.CustomerCount = customers.Count;

    CustomerType existingCustomers = new CustomerType();
    existingCustomers.CustomerTypeDescription = "Existing Customers";

    CustomerType potentialCustomers = new CustomerType();
    potentialCustomers.CustomerTypeDescription = "Potential Customers";

    CustomerType newCustomers = new CustomerType();
    newCustomers.CustomerTypeDescription = "New Customers";


    foreach (Customer cus in customers)
    {
        var ordercount = (from oc in db.SalesOrders where oc.CustomerID == cus.CustomerID amp;amp; oc.CreatedDate >= cus.CreatedDate amp;amp; oc.CreatedDate <= DateTime.Now.Date select oc.SalesOrderID).Count();

        if (ordercount >= 3)
        {
          existingCustomers.CustomerCount  ;
        }
        else if (ordercount == 2 || ordercount == 1)
        {
          potentialCustomers.CustomerCount  ;
        }
        else if (ordercount <= 0)
        {
          newCustomers.CustomerCount  ;
        }
    }

    //now get the list of visits
    var userID = System.Web.HttpContext.Current.Session["UserID"].ToString();
    var currentUser = db.UserRightsSettings.Where(u => u.UserID.ToString() == userID).Select(e => new
    {
        employeeID = e.EmployeeID,
        departmentID = e.DepartmentID,
        usertypeID = e.UserTypeID
    }).FirstOrDefault();

    List<View_VisitorsForm> visitList = new List<View_VisitorsForm>();
    if (currentUser.departmentID == new Guid("47D2C992-1CB6-44AA-91CA-6AA3C338447E") amp;amp;
       (currentUser.usertypeID == new Guid("106D02CC-7DC2-42BF-AC6F-D683ADDC1824") ||
       (currentUser.usertypeID == new Guid("B3728982-0016-4562-BF73-E9B8B99BD501")))
    {
        visitList = db.View_VisitorsForm.Where(X => X.NextAppointment == DateTime.Now.Date).ToList();
    }
    else
    {
        visitList = db.View_VisitorsForm.Where(x => x.NextAppointment == DateTime.Now.Date amp;amp; x.EmployeeID == currentUser.employeeID).ToList();
    }

    //finally bring it all together to create the ViewModel
    DashboardViewModel vm = new DashboardViewModel();
    vm.CustomerTypes = new List<CustomerType>();
    vm.CustomerTypes.Add(allCustomers);
    vm.CustomerTypes.Add(existingCustomers);
    vm.CustomerTypes.Add(potentialCustomers);
    vm.CustomerTypes.Add(newCustomers);
    vm.Visits = visitList;

    return View("Dashboard", vm);
}
  

Вид

 @model CostToWafe.Areas.Sales.Models.DashboardViewModel
@using CostToWafe.Areas.Sales.Models
@{
  ViewBag.Title = "Dashboard";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div class="container body">
  <div class="main_container">
    <div class="right_col" role="main">
      <!-- top tiles -->
      <div class="row tile_count">
      @foreach (CustomerType cusType in Model.CustomerTypes)
      {
        <div class="right">
         <span class="count_top"><i class="fa fa-user"></i>@cusType.CustomerTypeDescription</span>
         <div class="count">@cusType.CustomerCount</div>
        </div>
      }
      </div>

      <div class="row">
        <table>
          <thead>
            <tr>
              <th>Employee </th>
              <th>Customer Name</th>
              <th>Purpose of Visit</th>
            </tr>
          </thead>
          <tbody>
          @foreach (View_VisitorsForm visit in Model.Visits)
          {
            <tr>
              <td>@visit.Employee;</td>
              <td>@visit.CustomerName;</td>
              <td>@visit.POVisit;</td>
            </tr>
          }
          </tbody>
        </table>
      </div>
    </div>
  </div>
</div>
  

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

Некоторые другие краткие комментарии к вашему коду:

  • у вас там были некоторые избыточные переменные (в частности, var salescount ). Не оставляйте код, который не используется, — это все запутывает.

  • был какой-то неправильный html (например, у вас было <thead> дважды: <thead>... instead of closing the tag properly: …`.

  • Код был более подробным, чем должен был быть. Например, все объявления EmployeeID , DepartmentID, которые затем использовались только один раз. Они были прямым отображением из более ранней переменной, поэтому просто используйте это вместо этого.

  • используйте значимые имена переменных, которые можно понять по всему коду, не возвращаясь к определению (например, используйте List<Customer> customers для списка клиентов вместо List<Customer> n , и не вызывайте ничего простого obj — нет никаких шансов узнать, что это такое.

  • C # — это строго типизированный язык, поэтому вам не обязательно использовать венгерскую нотацию для префикса имен переменных (т. Е. objEmpDepUTID objVisitorsList ). В любом случае вы также obj неправильно использовали префикс во многих местах, когда тип переменной на самом деле был примитивом, таким как string или int, а вовсе не объектом. Мнения об использовании этого различаются, но в целом я нахожу, что это просто загромождает код и не передает никакой информации, которую нельзя было бы увидеть, прочитав остальную часть кода (или используя Intellisense в Visual Studio).

Примечание. Из скриншота видно, что в представлении есть и другое содержимое (использование устройства, быстрые настройки и т. Д.), Но вы не предоставили подробную информацию об этом, Поэтому я предполагаю, что вы добавите их в ViewModel позже.

Комментарии:

1. Adyson я получаю сообщение об ошибке. Сначала я попробовал ваш код, я попробовал первое действие, которое само подсчитывает количество заказов, поскольку я получаю ошибку object reference is null рядом с @forEach(cus в CustmoerType)

2. без возможности тестирования мне трудно сказать точно, но я внес небольшую правку, добавив строку vm.CustomerTypes = new List<CustomerType>(); в метод действия ближе к концу, на случай, если список не инициализируется должным образом. Посмотрите, поможет ли это.

3. Да, он показывает ошибку рядом с Dashboardviewmodel. Теперь я изменил, как вы сказали, и проверил и дал вам знать

4. Я также добавил строгую типизацию в два цикла, которые я пропустил: @foreach (CustomerType cusType in Model.CustomerTypes) (в представлении) и foreach (Customer cus in customers) в действии — иногда компилятор может жаловаться на это

5. Adyson первое действие работает, я должен проверить со вторым