Loading

EDITING CUSTOM MODULE DATA - Part 2

Recently I've shared an idea of how you could provide live site users with edit interface for custom module data. As you might know, perfection has no boundaries... This time I want to share some improvement, those will allow you to reuse the same web part for literally any object within your application.

I'm my first post on the related topic I've suggested using UI Form control in order to create/edit custom (or even native) objects within you system. It works perfectly fine with any particular object, but there is a limitation: you have to know what object you are going to work with beforehand. That's good, but not generic enough. So I went further and implemented class agnostic web part.
 
There were two challenges during implementation:

  • Instantiate object knowing just class code name when creating new object
  • Retrieve object data knowing just class code name and ID of an object when updating one
 
In first case ObjectTypeManager and a little bit of .net reflection were really useful.
In second case I knew ObjectQuery is the right path to go, but struggled with finding appropriate methods for data I have. Finally it turned to be really simple.
 
Following is entire code of my custom web part:
 

public partial class CMSWebParts_MyWebParts_EditObject : CMSAbstractWebPart
{
    public string Class
    {
        get
        {
            return ValidationHelper.GetString(GetValue("Class"), "");
        }
        set
        {
            SetValue("Class", value);
        }
    }

    public string Layout
    {
        get
        {
            return ValidationHelper.GetString(GetValue("Layout"), "");
        }
        set
        {
            SetValue("Layout", value);
        }
    }

    protected override void OnInit(EventArgs e)
    {
        var id = -1;
        if (!string.IsNullOrEmpty(Request.QueryString["id"]))
        {
            id = int.Parse(Request.QueryString["id"]);
        }

        var obj = ObjectTypeManager.GetTypeInfo(this.Class);

        BaseInfo bi = null;

        if (id > 0)
        {
            var editObj = new ObjectQuery(this.Class)
                .WhereID(obj.ClassStructureInfo.IDColumn, id)
                .FirstOrDefault();
            bi = (BaseInfo)editObj;
        }
        else
        {
            var newObj = Activator.CreateInstance(obj.InfoType);
            bi = (BaseInfo)newObj;
        }

        EditForm.EditedObject = bi;
        EditForm.Mode = id > 0 ? FormModeEnum.Update : FormModeEnum.Insert;
        EditForm.ObjectSiteID = SiteContext.CurrentSiteID;
        EditForm.ObjectType = this.Class;
        EditForm.MessagesPlaceHolder = new CMS.ExtendedControls.MessagesPlaceHolder();

        EditForm.AlternativeFormName = AlternativeFormInfoProvider.GetAlternativeFormInfo(this.Layout).FormName;
    }

    public override void OnContentLoaded()
    {
        base.OnContentLoaded();
        SetupControl();
    }

    protected void SetupControl()
    {
        if (StopProcessing)
        {
            EditForm.StopProcessing = true;
        }
    }
}


 
This control is generic enough to work with any object you need. Class property allows you to select object class and Layout allows you to specify alternative layout for your form. Also you don't need to adjust your code behind whenever you add new field to the object UI Form will take care about it.

Please, feel free to share your thought, ideas, feedback or experiance on this topic.