6
votes

I created a content part, and add it to content type. When I create content type, a content part is not displayed, unlike as other fields. No have compilation or logged errors, content part added to placement.info.

Driver:

[UsedImplicitly]
public class TradeItemPartDriver: ContentPartDriver<TradeItemPart>
{
    private readonly ITradeItemService _tradeItemService;

    private const string TemplateName = "Parts/TradeItem";

    public TradeItemPartDriver(ITradeItemService tradeItemService)
    {
        _tradeItemService = tradeItemService;
    }

    protected override string Prefix
    {
        get { return "TradeItem"; }
    }

    protected override DriverResult Display(
        TradeItemPart part,
        string displayType,
        dynamic shapeHelper)
    {

        return ContentShape("Parts_TradeItem",
                        () => shapeHelper.Parts_TradeItem(
                            ContentPart: part)); 
    }

    protected override DriverResult Editor(
        TradeItemPart part,
        dynamic shapeHelper)
    {
        var shape = ContentShape("Parts_TradeItem_Edit",
                () => shapeHelper.EditorTemplate(
                    TemplateName: TemplateName,
                    Model: BuildEditorViewModel(part),
                    Prefix: Prefix));
        return shape;
    }

    protected override DriverResult Editor(
        TradeItemPart part,
        IUpdateModel updater,
        dynamic shapeHelper)
    {

        var model = new EditTradeItemViewModel();
        updater.TryUpdateModel(model, Prefix, null, null);

        if (part.ContentItem.Id != 0)
        {
            _tradeItemService.UpdateTradeItemForContentItem(
                part.ContentItem, model);
        }

        return Editor(part, shapeHelper);
    }

    private EditTradeItemViewModel BuildEditorViewModel(TradeItemPart part)
    {
        var model = new EditTradeItemViewModel
        {
Code = part.Code, Cost= part.Cost, Unit = part.Unit, Weight = part.Weight,
UnitsList = _tradeItemService.GetUnitTypes()
        };
        return model;
    }
}

Handler:

public class TradeItemPartHandler : ContentHandler
{
    public TradeItemPartHandler(IRepository<TradeItemPartRecord> repository)
    {
        Filters.Add(StorageFilter.For(repository));
    }
}

Models:

public enum EnumTradeItemUnit  : byte
{
    Шт = 0,
    Кг = 1,
    Литр = 2,
    Упаковка = 3
}

public class TradeItemPartRecord : ContentPartRecord
{
    public virtual string Code { get; set; }
    public virtual decimal Weight { get; set; }
    public virtual decimal Cost { get; set; }
    public virtual int Unit { get; set; }
}

public class TradeItemPart : ContentPart<TradeItemPartRecord>
{
    public virtual string Code { get; set; }
    public virtual decimal Weight { get; set; }
    public virtual decimal Cost { get; set; }
    public virtual EnumTradeItemUnit Unit { get; set; }
}

Serveces:

public interface ITradeItemService: IDependency
{
    //IEnumerable<TradeItemPart> GetTradeItems();
    SelectList GetUnitTypes();
    void UpdateTradeItemForContentItem(
        ContentItem item,
        EditTradeItemViewModel model);
}

public class TradeItemService : ITradeItemService
{
    private readonly IContentManager _contentManager;
    private readonly IRepository<TradeItemPartRecord> _tradeItemsRepository;

    public TradeItemService(IContentManager contentManager, IRepository<TradeItemPartRecord> tradeItemsRepository)
    {
        _contentManager = contentManager;
        _tradeItemsRepository = tradeItemsRepository;
    }

    public SelectList GetUnitTypes()
    {
        return new SelectList(
        Enum.GetValues(typeof(EnumTradeItemUnit)).Cast<EnumTradeItemUnit>().Select
            (it =>
            new SelectListItem() { Value = ((byte)it).ToString(), Text = it.ToString() }));
    }

     public void UpdateTradeItemForContentItem(
        ContentItem item,
        EditTradeItemViewModel model)
    {
        var part = item.As<TradeItemPart>();
        part.Code = model.Code;
        part.Cost = model.Cost;
        part.Unit = model.Unit;
        part.Weight = model.Weight;
    }
}

ViewModel:

public class EditTradeItemViewModel
{
    [StringLength(10), WebDisplayName("Код")]
    public virtual string Code { get; set; }
    [Required, Range(0, 100, ErrorMessage = "Товары тяжелее 100кг пусть более крутые ребята возят"), WebDisplayName("Вес")]
    public virtual decimal Weight { get; set; }
    [Required, Range(0.01, 100000, ErrorMessage = "Товары дороже 100тыс.р. пусть более крутые ребята возят"), WebDisplayName("Цена")]
    public virtual decimal Cost { get; set; }
    [Required, WebDisplayName("Единица измерения")]
    public virtual EnumTradeItemUnit Unit { get; set; }
    public virtual SelectList UnitsList { get; set; }
}

~/Views/EditorTemplates/Parts/TradeItem.cshtml

@model Delivery.ViewModels.EditTradeItemViewModel
<fieldset>
    <legend>@T("Характеристики")</legend>

  <div class="editor-label">
    @Html.LabelFor(model => model.Code, T("Код"))
  </div>
  <div class="editor-field">
    @Html.TextBoxFor(model => model.Code)
    @Html.ValidationMessageFor(model => model.Code)
  </div>

  <div class="editor-label">
    @Html.LabelFor(model => model.Unit, T("Единица измерения"))
  </div>
  <div class="editor-field">
    @Html.DropDownListFor(model => model.Unit, Model.UnitsList)
    @Html.ValidationMessageFor(model => model.Unit)
  </div>

  <div class="editor-label">
    @Html.LabelFor(model => model.Cost, T("Стоимость"))
  </div>
  <div class="editor-field">
    @Html.TextBoxFor(model => model.Cost)
    @Html.ValidationMessageFor(model => model.Cost)
  </div>

  <div class="editor-label">
    @Html.LabelFor(model => model.Weight, T("Вес одной единицы"))
  </div>
  <div class="editor-field">
    @Html.TextBoxFor(model => model.Weight)
    @Html.ValidationMessageFor(model => model.Weight)
  </div>

</fieldset>

Placement:

<Placement>
  <Place Parts_TradeItem_Edit="Content:10"/>
  <Place Parts_TradeItem="Content:10"/>
</Placement>

Migrations:

        SchemaBuilder.CreateTable("TradeItemRecord",
                       table => table
                           .ContentPartRecord()
                           .Column<string>("Code", column => column.WithLength(10))
                           .Column<decimal>("Weight", column => column.WithPrecision(8).WithScale(2))
                           .Column<decimal>("Cost", column => column.WithPrecision(8).WithScale(2))
                           .Column<byte>("Unit")
                       );

        ContentDefinitionManager.AlterPartDefinition("TradeItem",
            builder => builder.Attachable());
1

1 Answers

12
votes

There are generally 2 problems with your code.

First, in your migrations, you called the part TradeItem while in the model, you called it TradeItemPart. Changing one or the other will solve the problem of why nothing is showing up in the editor.

Which leads us to the second problem which will disable saving any of your data. You didn't connect your TradeItemPart with your TradeItemPartRecord. To solve this problem, you'll need to adjust TradeItemPart so that it looks like this:

public class TradeItemPart : ContentPart<TradeItemPartRecord>
{
    public string Code { 
        get { return Record.Code; } 
        set { Record.Code = value; } 
    }
    public decimal Weight { 
        get { return Record.Weight; } 
        set { Record.Weight = value; } 
    }
    public decimal Cost { 
        get { return Record.Cost; } 
        set { Record.Cost = value; } 
    }
    public EnumTradeItemUnit Unit { 
        get { return (EnumTradeItemUnit)Record.Unit; } 
        set { Record.Unit = (int)value; } 
    }
}

I'm also not sure whether Orchard will correctly associate column of type byte to the int type. If above mentioned changes don't work, try changing the column type of Unit column to int.