在 Kentico 的自定义模块中创建 UI 来管理 类 之间的多对多关系

Create UI to manage many to many relationship between classes in custom module in Kentico

我正在尝试在 Kentico (Kentico 10) 数据库中存储和管理一些关系数据。我无法将其纳入 Kentico 的最佳实践。

我有以下数据:
1.公司-公司列表
2. PostalCode - 国际邮政编码列表,他们的国家和他们的 lat/long
3. CompanyPostalCodes - 多对多 table 每家公司提供的邮政编码以及描述公司如何提供该邮政编码的布尔标志(邮政编码是服务/送货区域)

我已阅读 creating custom modules 上的文档 并已成功创建模块 类 和 UI 来管理公司和邮政编码。
我还阅读了 creating a binding class 上的文档 并创造了一个。 (我也在那里添加了前面提到的布尔字段。)

我一直在尝试创建一个 UI 来管理它们之间的多对多关系。理想情况下,我有办法从“编辑公司”页面 select 多个邮政编码(并键入 PostalCode table 中尚不存在的邮政编码)。我还需要能够在给定公司的编辑页面上为每个邮政编码设置标志字段。 (如果这过于复杂,我可以为带有标志的邮政编码设置一个选项卡,为没有标志的邮政编码设置另一个选项卡。)但我愿意接受任何关于如何管理 UI.[=14 中的关系的建议。 =]

有什么建议吗?

如果您的绑定 object 不仅仅是对两个表(它有字段)的引用,那么这里有几个选项。

首先确保您在公司中的编辑是 ui 页面类型垂直列表,然后在其下添加类型编辑 object 的 "general" 页面,以及您的绑定 UI。那么...

  1. 使用绑定 UI 模板,但扩展 ui 并调整列表以指向具有编辑功能的自定义 unigrid xml,这样您就可以不仅添加绑定,还编辑 object.

  2. 做 #1 除了修改 unigrid 为复选框添加额外的列,改变列呈现所以它 returns 一个复选框 object (标志检查框)并向 header 添加一个保存按钮(所有这些都可以通过 ui 扩展程序实现)循环遍历项目并使用复选框保存公司邮政)

  3. 有一个单独的 object 列表 UI 页面,它是绑定 object 上的 object 列表,因此您有一个可以创建绑定,另一个编辑它们。请注意,有时您不能 select object 因为它是属性中的绑定 object 并且您需要单击下拉列表旁边的黑色箭头并手动输入 class.

  4. 创建一个完全自定义的 object 列表或一个扩展的 unigrid 并根据需要进行操作。

我亲自完成了所有 4 个,#2 可能是最复杂但最流畅的管理。如果你想挑一个你想一起去,我可以给一些样品!

--------------------编辑-----------------

再看一遍,#2 你不能真正扩展保存功能,我不得不走自定义路线 (#4) 来拥有一个 UniGrid,它有可以在保存时检索的可变字段。

这是代码

// ASCX
<!-- DO NOT Arranged or add to the columns without adjusting the back end code, as it references by index -->
    <div class="GridContent">
        <cms:UniGrid EnableTheming="true" ShowActionsMenu="false" ShowActionsLabel="false" ShowExportMenu="false" ShowObjectMenu="false" runat="server" ID="gridSizes" OrderBy="enabled desc, SizeOrder" AllColumns="SizeID, Enabled, SizeDisplayName, PriceAdjustment, Upcharge, VendorUpcharge" ApplyPageSize="false" PageSize="##ALL##">
            <GridActions Enabled="false" />
            <GridColumns>
                <ug:Column runat="server" Source="SizeID" Caption="SizeID" CssClass="hidden" AllowSorting="false" />
                <ug:Column runat="server" Source="Enabled" Caption="Enabled" ExternalSourceName="Enabled" AllowSorting="false" />
                <ug:Column runat="server" Source="SizeDisplayName" CssClass="DisplayName" Caption="Size Display Name" AllowSorting="false" />
                <ug:Column runat="server" Source="Upcharge" Caption="Upcharge" ExternalSourceName="Upcharge" AllowSorting="false" />
                <ug:Column runat="server" Source="VendorUpcharge" Caption="Vendor Upcharge" ExternalSourceName="VendorUpcharge" AllowSorting="false" />
            </GridColumns>
            <PagerConfig  ShowPageSize="false" ShowDirectPageControl="false" PageSizeOptions="##ALL##" runat="server" Visible="false" />
        </cms:UniGrid>
    </div>
    <cms:FormSubmitButton runat="server" ID="btnSaveItems" OnClick="btnSave_Click" />

// Code Behind
private void SetSizesTable()
    {
        QueryDataParameters parameters = new QueryDataParameters();
        parameters.Add("@SkuID", GetSkuID());
        int totalRecords = 0;
        DataSet ds = YourDataCallHere;
        gridSizes.DataSource = ds;
        gridSizes.OnExternalDataBound += GridSizes_OnExternalDataBound;
        gridSizes.DataBind();
    }

private object GridSizes_OnExternalDataBound(object sender, string sourceName, object parameter)
    {
        // Replace the Enabled and Upcharge with actual controls, this way the user can adjust them
        // and then those values retrieved when saved.
        switch(sourceName.ToLower())
        {
            case "enabled":
                var enabled = ValidationHelper.GetBoolean(parameter, false);
                CheckBox cbxEnabled = new CheckBox();
                cbxEnabled.Checked = enabled;
                cbxEnabled.TabIndex = 100;
                return cbxEnabled;
            case "upcharge":
            case "vendorupcharge":
                var price = ValidationHelper.GetDecimal(parameter, 0);
                CMSTextBox txtBox = new CMSTextBox();
                txtBox.Text = price.ToString("F2");
                txtBox.TabIndex = 1000;
                return txtBox;
            default:
                return parameter;
        }
    }

// Save logic here
protected void btnSave_Click(object sender, EventArgs e)
    {
        // Loop through the actual control rows so we can retrieve the values and update.
        ControlFinder<GridViewRow> GridViewRowFinder = new ControlFinder<GridViewRow>();
        GridViewRowFinder.FindChildControlsRecursive(gridSizes);

        bool ErrorOccurred = false;

        // Skip the first and last as they are the header / action rows
        foreach (GridViewRow RowItem in GridViewRowFinder.FoundControls.Skip(1).Take(GridViewRowFinder.FoundControls.Count()-2))
        {
            try
            {
                // Retrieve the values from the controls.  These are based on the Cell index so any modification to the
                // UniGrid may break this and need updating!
                int SizeID = ValidationHelper.GetInteger(((LiteralControl)RowItem.Cells[1].Controls[0]).Text, -1);
                bool isChecked = ((CheckBox)RowItem.Cells[2].Controls[0]).Checked;
                decimal Upcharge = ValidationHelper.GetDecimal(((CMSTextBox)RowItem.Cells[4].Controls[0]).Text, 0);
                decimal VendorUpcharge = ValidationHelper.GetDecimal(((CMSTextBox)RowItem.Cells[5].Controls[0]).Text, 0);
                if (Upcharge > 0 || VendorUpcharge > 0)
                {
                    isChecked = true;
                }
                // Grab any existing Sku Size
                var ExistingSkuSize = SkuSizeInfoProvider.GetSkuSizeInfo(GetSkuID(), SizeID);

                // Update the Sku Size
                if (!isChecked && ExistingSkuSize != null)
                {
                    // Delete existing since unchecked
                    ExistingSkuSize.Delete();
                }
                else if (isChecked && ExistingSkuSize == null)
                {
                    // Create new one since it does not exist
                    SkuSizeInfo newSkuSize = new SkuSizeInfo();
                    newSkuSize.SkuID = GetSkuID();
                    newSkuSize.SizeID = SizeID;
                    newSkuSize.Upcharge = Upcharge;
                    newSkuSize.VendorUpcharge = VendorUpcharge;
                    newSkuSize.SkuSizeGuid = Guid.NewGuid();
                    newSkuSize.SkuSizeLastModified = DateTime.Now;
                    newSkuSize.Insert();
                }
                else if (isChecked && (ExistingSkuSize.Upcharge != Upcharge || ExistingSkuSize.VendorUpcharge != VendorUpcharge))
                {
                    // Just update the upcharge
                    ExistingSkuSize.Upcharge = Upcharge;
                    ExistingSkuSize.VendorUpcharge = VendorUpcharge;
                    ExistingSkuSize.Update();
                }
            } catch(Exception ex)
            {
                ErrorOccurred = true;
                EventLogProvider.LogException("ProductSizes", "UPDATEERROR", ex, additionalMessage: string.Format("Unable to Set/Update the Sku Size for SkuID {0}, this could be because the grid was altered.", GetSkuID()));
            }
        }

        if(ErrorOccurred)
        {
            AddWarning("An error occured on some items while saving, please check the Event Log.");
        } else
        {
            AddConfirmation("Product Sizes Updated.");
            // Force refresh as otherwise it messes up
            URLHelper.Redirect(HttpContext.Current.Request.Url.PathAndQuery);
        }

    }
}