Ошибка при попытке заполнить выпадающий список во время действия «GET» - PullRequest
0 голосов
/ 05 июня 2009

Я пытаюсь понять что-то немного лучше, будучи новичком в C #, .NET 3.5 и MVC.

Я работаю с примером MVC NerdDinner, и если вы посмотрите на ViewModel здесь: http://nerddinnerbook.s3.amazonaws.com/Part6.htm#highlighter_662935

Вы можете увидеть список стран и то, как он заполняется, похоже, это работает нормально, но я попытался сделать то же самое ниже, используя LINQ, и у меня возникли проблемы с подходом SelectList, хотя он наследуется от интерфейса IEnumerable.

У меня есть таблица задач с внешним ключом таблицы состояния. Приведенный ниже код дает мне исключение NullReferenceException, когда я выполняю GET для действия создания. Я вижу, что у объекта анонимной задачи не будет установлен статус ... поэтому мне, вероятно, нужно проверить его, но я не понимаю, как это не делается для примера 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

Ответы [ 3 ]

0 голосов
/ 06 июня 2009

Я понимаю, что получу нулевое значение для типа или статуса, если я не добавлю значение во вновь созданную задачу. То, что я не понимаю и что я не прояснил, это ниже. Вы можете видеть, что модель представления имеет свойство «Страны», и его выбранное значение установлено как 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>
0 голосов
/ 07 июня 2009

Моя попытка лучше понять это.

    //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 в действии create контроллера?

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

0 голосов
/ 05 июня 2009

Что у тебя в конструкторе задач? Каково значение .typeId для вновь созданной задачи? Это нулевая ссылка?

Для модели представления, отправляемой в представление Create, не следует пытаться установить выбранный элемент списка, если ваш конструктор задач (или другой код инициализации) не установит значения по умолчанию для этих свойств. Если значение task.typeId равно нулю, ваш код, который создает список выбора, получит ошибку.

...