Telerik MVC Grid: как использовать DropDownList в столбце?

У меня есть сетка Telerik MVC в приложении MVC 3 с Razor, которое связано с Ajax. Сейчас я пытаюсь добавить к нему столбец выпадающего списка, чтобы пользователи могли использовать его в режиме редактирования, но не могу понять, как это сделать. В сетке отображается список продуктов, и я хочу, чтобы выпадающий список содержал набор категорий продуктов, с которыми может быть связан продукт. Я занимаюсь этим уже несколько часов, и у меня нет идей. Я очень надеюсь, что кто-то здесь может помочь :)

Я ссылался на демо-версию Telerik, которая находится здесь.

Я думаю, что часть, которая вешает меня, находится в представлении справки, которое используется в демо. В демо это называется "ClientEmployee(Editor)". В моем случае я поместил помощника в файл с именем «ProductCategoryDropList.cshtml». В этом помощнике мне трудно заставить DropDownList правильно связываться. Я думаю, это может быть потому, что я каким-то образом не устанавливаю метод BindTo() с правильными данными. Я отметил эту путаницу в приведенном ниже примере кода вспомогательной программы DropDownList с параметром SomeCollectionReference в качестве первого параметра в вызове конструктора new SelectList(). Когда я пытаюсь поместить «Модель» в это место, я получаю исключение NullReferecne. Когда я пытаюсь получить доступ к данным ViewBag, содержащим список, я получаю сообщение, похожее на «В SelectList нет столбца ProductCategoryID» или что-то в этом роде. Итак, я не уверен, что еще попробовать.

Я не уверен, насколько ясно это описание моей проблемы, но чтобы быть полным, я включил код, который я считаю уместным ниже.

Контроллер:

public ActionResult Index()
{
    ViewBag.ProductCategories = new SelectList(_productCategoryService.GetActiveProductCategories(), "ProductCategoryID", "ProductcategoryName");
    var products = _productService.GetProducts().ToList();
    var presentationModel = _mapper.MapAsList(products);
    return View(presentationModel);
}

//
// GET: /Product/
[GridAction]
public ViewResult _Index()
{
    ViewBag.ProductCategories = new SelectList(_productCategoryService.GetActiveProductCategories(), "ProductCategoryID", "ProductcategoryName");
    return View(new GridModel<ProductPresentationModel>
                    {
                        Data = _mapper.MapAsList(_productService.GetProducts().ToList())
                    });
}

Просмотр:

Это немного длинно, но я попытался упростить его, поместив «// ‹--- DropList Here» рядом со столбцом, с которым я пытаюсь работать.

@model IEnumerable<Models.PresentationModels.ProductPresentationModel>

@(Html.Telerik().Grid(Model).HtmlAttributes(new { style = "width: 100%;" })
        // Give the Grid an HTML id attribute value
        .Name("ProductGrid")
        // Establish the promiry key, to be used for Insert, Update, and Delete commands
        .DataKeys(dataKeys => dataKeys.Add(p => p.ProductID))
        // Add an Insert command to the Grid Toolbar
        .ToolBar(commands => commands.Insert().ButtonType(GridButtonType.ImageAndText))
        // Using Ajax Data Binding to bind data to the grid
        .DataBinding(dataBinding => dataBinding
                // Ajax Binding
                .Ajax()
                    .Select("_Index", "Product")
                    // Home.Insert inserts a new data record
                    .Insert("Create", "Product")
                    // Home.Update updates an existing data record
                    .Update("Edit", "Product")
                    // Home.Delete deletes an existing data record
                    .Delete("Delete", "Product")
        )
        .Columns(columns =>
        {
            columns.Bound(p => p.ProductName).Width(120);
            columns.Bound(p => p.ProductDescription).Width(150);
            columns.Bound(p => p.PricePerMonth).Width(120);
            columns.Bound(p => p.ProductImagePath).Width(150)
            columns.Bound(p => p.ProductActive).Width(120)
                .ClientTemplate("<input type='checkbox' disabled='disabled' name='Active' <#= ProductActive ? checked='checked' : '' #> />");
            columns.Bound(p => p.ProductCategoryName); // <--- DropList Here
            columns.Command(commands =>
            {
                commands.Edit().ButtonType(GridButtonType.Image);
                commands.Delete().ButtonType(GridButtonType.Image);
            });
        })
        .Editable(editing => editing.Mode(GridEditMode.PopUp))
        .ClientEvents(events => events.OnEdit("onEdit"))
        .Pageable()
        .Scrollable()
        .Sortable()
        .Filterable()
)

@section HeadContent {
    <script type="text/javascript">
        function onEdit(e) {
            $(e.form).find('#ProductCategoryName').data('tDropDownList').select(function (dataItem) {
                return dataItem.Text == e.dataItem['ProductCategoryName'];
            });
        }
    </script>
}

Модель:

[DisplayName(@"Category Name")]
[UIHint("ProductCategoryDropList"), Required]
[StringLength(255, ErrorMessage = @"Product Category Name cannot be more than 255 characters in length")]
public string ProductCategoryName
{
    get 
    {   
        string name = string.Empty;

        if (_model.ProductCategory != null)
        {
            name = _model.ProductCategory.ProductCategoryName;
        }

        return name;
    }
    set 
    {
        if (_model.ProductCategory != null)
        {
            _model.ProductCategory.ProductCategoryName = value;
        }
    }
}

Помощник DropList:

@model Models.PresentationModels.ProductPresentationModel

@(Html.Telerik().DropDownList()
        .Name("ProductCategoryName")
            .BindTo(new SelectList(<SomeCollectionReference>, "ProductCategoryID", "ProductCategoryName"))
)

Карта продукта:

public List<ProductPresentationModel> MapAsList(List<Product> products)
{
    //var categoryList = new SelectList(_productCategoryService.GetProductCategories().ToList(), "ProductCategoryID", "ProductCategoryName"); 

    var presentationModels = products
            .Select(x => new ProductPresentationModel()
            {
                ProductID = x.ProductID,
                ProductCategoryID = ((x.ProductCategory != null) ? x.ProductCategory.ProductCategoryID : 0),
                ProductCategoryName = ((x.ProductCategory != null) ? x.ProductCategory.ProductCategoryName : String.Empty),
                ProductName = x.ProductName,
                ProductDescription = x.ProductDescription,
                PricePerMonth = x.PricePerMonth,
                ProductImagePath = x.ProductImagePath,
                ProductActive = x.ProductActive,
                ProductCategories = new SelectList(_productCategoryService.GetProductCategories().ToList(), "ProductCategoryID", "ProductCategoryName")//categoryList
            }).ToList();

    return presentationModels;
}

person campbelt    schedule 17.08.2011    source источник


Ответы (3)


Мне удалось немного разобраться с этим, но у меня все еще есть вопрос. вот что я изменил, чтобы заставить его работать:

Создал объект ViewData в контроллере, вот так...

public ActionResult Index()
{
    // ViewData object here ...
    ViewData["ProductCategories"] = new SelectList(_productCategoryService.GetActiveProductCategories(), "ProductCategoryID", "ProductCategoryName");
    var products = _productService.GetProducts().ToList();
    var presentationModel = _mapper.MapAsList(products);
    return View(presentationModel);
}

//
// GET: /Product/
[GridAction]
public ViewResult _Index()
{
    // ViewData object here ...
    ViewData["ProductCategories"] = new SelectList(_productCategoryService.GetActiveProductCategories(), "ProductCategoryID", "ProductCategoryName");
    return View(new GridModel<ProductPresentationModel>
                    {
                        Data = _mapper.MapAsList(_productService.GetProducts().ToList())
                    });
}

Затем я использовал объект ViewData в DropDownListHelper, вот так...

@using System.Collections
@model Models.PresentationModels.ProductPresentationModel

@(Html.Telerik().DropDownList()
        .Name("ProductCategoryName")
        .BindTo(new SelectList((IEnumerable)ViewData["ProductCategories"], "Value", "Text"))
);

Теперь мой вопрос: нужно ли мне использовать объект ViewData? Я хотел бы иметь возможность использовать свойство моей модели. Но по какой-то причине моя модель всегда имеет значение NULL внутри вспомогательного файла. И если я попытаюсь поместить код DropDownList в код создания Grid, DropDownList вообще не будет работать.

Итак, есть ли у меня другие варианты?

person campbelt    schedule 18.08.2011

В настоящее время я сталкиваюсь с той же проблемой, что и вы, и это действительно правда, что вам написали ребята из Telerik. Частичный вид предварительно визуализируется на сервере (содержимое включено). Это может быть достаточным решением, если список допустимых значений статичен, но...

... представьте, что вы хотите иметь разные списки допустимых значений для каждой строки сетки. В таком случае эта концепция не реализуема...

Поскольку в сетке есть только одна комбинация (на столбец), единственное решение, которое я нашел, - это обрабатывать событие сетки onEdit, где вы можете привязать поле со списком к разрешенным значениям с помощью AJAX. В обработчике сетки onEdit вы можете получить доступ ко всем полям данных соответствующей строки, поэтому вы можете использовать их для целей привязки.

С уважением, Ондрей.

person Ondrej Bechera    schedule 22.08.2011
comment
Отличная информация, Ондрей. Не могли бы вы обновить этот пост одним или двумя примерами, иллюстрирующими то, что вы описали? - person campbelt; 22.08.2011

Я спросил об этом у хороших людей из службы поддержки Telerik. Вот какой ответ они мне дали:

Модель имеет значение null, поскольку частичное представление DropDownList отображается для редактирования ajax. В этом случае сетка выполняет предварительную визуализацию всех шаблонов редактора частичного представления, чтобы их можно было использовать на стороне клиента. В этом случае модель будет нулевой. Если вы использовали привязку к серверу и редактирование, для модели будет установлено правильное значение.

На данный момент я собираюсь принять этот пост как ответ на мой вопрос. К сожалению, в этом случае я должен принять свой собственный ответ, но ... ну, у меня не было других на выбор :)

person campbelt    schedule 19.08.2011