BitterCoder's Wiki

Edit

Xml Configuration

One of the advantages of replacing the new/edit form is that you can introduce fine-grained control over field visibility, based on roles etc. of the current user or the state of the current item - here's how I did this.

Edit

The Code

In this example we will assume that there are some item-specific properties, in this case we have a bunch of fields which are assigned by the Author/Creator of the SPListItem and can only be changed by that user in the Edit form.

So we create an enumeration for the various states:


public enum Applies
{
    Never = 0,
    Always,
    ToItemAuthor
}



Now we create a class to represent the field, and make it XML serializable:


public class FilteredField
{
    private Applies _isVisible;
    private Applies _isWriteable;
    private string _name;

[XmlAttribute("IsVisible")] public Applies IsVisible { get { return _isVisible; } set { _isVisible = value; } }

[XmlAttribute("IsWriteable")] public Applies IsWriteable { get { return _isWriteable; } set { _isWriteable = value; } }

[XmlAttribute("Name")] public string Name { get { return _name; } set { _name = value; } } }


Notice we use the Applies status to both the Writeable and Visible properties.

Now, this may not be necessary, depending on how your setting the web part up - but we can create a class for storing all the FilteredField settings for a mode (i.e. New or Edit)


public class FilteredListMode
{
    private List _fields = new List();
    private string _mode;

[XmlAttribute("Mode")] public string Mode { get { return _mode; } set { _mode = value; } }

public FilteredField this[string fieldName] { get { return _fields.Find( delegate(FilteredField field) { return field.Name.Equals(fieldName, StringComparison.InvariantCultureIgnoreCase); } ); } }

[XmlArray("Fields")] [XmlArrayItem("Field")] public List Fields { get { return _fields; } set { _fields = value; } }

public FilteredListMode CreateField(string name, Applies isVisible, Applies isWriteable) { FilteredField field = new FilteredField(); field.Name = name; field.IsVisible = isVisible; field.IsWriteable = isWriteable;

Fields.Add(field);

return this; } }


And finally the top level class of the configuration, which holds the settings for the various modes and provides some serialization utility methods.


[XmlRoot("Config")]
public class FilteredListConfiguration
{
    private List _modes = new List();

[XmlArray("Modes")] [XmlArrayItem("Mode")] public List Modes { get { return _modes; } set { _modes = value; } }

public FilteredListMode this[string modeName] { get { return _modes.Find( delegate(FilteredListMode mode) { return mode.Mode.Equals(modeName, StringComparison.InvariantCultureIgnoreCase); }); } }

public string ToXml() { XmlSerializer serializer = new XmlSerializer(GetType());

using (StringWriter writer = new StringWriter()) { serializer.Serialize(writer, this); return writer.ToString(); } }

public static FilteredListConfiguration FromXml(string xml) { XmlSerializer serializer = new XmlSerializer(typeof (FilteredListConfiguration));

using (StringReader reader = new StringReader(xml)) { return serializer.Deserialize(reader) as FilteredListConfiguration; } }

public FilteredListMode CreateMode(string modeName) { FilteredListMode mode = new FilteredListMode(); mode.Mode = modeName; Modes.Add(mode);

return mode; } }


Edit

Usage

Add a property to the web part for storing the xml.



private FilteredListConfiguration _modesConfig;

[WebBrowsable(true), Personalizable(true), Browsable(true), Category("List"), WebPartStorage(Storage.Personal), FriendlyName("Modes Config"), Description("Configuration for the filtered fields")] public string ModesConfigXml { get { return ModesConfig.ToXml(); } set { try { ModesConfig = FilteredListConfiguration.FromXml(value); } catch (Exception) { } } }


And then when rendering the page you can add a method for enumerating over the fields.


private IEnumerable EnumerateFields(SPList list)
{
    bool isAuthor = IsAuthor();
    
    FilteredListMode modeConfig = ModesConfig[ControlMode.ToString()];

foreach (FilteredField filteredField in modeConfig.Fields) { bool isVisible = IsMatch(filteredField.IsVisible, isAuthor); bool isWriteable = IsMatch(filteredField.IsWriteable, isAuthor);

foreach (SPField field in list.Fields) { if (field.InternalName.Equals(filteredField.Name, StringComparison.InvariantCultureIgnoreCase)) { yield return new FieldToRender(field, isVisible, isWriteable); } } } }


Because we're looping through the filtered fields first, the results are ordered based on the order of the FilteredField elements in the configuraiton xml.

Edit

Configuration

You can either write the configuration by hand i.e.


<?xml version="1.0" encoding="utf-16"?>
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Modes>
    <Mode Mode="New">
      <Fields>
        <Field IsVisible="Always" IsWriteable="Always" Name="CreateOnlyField" />
        <Field IsVisible="Always" IsWriteable="Always" Name="Title" />
        <Field IsVisible="Always" IsWriteable="Always" Name="Description" />
      </Fields>
    </Mode>
    <Mode Mode="Edit">
      <Fields>
        <Field IsVisible="Always" IsWriteable="ToItemAuthor" Name="CreateOnlyField" />
        <Field IsVisible="Always" IsWriteable="Always" Name="Title" />
        <Field IsVisible="Always" IsWriteable="Always" Name="Description" />    
      </Fields>
    </Mode>
  </Modes>
</Config>



Or bootstrap it by writing a class to iterate over the existing fields and dump out a default configuration which can then serialize to XML etc. (or you could wire up the property on the web part to auto-generate the configuration when it's empty, if that's useful to you).


public class ListConfigurationBuilder
{
    public FilteredListConfiguration BuildFromList(SPList list)
    {
        FilteredListConfiguration configuration = new FilteredListConfiguration();

FilteredListMode newMode = configuration.CreateMode("New"); FilteredListMode editMode = configuration.CreateMode("Edit");

foreach (SPField field in list.Fields) { if (!IsHidden(field)) { if (!field.ShowInNewForm.HasValue || field.ShowInNewForm.Value) { newMode.CreateField(field.InternalName, Applies.Always, Applies.Always); } if (!field.ShowInEditForm.HasValue || field.ShowInEditForm.Value) { editMode.CreateField(field.InternalName, Applies.Always, Applies.Always); } } }

return configuration; }

private static bool IsHidden(SPField field) { return (field.Hidden || field.ReadOnlyField || field.Type == SPFieldType.Attachments); } }

ScrewTurn Wiki version 2.0.2. Some of the icons created by FamFamFam.