Question

I'm creating a webpart that acts like a new form. Based on a view I'm getting on fields and rendering them in my webpart using spfield.FieldRenderingControl.

My columns are site columns, at this level some have been made required, added to a content type, which has been added to a list. After added to the list, certain columns that were not required have been made required, and some that were required at the site column level are now not.

Below is the code I'm using to render my form. No matter what I have tried, the rendering of the control seems to be grabbed from the site column level, not the list content type level. I'm unable to Render the control from a SPFieldLink.

I've put comments within the code around the area I think might need amending.

                try
                {
                    Table table = new Table();
                    table.CssClass = "hlwp_DSCreateEditTable";
                    TableRow row;
                    TableCell cell;
                    SPContentType ct = spList.ContentTypes[ContentTypeName];


                for (int i = 0; i < spView.ViewFields.Count; i++)
                {
                    string fieldName = spView.ViewFields[i];
                    //The flink holds the information at the content type level in the list.
                    SPFieldLink flink = ct.FieldLinks[fieldName];
                    SPField field = spList.Fields.GetField(fieldName);

                    row = new TableRow();
                    row.CssClass = "hlwp_DSCreateEditRow";
                    cell = new TableCell();
                    cell.CssClass = "hlwp_DSCreateEditTitleCell";



    //Even tried setting the field.required to match the flink.required.
    //When debugging and following the code through it stays the same as flink.required, 
    //but if you call Page.Validate() it displays errors on the controls 
    //that are required at the site column level not list content type level.

                    if (flink != null)
                    {
                        field.Required = flink.Required;
                    }

                    if (field.Required)
                    {
                        cell.Text = field.Title + "<font color='red'>*</font>";
                    }
                    else
                    {
                        cell.Text = field.Title;
                    }

                    row.Cells.Add(cell);
                    cell = new TableCell();
                    cell.CssClass = "hlwp_DSCreateEditControlCell";
                    Control cntrl = HelperClass.GetSharePointControls(field, spList, itemId);
                    if (cntrl == null) continue;
                    cell.Controls.Add(cntrl);
                    row.Cells.Add(cell);
                    table.Rows.Add(row);

                }

HelperClass.GetSharePointControls

public static Control GetSharePointControls(SPField field, SPList list, int itemId)
        {
          // check if the field is a buildIn field, or can be rendered by a SharePoint Control
            if (field == null || field.FieldRenderingControl == null || field.Hidden) return null;

        Control ctrl = null;
        SPControlMode mode = SPControlMode.Invalid;

        if (itemId > 0)
            mode = SPControlMode.Edit;
        else
            mode = SPControlMode.New;

//Wondering if it's something to do with the context, as later on you set this context to the RenderingContext.
            var controlContext = SPContext.GetContext(System.Web.HttpContext.Current, itemId, list.ID, SPContext.Current.Web);



        SPContext.Current.FormContext.SetFormMode(mode, true);
        controlContext.FormContext.SetFormMode(mode, true);


        try
        {
                BaseFieldControl webControl = field.FieldRenderingControl;
                webControl.ListId = list.ID;
                webControl.ControlMode = mode;
                webControl.ItemId = itemId;
                webControl.FieldName = field.Title;
                webControl.ID = GetControlID(field); //Creates a unique ID.

                webControl.RenderContext = controlContext;
                webControl.ItemContext = controlContext;

                ctrl = webControl;
            }
            return ctrl;
        }
        catch (Exception ex)
        {
            var errorLabel = new Label
            {
                ID = "ErrorLabel",
                Text = String.Format("Error in GetSharePointControls:<br/>{0}", ex)
            };
            return errorLabel;
        }
    }

If anyone has any ideas I would be very grateful. I've even tried to reflect on Microsoft code with limited success.

Was it helpful?

Solution 2

I've looked further into this, and it appears that the SPField does read in the required status of the list field. However on a custom list, you are able to edit the required field by clicking on the column name in List settings.

For a document library the required field setting is missing. The only way you can set the required field is either in the site content type and push down the change, (which would change the required field everywhere you use it, not just on the given list) or you code, using .Net or powershell to set the field on the list to required. Then remove any reference in my original code to SPFieldLink.

$web = Get-SPWeb "[YourSite]"
$list = $web.GetListFromUrl("[Your List URL]")
$field = $list.Fields["[Field Name"]
Write-Host "Previous Value:" $field.Required
$field.Required = $true
$field.Update()
Write-Host "The field" $field.Title "is now set to" $field.Required

It is strange how the original code I posted acts very different in a Custom List compared to a Document Library.

I discovered this, by display the field description in my webpart. If the local description was different to the site column description, when you call field.Description you always got the local description. Which meant calling spfield from the list did give you the values from the column given in the list not from the site column. So I powershelled a query if the column on the list was required, and although it was in the site column it wasn't for the list.

Alternative fix instead of using powershell is to create a layouts page that you call from library settings that allows you to modify the required value for each of the columns in the list, as clearly Microsoft has missed out this functionality. (Maybe for a good reason that I haven't found yet).

OTHER TIPS

Maybe view how the codeplex project batchedit does it: http://sp2010batchedit.codeplex.com/

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top