0

私は、C#、. NET 3.5、およびMVCを初めて使用することで、もう少し理解を深めようとしています。

私はMVCNerdDinnerの例を実行していますが、ここでViewModelを見ると、http://nerddinnerbook.s3.amazonaws.com/Part6.htm#highlighter_662935

国リストとその入力方法を確認できます。これは正常に機能しているようですが、LINQを使用して以下で同様のことを実行しようとしましたが、IEnumerableインターフェイスから継承しているにもかかわらず、SelectListアプローチで問題が発生しています。

ステータステーブルへの外部キーを持つタスクテーブルがあります。以下のコードは、作成アクションで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

タスクコンストラクターには何が含まれていますか?新しく作成されたタスクの.typeIdの値は何ですか?null参照ですか?

作成ビューに送信されるビューモデルの場合、タスクコンストラクター(または他の初期化コード)がこれらのプロパティのデフォルト値を設定しない限り、選択したリストアイテムを設定しようとしないでください。task.typeIdがnullの場合、選択リストを作成しているコードはエラーになります。

于 2009-06-05T18:52:52.557 に答える
0

新しく作成したタスクに値を追加しないと、タイプまたはステータスにnull値が返されることを理解しています。私が理解していないことと私が明らかにしなかったことは以下のとおりです。ビューモデルにCountriesプロパティがあり、選択した値がDinner.Country ..に設定されていることがわかります。現在、Dinner.Countryはcreateアクションで設定されていません。では、なぜこれでnull例外が発生しないのでしょうか。

//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

これをよりよく理解しようとする私の試み。

    //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 に答える