The requirement:

The metadata attached to an uploaded document is fairly complex, and users should not need to specify values manually. Instead the values should be set based on where the user clicked to upload the document.

 

**The solution: **

A custom field type is created that extends the out of box lookup field and reads values from the query string. Standard query string parameters will work well for adding list items, but not for uploads as the upload page will not pass values through to the edit form. For uploads we can add the same properties to the Source query string parameter, which is used to redirect after the item is saved. To do this properly you would need a custom script to set the source parameter, but it is easily tested by adding the parameters to the address bar before clicking the upload button on a standard list page.

 

To create a custom field type, you need at least two files on top of the standard solution package structure - an xml file with a name like fldtypes_LookupDefaultFromQuery.xml in 12\TEMPLATE\XML and a class that extends SPField.

 

The class itself is fairly simple - just extend SPFieldLookup to override SPFieldLookup. Only default value needs to be changed - we can use the existing edit controls for both the value and the field properties. The value to use will be the id of the item to select in the lookup. 

<font size="2"><span style="font-weight:bold;color:#800000;">using</span> System<span style="color:#800080;">;</span>
<span style="font-weight:bold;color:#800000;">using</span> System<span style="color:#808030;">.</span>Collections<span style="color:#808030;">.</span>Generic<span style="color:#800080;">;</span>
<span style="font-weight:bold;color:#800000;">using</span> System<span style="color:#808030;">.</span>Text<span style="color:#800080;">;</span>
<span style="font-weight:bold;color:#800000;">using</span> Microsoft<span style="color:#808030;">.</span>SharePoint<span style="color:#800080;">;</span>
<span style="font-weight:bold;color:#800000;">using</span> Microsoft<span style="color:#808030;">.</span>SharePoint<span style="color:#808030;">.</span>WebControls<span style="color:#800080;">;</span>
<span style="font-weight:bold;color:#800000;">using</span> System<span style="color:#808030;">.</span>Web<span style="color:#808030;">.</span>UI<span style="color:#800080;">;</span>
<span style="font-weight:bold;color:#800000;">using</span> System<span style="color:#808030;">.</span>Web<span style="color:#808030;">.</span>UI<span style="color:#808030;">.</span>WebControls<span style="color:#800080;">;</span>


<span style="font-weight:bold;color:#800000;">namespace</span> LookupFieldTypes
<span style="color:#800080;">{</span>
    <span style="font-weight:bold;color:#800000;">public</span> <span style="font-weight:bold;color:#800000;">class</span> LookupDefaultFromQuery <span style="color:#808030;">:</span> SPFieldLookup
    <span style="color:#800080;">{</span>

        <span style="font-weight:bold;color:#800000;">public</span> LookupDefaultFromQuery<span style="color:#808030;">(<br></br>		</span>SPFieldCollection fields<span style="color:#808030;">,</span> <br></br>		<span style="font-weight:bold;color:#800000;">string</span> fieldName<span style="color:#808030;">)</span>
            <span style="color:#808030;">:</span> <span style="font-weight:bold;color:#800000;">base</span><span style="color:#808030;">(</span>fields<span style="color:#808030;">,</span> fieldName<span style="color:#808030;">)</span>
        <span style="color:#800080;">{</span>
        <span style="color:#800080;">}</span>

        <span style="font-weight:bold;color:#800000;">public</span> LookupDefaultFromQuery<span style="color:#808030;">(<br></br>		</span>SPFieldCollection fields<span style="color:#808030;">,</span> <br></br>		<span style="font-weight:bold;color:#800000;">string</span> typeName<span style="color:#808030;">,</span> <br></br>		<span style="font-weight:bold;color:#800000;">string</span> displayName<span style="color:#808030;">)</span>
            <span style="color:#808030;">:</span> <span style="font-weight:bold;color:#800000;">base</span><span style="color:#808030;">(</span>fields<span style="color:#808030;">,</span> typeName<span style="color:#808030;">,</span> displayName<span style="color:#808030;">)</span>
        <span style="color:#800080;">{</span>
        <span style="color:#800080;">}</span>

        <span style="font-weight:bold;color:#800000;">public</span> <span style="font-weight:bold;color:#800000;">override</span> <span style="font-weight:bold;color:#800000;">string</span> DefaultValue
        <span style="color:#800080;">{</span>
            get
            <span style="color:#800080;">{</span>
                <span style="font-weight:bold;color:#800000;">try</span>
                <span style="color:#800080;">{</span>
                    System<span style="color:#808030;">.</span>Collections<span style="color:#808030;">.</span>Specialized<span style="color:#808030;">.</span>NameValueCollection qs <span style="color:#808030;">=</span> <br></br>			System<span style="color:#808030;">.</span>Web<span style="color:#808030;">.</span>HttpContext<span style="color:#808030;">.</span>Current<span style="color:#808030;">.</span>Request<span style="color:#808030;">.</span>QueryString<span style="color:#800080;">;</span>

                    <span style="color:#696969;">// First look for the value in the page query string</span>
                    <span style="font-weight:bold;color:#800000;">string</span> dv <span style="color:#808030;">=</span> qs<span style="color:#808030;">[</span><span style="color:#800000;">"</span><span style="color:#0000e6;">Selected</span><span style="color:#800000;">"</span> <span style="color:#808030;">+</span> <span style="font-weight:bold;color:#800000;">this</span><span style="color:#808030;">.</span>InternalName<span style="color:#808030;">]</span><span style="color:#800080;">;</span>
                    <span style="font-weight:bold;color:#800000;">if</span> <span style="color:#808030;">(</span><span style="color:#808030;">!</span><span style="font-weight:bold;color:#800000;">string</span><span style="color:#808030;">.</span>IsNullOrEmpty<span style="color:#808030;">(</span>dv<span style="color:#808030;">)</span><span style="color:#808030;">)</span>
                    <span style="color:#800080;">{</span>
                        <span style="font-weight:bold;color:#800000;">return</span> dv<span style="color:#800080;">;</span>
                    <span style="color:#800080;">}</span>

                    <span style="color:#696969;">// if the value wasn't found, try the source url                   </span>
                    <span style="font-weight:bold;color:#800000;">string</span> source <span style="color:#808030;">=</span> qs<span style="color:#808030;">[</span><span style="color:#800000;">"</span><span style="color:#0000e6;">Source</span><span style="color:#800000;">"</span><span style="color:#808030;">]</span><span style="color:#800080;">;</span>

                    Uri uri <span style="color:#808030;">=</span> <span style="font-weight:bold;color:#800000;">new</span> Uri<span style="color:#808030;">(</span>source<span style="color:#808030;">)</span><span style="color:#800080;">;</span>
                    <span style="font-weight:bold;color:#800000;">return</span> System<span style="color:#808030;">.</span>Web<span style="color:#808030;">.</span>HttpUtility<span style="color:#808030;">.</span>ParseQueryString<span style="color:#808030;">(</span>uri<span style="color:#808030;">.</span>Query<span style="color:#808030;">)<br></br>			</span><span style="color:#808030;">[</span><span style="color:#800000;">"</span><span style="color:#0000e6;">Selected</span><span style="color:#800000;">"</span> <span style="color:#808030;">+</span> <span style="font-weight:bold;color:#800000;">this</span><span style="color:#808030;">.</span>InternalName<span style="color:#808030;">]</span><span style="color:#800080;">;</span>
                <span style="color:#800080;">}</span>
                <span style="font-weight:bold;color:#800000;">catch</span> <span style="color:#808030;">(</span>Exception ex<span style="color:#808030;">)</span>
                <span style="color:#800080;">{</span>
                    <span style="font-weight:bold;color:#800000;">return</span> <span style="font-weight:bold;color:#800000;">base</span><span style="color:#808030;">.</span>DefaultValue<span style="color:#800080;">;</span>
                <span style="color:#800080;">}</span>

            <span style="color:#800080;">}</span>
            set
            <span style="color:#800080;">{</span>
                <span style="font-weight:bold;color:#800000;">base</span><span style="color:#808030;">.</span>DefaultValue <span style="color:#808030;">=</span> value<span style="color:#800080;">;</span>
            <span style="color:#800080;">}</span>
        <span style="color:#800080;">}</span>



    <span style="color:#800080;">}</span>

<span style="color:#800080;">}</span>
</font>

The xml file is a little harder to get right, since there is no useful documentation available and copying any of the out of box fieldtype declarations from fldtypes.xml doesn’t work. Bits that seem to be particularly important:

  • FieldTypeClass needs to point to the custom class above. Even if that class doesn’t override anything from the base class, specifying SPFieldLookup as the out of box lookup field does will not work. It even stops the standard lookup field from working properly.

  • FieldEditorUserControl is the control that appears when creating a new field. The out of box control can be used, although there are issues around switching to multiple selection that aren’t handled by this code.

  • SQLType needs to be int to store the id. Various things break if it isn’t specified.

  • InternalType is what allows the LookupColumn and URL cmd=”Lookup” elements in the renderpatterns to work properly.

  • RenderPattern elements are copied from the Lookup field type in fldtypes.xml and are excluded from this post because they are really long and complex. You can make changes to them if you want, but the only documentation I have seen is the view schema at http://msdn2.microsoft.com/en-us/library/ms439798.aspx, which is only slightly helpful.

 

      LookupDefaultFromQuery     LookupDefaultFromQuery     Lookup with default value from query string     TRUE     LookupFieldTypes.LookupDefaultFromQuery, LookupFieldTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5296a18ab0247d05     /_controltemplates/LookupFieldEditor.ascx     int     Lookup     TRUE     TRUE     ...