0

我试图更好地理解 C#、.NET 3.5 和 MVC 的新手。

我正在运行 MVC NerdDinner 示例,如果您在此处查看 ViewModel:http: //nerddinnerbook.s3.amazonaws.com/Part6.htm#highlighter_662935

您可以看到 Country 列表及其填充方式,这似乎工作正常,但我尝试在下面使用 LINQ 执行类似的操作,但使用 SelectList 方法时遇到了问题,即使它继承自 IEnumerable 接口。

我有一个带有状态表外键的任务表。当我对创建操作执行 GET 时,下面的代码给了我一个 NullReferenceException。我可以看到匿名任务对象不会设置状态..所以我可能需要检查它,但我不明白对于 NerdDinner 示例如何不这样做?

        public class TaskViewModel {
        // Properties

        public Task Task { get; private set; }
        public SelectList Status { get; private set; }

        // Constructor
        public TaskViewModel(Task task) {
            TaskRepository taskRepo = new TaskRepository();
            Task = task;
            Status = new SelectList(taskRepo.GetStatus(), Task.Status.description);
        }

    }

        //
        // GET: /Tasks/Create

        public ActionResult Create()
        {
            Task task = new Task();

            return View(new TaskViewModel(task));
        } 


//Code from TaskRepository 

        private TaskManagerDataContext db = new TaskManagerDataContext();

        public IQueryable<Status> GetStatus() {
            return from status in db.Status
                   orderby status.description
                   select status;
        }

我使用 LINQ 对类型下拉列表进行了另一种方法,并且下拉列表的数量有效,但我尚未测试它是否在发布帖子并返回详细信息视图后选择了正确的值。我也想知道这是否应该如何移动到我的存储库中,而不是在我的控制器中让一个类做这种事情?

这是代码:

//In TaskViewModel Class
        public IEnumerable<SelectListItem> Types { get; private set; }

//In TaskViewModel constructor

                IList<NPType> types = taskRepo.GetTypes().ToList();

            Types =
                from type in types
                select new SelectListItem {
                    Selected = (type.typeId == task.typeId),
                    Text = type.description,
                    Value = type.typeId.ToString()
                };

//The TaskForm partial View that is used for the Create action of the TaskController
            <p>
                <label for="type">type:</label>
                <%= Html.DropDownList("Type", Model.Types)%>
                <%= Html.ValidationMessage("type", "*") %>
            </p>
            <p>
                <label for="status">status:</label>
                <%= Html.DropDownList("Status", Model.Status)%>
                <%= Html.ValidationMessage("status", "*") %>
            </p>

并且 TaskForm 视图继承 System.Web.Mvc.ViewUserControl

4

3 回答 3

0

我知道如果我不向新创建的任务添加值,我将获得类型或状态的空值。我不明白和我没有说清楚的是以下内容。您可以看到视图模型有一个 Country 属性,并且它的选定值设置为 Dinner.Country.. 现在 Dinner.Country 没有在创建操作中设置.. 那么为什么这不会给出空异常?

//viewmodel code
            public DinnerFormViewModel(Dinner dinner) {
            Dinner = dinner;
            Countries = new SelectList(PhoneValidator.Countries, Dinner.Country);
        }

//controller code
        public ActionResult Create() {

            Dinner dinner = new Dinner() {
                EventDate = DateTime.Now.AddDays(7)
            };

            return View(new DinnerFormViewModel(dinner));
        } 

//view code
            <p>
            <label for="Country">Country:</label>
            <%= Html.DropDownList("Country", Model.Countries) %>                
            <%= Html.ValidationMessage("Country", "*") %>
        </p>
于 2009-06-06T12:49:33.253 回答
0

您的任务构造函数中有什么?新创建的任务上 .typeId 的值是多少?它是空引用吗?

对于发送到您的创建视图的视图模型,您不应该尝试设置选定的列表项,除非您的任务构造函数(或其他初始化代码)为这些属性设置了默认值。如果 task.typeId 为 null,则构建选择列表的代码将出错。

于 2009-06-05T18:52:52.557 回答
0

我试图更好地理解这一点。

    //controller code creating a select list in the viewmodel class.
//taskRepo.GetStatus() returns an IQueryable<Status>
        Status = new SelectList(taskRepo.GetStatus(), Task.Status);

//MVC Framework SelectList class constructor and ToEnumerable method
            public SelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue)
            : base(items, dataValueField, dataTextField, ToEnumerable(selectedValue)) {
            SelectedValue = selectedValue;
        }

        private static IEnumerable ToEnumerable(object selectedValue) {
            return (selectedValue != null) ? new object[] { selectedValue } : null;
        }

我可以看到 SelectList 使用它的 MultiSelectList 基类,并且构造函数在这里:

        public MultiSelectList(IEnumerable items, string dataValueField, string dataTextField, IEnumerable selectedValues) {
        if (items == null) {
            throw new ArgumentNullException("items");
        }

        Items = items;
        DataValueField = dataValueField;
        DataTextField = dataTextField;
        SelectedValues = selectedValues;
    }

当我运行这个项目时,html 给出为:

    <select id="Status" name="Status"><option>NPTaskManager.Models.Status</option>
<option>NPTaskManager.Models.Status</option>
<option>NPTaskManager.Models.Status</option>
<option>NPTaskManager.Models.Status</option>
</select>

这是可以预料的。

如果我将控制器代码更改为:

Status = new SelectList(taskRepo.GetStatus(), Task.Status.statusId.ToString(), Task.Status.description);

然后我得到一个 NullReferenceException。由于这不是 ArgumentNullException 在我看来,异常的根源不是第一个 SelectList 参数。我想了解的是这一切是如何发生的?是不是因为在控制器的创建动作中需要将Task.Status添加到Task中?

我将更改此代码以使用我用于上述任务的 LINQ 方法,我现在想要实现的只是对正在发生的事情有所了解。

于 2009-06-07T11:40:14.300 回答