简体   繁体   中英

ASP.NET MVC Get inherited class data in View

I am very new to c# and OOP and MVC and am struggling with getting the data from an inherited class in MVC View. I am probably doing this all wrong.

I have for example:

public class TasksViewModel
{
    public Tasks tasks;
        public TaskViewModel()
        {
            this.tasks = new Tasks();
        }
    }
}

I then have (simplified):

public class BaseTask    
{
    public int id { get; set; }
    public String Description { get; set; }
}

public class WorkTasks : BaseTask
{
    public String Company { get; set; }
}

public class HomeTasks : BaseTask
{
    public String UserName{ get; set; }
}

public class Tasks
{

    public List<BaseTask> taskslist { get; set; }
    public Tasks()
    {
         taskslist = getAllTasks();
    }

    public List<BaseTask> getAllTasks()
    {


           //get data
        List<BaseTask> tempTasks = new List<BaseTask>();
        if (taskType == "Work")
        {
            WorkTask work = new WorkTask();
            work.id = id;
            work.Description = description;
            work.Company = company;
            tempTasks.Add(work)
        }
        else
        {
            HomeTask home = new HomeTask();
            home.id = id;
            home.Description = description;
            home.UserName = name;
            tempTasks.Add(home)
        }
...
        return tempTasks;

}

I set the model as Tasks and in my view I just iterate through them

@foreach(var item in Model.tasks.taskslist)
{
    <p>@item.Description</p>
}

this works just fine and I can get the description and Id, but I can't get the Company or UserName from the tasks inherited from BaseTask. The data I get from item is:

>id
>Description
>Namespace.WorkTasks

however I can't access WorkTasks or HomeTasks.

I can check that the item is a WorkTask or a HomeTask with

if (item.GetType().Name.Equals("WorkTasks"))
{
}

and I tried

item.WorkTasks.Company

but this just gives an error: Tasks does not contain a definition for WorkTasks...

I am sure I am making a stupid rookie mistake. Can anyone help?

And if I am doing this totally wrong then just say. This is my very first attempt at this.

This seems overly complicated and lacks using some of the awesome advantages of MVC (granted I didn't real the entire post). So here is some example code based losely off most of your models:

Simplier model:

public class TasksViewModel
{
  public IEnumerable<TaskBase> Tasks {get; set; }
}

// Removed (s), it's best practice to only use s on collections
public class WorkTask : BaseTask
{
  public String Company { get; set; }
}

// Removed (s), it's best practice to only use s on collections
public class HomeTask : BaseTask
{
  public String UserName{ get; set; }
}

Controller populates model:

public MyController
{
  public ActionResult MyTasksAction()
  {
    var model = new TasksViewmodel()
    model.Tasks = db.GetTasks();
    return View(model);  // Looks for MyTasksAction.cshtml
  }
}

View (MyTasksAction.cshtml):

@model TasksViewModel

<div>
  @Html.DisplayFor(m => m.Tasks)
</div>

Boom done... ( sorta kidding, but not really, if you're into that sorta thing )

By default the DisplayFor will do it's work ( thats a story for another time ) but it won't find a display template matching that type, so it uses it's own internal Object display template which is smart enough to loop through all the items auto-magically. As it loops through the items it calls DisplayFor() on each item so as long as you have:

/Views/MyController/DisplayTemplates/WorkTask.cshtml

/Views/MyController/DisplayTemplates/HomeTask.cshtml

OR

/Views/Shared/DisplayTemplates/WorkTask.cshtml

/Views/Shared/DisplayTemplates/HomeTask.cshtml

those templates are called with the current model in the loop... because Display templates are based on the type (IE a display template for string would be string.cshtml ; worktask would be worktask.cshtml , etc). Those templates might look like:

WorkTask.cshtml

@model WorkTask     
<div>
  @Html.DisplayFor(m => m.Description)</br>
  @Html.DisplayFor(m => m.Company)</br>
</div>

HomeTask.cshtml

@model HomeTask     
<div>
  @Html.DisplayFor(m => m.Description)</br>
  @Html.DisplayFor(m => m.UserName)</br>
</div>

I'm going to answer the question directly cause its a learning experience. Although, I would probably split it into two separate lists as suggested by other people. The general rule of thumb is one view (.cshtml thing) per one model, although at work we built a ViewEngine to render List'TBase' so lol.

namespace SOAnswer0729.Controllers
{
public class HomeController : Controller
{
    public RedirectToRouteResult Index()
    {
        return RedirectToAction("Tasks");
    }
    public ActionResult Tasks()
    {
        var tasks = new Tasks();
        var model = tasks.getAllTasks();
        return View(model);
    }
}

public class Tasks
{

    public List<BaseTask> taskslist { get; set; }
    public Tasks()
    {
        taskslist = getAllTasks();
    }

    public List<BaseTask> getAllTasks()
    {
        //get data
        List<BaseTask> tempTasks = new List<BaseTask>();

        tempTasks.AddRange(DataRepository.WorkSeedData);            
        tempTasks.AddRange(DataRepository.HomeSeedData);

        return tempTasks;
    }

    public enum TaskType
    {
        Undefined = 0,
        WorkTask = 1,
        HomeTask = 2
    }

}

public static class DataRepository
{

    public static List<WorkTask> WorkSeedData = new List<WorkTask>() { 
        new WorkTask() { id = 1, Company = "MSFT", Description = "Write Code" },
        new WorkTask() { id = 2, Company = "ATT", Description = "Sell Service" },
        new WorkTask() { id = 3, Company = "XFTY", Description = "Retain Customers" }
    };

    public static List<HomeTask> HomeSeedData = new List<HomeTask>() {
        new HomeTask() { id = 11, UserName = "Jim", Description = "Make Keys" },
        new HomeTask() { id = 12, UserName = "Bob", Description = "Find Keys" },
        new HomeTask() { id = 13, UserName = "Alice", Description = "Intecept Keys" }
    };
}

public class BaseTask
{
    public int id { get; set; }
    public String Description { get; set; }
}

public class WorkTask : BaseTask
{
    public String Company { get; set; }
}

public class HomeTask : BaseTask
{
    public String UserName { get; set; }
}

}

VIEW

@using SOAnswer0729.Controllers;
@model IEnumerable<BaseTask>
<table class="table">
<tr>
    <th>Company / Name </th>
    <th>
        @Html.DisplayNameFor(model => model.Description)
    </th>
</tr>

@foreach (var item in Model) {
<tr>
    <td>
        @Html.DisplayFor(modelItem => item.Description)
    </td>
    <td>
        @{ if (item is WorkTask)
            {
              <text>@(((WorkTask)item).Company)</text>
            }
            else if (item is HomeTask)
            {
                <text>@(((HomeTask)item).UserName).</text>
            }
        }
    </td>
</tr>
}
</table>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM