none
Custom Field Type Properties

    Pertanyaan

  • Hi,

    I have created a custom field type for SharePoint that represents hierachical data from and XML file (stored in SharePoint) in a TreeView.

    I have created properties on the field to store the location of the source XML file and whether to render the TreeView as a multi-select, ie. with checkboxes.

    I created the properties in the _fldtypes xml definition using the property schema elements as they are only simple textboxes and checkboxes. My problem is that these properties work ok to add the form and save, but when you try and edit the field, the values in the properties reset to <field description> value. ie. they are not what was set and they are not even the default!

    This is supposed to be out of the box stuff according to the SDK, but does not seem to work. The SDK is pretty thin when it comes to this stuff. Does anyone have any ideas, or have this working?

    Thanks.

    Aaron.

    15 Januari 2007 3:33

Jawaban

  • Hi, Aaron

     

    You are right – custom property value is not set, when the new field is created. I’ve missed this point somehow while developing my workaround. Sorry for that.

     

    I’ve investigated it, and came to the following conclusions:

    1)     Update method is not called, when new custom field item is created. Only OnAdded method is firing.

    2)      We can not solve this problem, by just including something like:

          public override void OnAdded(SPAddFieldOptions op)

          {

                base.OnAdded(op);

                Update();

    }

    in our custom field type class. SharePoint calls OnSaveChange(SPField field, bool isNew) in our custom control, providing field object, but before saving it creates the new one! That’s why custom property values will be lost.

     

    So we need to save our custom property values between object instances. This may be achieved in 2 ways: storing value in session or in some static member. I’ve chosen the second approach, because we should take in mind, that user may change custom properties of our field not only using web interface, but from API as well. In this case, I think, Session object will not be available. In addition, we should take in mind that multiple users (or multiple connections for one user) may try to modify fields of the same type across the site simultaneously. That’s why we can’t just store our custom property value in static member, but we should create static Dictionary of values, and use some Identity for each connection. I’ve chosen to use current context object hash code as identity: SPContext.Current.GetHashCode().

    In addition, I think, we should avoid always storing value in static member, cause it just gives us additional head ache – how to determine when the value is not used any more, and remove it from our static member? If we won’t do it, we will create a memory leak.

     

    So we need to modify our code like:

     

    public class MyCustomField : SPFieldText

    {

          public MyCustomField(SPFieldCollection fields, string fieldName)

                : base(fields, fieldName)

          {

                this.Init();

          }

          public MyCustomField(SPFieldCollection fields, string typeName, string displayName)

                : base(fields, typeName, displayName)

          {

                this.Init();

          }

          private void Init()

          {

                this.MyCustomProperty = this.GetCustomProperty("MyCustomProperty")+"";

          }

          private static Dictionary<int, string> updatedMyCustomProperty = new Dictionary<int, string>();

          private string myCustomProperty;

          public string MyCustomProperty

          {

                get

                {

                      return updatedMyCustomProperty.ContainsKey(ContextId) ? updatedMyCustomProperty[ContextId] : myCustomProperty;

                }

                set

                {

                      this.myCustomProperty = value;

                }

          }

          public void UpdateMyCustomProperty(string value)

          {

                updatedMyCustomProperty[ContextId] = value;

          }

          public int ContextId

          {

                get

                {

                      return SPContext.Current.GetHashCode();

                }

          }

          public override void Update()

          {

                this.SetCustomProperty("MyCustomProperty", this.MyCustomProperty);

                base.Update();

                if(updatedMyCustomProperty.ContainsKey(ContextId))

                      updatedMyCustomProperty.Remove(ContextId);

          }

          public override void OnAdded(SPAddFieldOptions op)

          {

                base.OnAdded(op);

                Update();

          }

    }

     

    public class SelectMyCustomProperty : UserControl, IFieldEditor

    {

          /* ... */

         

          public void OnSaveChange(SPField field, bool isNew)

          {

                string value = this.ctlMyCustomProperty.SelectedValue;

                MyCustomField myField = field as MyCustomField;

                if(isNew)

                      myField.UpdateMyCustomProperty(value);

                else

                      myField.MyCustomProperty = value;

          }

         

          /* ... */

    }

     

     

    Hope this helps!

     

    Anton

    13 Februari 2007 9:46

Semua Balasan

  • Hi, Aaron,

     

    I was investigating the same issue for some time, and found a workaround, using custom control, to render field properties. I’ll try to describe my solution step-by-step.

     

    1. Create your field definition in FLDTYPES_xxx.XML file, and add FieldEditorUserControl property to your custom field definition. Define fields for all custom properties of your custom field definition in PropertySchema section. If you don’t define some property here, you are not able to set it’s value using field.SetCustomProperty(“fieldname”) later. Looks like WSS just ignores it. In addition, you should set Hidden attribute of all Field elements in PropertySchema section to True. Otherwise, fields will be rendered in user interface.

    For example, my custom property definition looks like:

        <FieldType>

            <Field Name="TypeName">MyCustomField</Field>

            <Field Name="TypeDisplayName">My Custom Field</Field>

                 <Field Name="ParentType">Text</Field>

                 <Field Name="FieldTypeClass">MyFields.MyCustomField, MyFields, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3bf8ec1b42660c3</Field>

            <Field Name="Sortable">TRUE</Field>

            <Field Name="Filterable">TRUE</Field>

                 <Field Name="FieldEditorUserControl">/_controltemplates/MyCustomFieldControl.ascx</Field>

                 <PropertySchema>

                        <Fields>

                               <Field Name="MyCustomProperty" DisplayName="My Custom Property"

                                 Type="Text" Hidden="TRUE">

                               </Field>

                        </Fields>

                 </PropertySchema>

     

    ...

    <!--RenderPatterns -->

        </FieldType>

     

     

    2. The next step is to create .ascx control file in TEMPLATE\CONTROLTEMPLATES directory. In my sample it’s MyCustomFieldControl.ascx. My control is very simple:

     

    <%@ Control Language="C#" Inherits="MyFields.SelectMyCustomProperty,MyFields, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3bf8ec1b42660c3"   AutoEventWireup="false" compilationMode="Always" %>

    <%@ Register TagPrefix="wssuc" TagName="InputFormControl" src="~/_controltemplates/InputFormControl.ascx" %>

    <%@ Register TagPrefix="wssuc" TagName="InputFormSection" src="~/_controltemplates/InputFormSection.ascx" %>

    <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %>

     

    <wssuc:InputFormSection runat="server" id="MySections" Title="My Custom Section">

           <Template_InputFormControls>

                 <wssuc:InputFormControl runat="server"

                        LabelText="My Custom Property">

                        <Template_Control>

                               <asp:DropDownList id="ctlMyCustomProperty" runat="server">

                               </asp:DropDownList>

                        </Template_Control>

                 </wssuc:InputFormControl>

           </Template_InputFormControls>

    </wssuc:InputFormSection>

     

    As you can see, it has only one drop-down control. The idea is, that user can select some value from drop-down, and it’ll be stored in custom property of our custom field.

     

    3. Now you should create .NET classes for your custom field type and user control. For custom field type:

           public class MyCustomField : SPFieldText

           {

                 public MyCustomField(SPFieldCollection fields, string fieldName)

                        : base(fields, fieldName)

                 {

                        this.Init();

                 }

     

                 public MyCustomField(SPFieldCollection fields, string typeName, string displayName)

                        : base(fields, typeName, displayName)

                 {

                        this.Init();

                 }

     

                 private void Init()

                 {

                        this.MyCustomProperty = this.GetCustomProperty("MyCustomProperty")+"";

                 }

                

                 private string myCustomProperty;

                 public string MyCustomProperty

                 {

                        get

                        {

                               return this.myCustomProperty;

                        }

                        set

                        {

                               this.myCustomProperty = value;

                        }

                 }

     

                 public override void Update()

                 {

                        this.SetCustomProperty("MyCustomProperty", this.MyCustomProperty);

                        base.Update();

                 }

           }

     

    As you can see, I’ve created string attribute and property, for my field type’s CustomProperty. In Init method, I populate it with stored custom property value. Finally, I’ve overridden Update method, to save modified custom property values to the field. I’ll describe what’s happening in WSS during field update and why all of these steps are necessary a bit later. 

    The code for my user control:

     

           public class SelectMyCustomProperty : UserControl, IFieldEditor

           {

                 protected DropDownList ctlMyCustomProperty;

                 private string value = "";

     

                 public void InitializeWithField(SPField field)

                 {

                        MyCustomField myField = field as MyCustomField;

                        if(myField != null)

                               this.value = myField.MyCustomProperty+"";

                 }

                 public void OnSaveChange(SPField field, bool isNew)

                 {

                        string value = this.ctlMyCustomProperty.SelectedValue;

                        MyCustomField myField = field as MyCustomField;

                        myField.MyCustomProperty = value;

                 }

                 public bool DisplayAsNewSection

                 {

                        get

                        {

                               return true;

                        }

                 }

     

                 protected override void CreateChildControls()

                 {

                        base.CreateChildControls();

                       

                        // load values

                        ctlMyCustomProperty.Items.Add("");

                        ctlMyCustomProperty.Items.Add("aaa");

                        ctlMyCustomProperty.Items.Add("bbb");

                        ctlMyCustomProperty.Items.Add("ccc");

                       

                        if(!this.IsPostBack)

                        {

                               ListItem item = ctlMyCustomProperty.Items.FindByText(this.value);

                               if(item != null)

                                      item.Selected = true;

                        }

                 }

           }

     

    As described in SDK user control class should implement IFieldEditor interface. It has 2 methods and 1 property:

    InitializeWithField – is called, when control is initialized;

    OnSaveChanged – called, when user clicks OK button in field properties window;

    DisplayAsNewSection – true if control should be displayed as new section in field properties form.

     

    In CreateChildControls we just populate our drop-down list with some values.

     

    The crucial point here is, not to try setting values directly to custom properties in OnSaveChange (like, myField.SetCustomProperty(“MyCustomProperty”, value)). Even if you call myField.Update() afterwards, the value won’t be saved! More precisely, it will be saved, but then it will be overwritten by current custom property value. Looks like SharePoint calls OnSaveChange in our control, then continues to update values of custom properties from other sources (and our Hidden field in PropertySchema section is one of them), and finally calls field’s Update method. That’s why we need to override Update method in our custom field class and set custom property values there – at that point SharePoint has done his job, and won’t change any property values.

     

    Hope this helps!

     

    Best regards,

    Anton

     

    • Disarankan sebagai Jawaban oleh Om Rahul 11 Juli 2012 13:53
    02 Februari 2007 2:21
  • That all sounds pretty good to me!

    I had a go with onSaveChanges and came to a similar conclusion to you about the update firing after and nuking the props!

    I will try this method out as soon as I can!

    Thanks again!

    02 Februari 2007 6:29
  • Anton,

    I have tried your code and found that it allows me to edit and re-save the properties ok, but that it does not set the property when the field is first created. The overridden Update method does not get called when adding a new field.

    Can you confirm that this behaviour is the same for you in case I have managed to break something in my copying of it?

    Thanks!

    09 Februari 2007 4:41
  • Aaron,

    I have tried this and can confirm the behaviour you're describing. The overriden Update only get called when editing a field and not when it's created.
    /Johan Smidje

    09 Februari 2007 13:10
  • Hi, Aaron

     

    You are right – custom property value is not set, when the new field is created. I’ve missed this point somehow while developing my workaround. Sorry for that.

     

    I’ve investigated it, and came to the following conclusions:

    1)     Update method is not called, when new custom field item is created. Only OnAdded method is firing.

    2)      We can not solve this problem, by just including something like:

          public override void OnAdded(SPAddFieldOptions op)

          {

                base.OnAdded(op);

                Update();

    }

    in our custom field type class. SharePoint calls OnSaveChange(SPField field, bool isNew) in our custom control, providing field object, but before saving it creates the new one! That’s why custom property values will be lost.

     

    So we need to save our custom property values between object instances. This may be achieved in 2 ways: storing value in session or in some static member. I’ve chosen the second approach, because we should take in mind, that user may change custom properties of our field not only using web interface, but from API as well. In this case, I think, Session object will not be available. In addition, we should take in mind that multiple users (or multiple connections for one user) may try to modify fields of the same type across the site simultaneously. That’s why we can’t just store our custom property value in static member, but we should create static Dictionary of values, and use some Identity for each connection. I’ve chosen to use current context object hash code as identity: SPContext.Current.GetHashCode().

    In addition, I think, we should avoid always storing value in static member, cause it just gives us additional head ache – how to determine when the value is not used any more, and remove it from our static member? If we won’t do it, we will create a memory leak.

     

    So we need to modify our code like:

     

    public class MyCustomField : SPFieldText

    {

          public MyCustomField(SPFieldCollection fields, string fieldName)

                : base(fields, fieldName)

          {

                this.Init();

          }

          public MyCustomField(SPFieldCollection fields, string typeName, string displayName)

                : base(fields, typeName, displayName)

          {

                this.Init();

          }

          private void Init()

          {

                this.MyCustomProperty = this.GetCustomProperty("MyCustomProperty")+"";

          }

          private static Dictionary<int, string> updatedMyCustomProperty = new Dictionary<int, string>();

          private string myCustomProperty;

          public string MyCustomProperty

          {

                get

                {

                      return updatedMyCustomProperty.ContainsKey(ContextId) ? updatedMyCustomProperty[ContextId] : myCustomProperty;

                }

                set

                {

                      this.myCustomProperty = value;

                }

          }

          public void UpdateMyCustomProperty(string value)

          {

                updatedMyCustomProperty[ContextId] = value;

          }

          public int ContextId

          {

                get

                {

                      return SPContext.Current.GetHashCode();

                }

          }

          public override void Update()

          {

                this.SetCustomProperty("MyCustomProperty", this.MyCustomProperty);

                base.Update();

                if(updatedMyCustomProperty.ContainsKey(ContextId))

                      updatedMyCustomProperty.Remove(ContextId);

          }

          public override void OnAdded(SPAddFieldOptions op)

          {

                base.OnAdded(op);

                Update();

          }

    }

     

    public class SelectMyCustomProperty : UserControl, IFieldEditor

    {

          /* ... */

         

          public void OnSaveChange(SPField field, bool isNew)

          {

                string value = this.ctlMyCustomProperty.SelectedValue;

                MyCustomField myField = field as MyCustomField;

                if(isNew)

                      myField.UpdateMyCustomProperty(value);

                else

                      myField.MyCustomProperty = value;

          }

         

          /* ... */

    }

     

     

    Hope this helps!

     

    Anton

    13 Februari 2007 9:46
  • Hi Anton,

    very helpful! You might what to do a blog post about it, since i have seen several others asking about this (myself included:-)

    have you reported this to MS as a bug? It does seem like alot of hazzle for something that ought to work OOTB?

    Aron/Anton

    i have also created a treeview custom field type (gets populated with the Site provider the user selects when creating field). However i ran into some weird limitations: even though i inherit directly from SPField, i cannot select items that add up to more than 255 chars. This has something to do with the way i store the selected nodes (custom ToString method that seperates selections with ;# just like SPFieldMultiChoice and SPFieldMultiColumn).

    I tried all sorts of workarounds like selecting Note as display field in xml file, but this only stops wss from throwing an exception and then cuts the output at 255 chars. I know this can be done as other fields can display alot more than 255 chars (like SOFieldMultiChoice that displays +7000 chars as limited in UI).

    Have anyone got a workaround for this?

    My post about this issue

    thx

    AndersR

    27 Februari 2007 9:16
  • Hi Antons,

    I am using this article to create a custom dropdown field which will populate values from the database. I should be able to select any value from this dropdown custom field and depending on selection another set of values should come from the database which will be again another custom dropdown Field.

    When i am following this article none of the values are populated in my custom dropdown field.even it is not diplaying values that i add manually.

    Can you please suggest me some workaround for this ?

    As it is urgent and inevitable for my sharepoint portal

     

     

     

    07 Maret 2007 8:19
  • Hi Smruti,

     

    As I understand from your post, this solution is very similar, to the one, described in my sample. The only difference is that there will be two drop-downs in your custom field control, and values will be filled in from database. So, I think, you’ve just missed some part of my implementation. Please, review your code carefully and compare it to mine – may be you will find the missing bit.

     

    If it still doesn’t work, feel free to post some simplified code sample of your solution here. It will help to understand this issue.

     

    Best regards,

    Anton

    09 Maret 2007 0:01
  • Hi Anton

    Thanks for your response.Actually i managed to create a custom field which has a dropdown list ,t hat is fetching data from a database in SQL server.

    Now i need to implement another custom field having a dropdown list which is dependent on the value selected in the first custom field's dropdown.

    Please suggest me how to proceed .Got really stuck up in this .

    Regards

    Smruti

     

     

     

    09 Maret 2007 6:32
  • I don't understand, why we can not do like this:

    internal string ValueColumn
    {
      get { return GetCustomProperty("valueColumn").ToString(); 
      set { SetCustomProperty("valueColumn", value); }
    }

    16 Maret 2007 9:15
  •  

    Hi Anton

    Thanks for your response.Actually i managed to create a custom field which has a dropdown list ,t hat is fetching data from a database in SQL server.

    Now i need to implement another custom field having a dropdown list which is dependent on the value selected in the first custom field's dropdown.

    Please suggest me how to proceed .Got really stuck up in this .

    Regards

    Smruti

    21 Maret 2007 15:55
  • I just built this exact solution.  Thanks to Anton's code for much help!

    My solution has a dropdown available when the user creates a column (which reads values for names describing sql queries).

    Example: If user chooses "Departments" then at runtime the dropdown will be populated by a sql query which retrieve department names.  If the user chooses "products" then at runtime a sql query will run displaying the list of products etc....

    Nothing else tricky except in CreateChildControls you retrieve the value from the hidden property defined in the XML file and use that value to populate the dropdown

    protected override void CreateChildControls()

    {

    if (Field == null) return;

    base.CreateChildControls();

    if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display)

    return;

    cboData = (DropDownList)TemplateContainer.FindControl("cboData");

    if (cboData == null)

    {

    throw new ArgumentException("cboData is null. Corrupted SQLDropdownFieldControl.ascx file.");

    }

    if (!Page.IsPostBack)

    {

    try

    {

    string ddtype = Field.GetCustomProperty("DropdownType").ToString();

    Common.FillCombobox(cboData, ddtype);

    }

    catch (Exception ex)

    {

    //we need to do something here, I am not sure what the best pratice is though.

    }

    }

    }

    }

    26 Maret 2007 21:01
  • Dear Mark , Anton

     

    Thanks for the solution.

    I was able to create dependent listboxes in my custom fieldtypes.

    I have now created around 15 custom fieldtypes.

    So when i go to a list or document library and say Create column

    It is showing me 15 custom fieldtypes apart from ( default ones from Sharepoint such as Single line of text, choice,multiple lines of text ..etc )

     

    So now my problem is i want to group all my custom fieldtypes under one fieldtype and lets say name it as My Custom Field type which should appear in create column page and when i select it , it should populate all my 15 custom field types in form of radio buttons..from which i should select and create my column in a list or a document library.

    03 April 2007 10:22
  • I'm trying to create a field type which will have the link to another page by default and I need to get the current Item context and pass the item ID as query string. I can get the list ID by this.ParentList.id but how do I get the List Item Id? Please help.

     

    Thanks!

    18 Mei 2007 15:37
  • this article is of great help to all of us.

    thanks to anton

     

    cheers

    21 Mei 2007 10:12
  • Anton,

     

    I finally got around to testing you code that stores the property values in the static dictionary based on session hash and it works very nicely.

     

    It took me a while to get over the 'why doesn't it work properly' factor, but now that I have a work around I'm very happy.

     

    Thanks for your help!

     

    Aaron.

    25 Mei 2007 0:37
  • Hi,

    I've followed the workaround and it seems to work.

    However, I'm not sure the tricks that use a static dictionnary will work on some configuration.
    Since the sharepoint process can work into separate processes (w3wp.exe) because of the configuration of the app pool (web garden, number of processes) or even in a server farm, the static member won't have "global" application scope.

    In this case, we cannot use neither application variables for the same reasons nor session variable because of the per user scope.

    Do you have any other way to work around ?

    At last, is this behaviour a MS bug ?
    01 Juni 2007 9:24
  •  

    Thanks Anton and Aaron,

     

    I used your ideas to create a custom filtered lookup field. It worked great except that when the 'Allow Multiple Values' property was set, the base SPFieldLookup class would internally reset the field type to the stock LookupMulti and bypass my assembly. To get past this I overrode the AllowMultipleValues property of the SPFieldLookup class and then also overrode the Update and OnAdded methods to insert the necessary XML attributes into the schemaXML for my custom field. Here's ths code:

     

    /**********************************************/

    /// <summary>

    // override SPFieldLookup property

    // so that it does not change the field type

    /// <summary>

    public override bool AllowMultipleValues

    {

      get

      {

        return bAllowMulti;

      }

      set

      {

        bAllowMulti = value;

      }

    }

    /**********************************************/

    /// <summary>

    // override update method to modify the field type XML

    /// </summary>

    public override void Update()

    {

      this.SetCustomProperty("FilterColumn", FilterColumn);

      this.SetCustomProperty("FilterValue", FilterValue);

      this.SetCustomProperty("AllowMultipleValues", AllowMultipleValues );

      base.Update();

      if( AllowMultipleValues )

      {

        String xml = this.SchemaXml;

        if( xml.IndexOf("Mult=")< 0 )

        {

          // this call instantly updates the database

          this.SchemaXml = xml.Insert(6, @" Mult=""TRUE"" Sortable=""FALSE"" ");

        }

      }

    }

    /**********************************************/

    /// <summary>

    // override the OnAdded method to call Update

    // because Update is not called when creating new fields

    /// </summary>

    public override void OnAdded( SPAddFieldOptions options )

    {

      //need to refetch the custom properties

      this.GetCustomProps();

      base.OnAdded(options);

      Update();

    }

     

    Everything is working smoothly, except I have not been able to figure out how to get this custom field to render correctly in the Datasheet view (requires Office 2003,2007). The values just show up as a string of delimited text. Yet if I create a regular Lookup field the Datasheet shows either a dropdown or a setof checkboxes(multiple values).

     

    I haven't been able to find out much about rendering custom fields in the Datsheet view. With the debugger attached, my custom field assembly never gets referenced when being displayed/edited in the Datasheet view. Maybe the Datasheet view is dealing directly with the database...

     

    If anyone knows anything about rendering custom fields in a Datasheet view, I'd sure like to hear about it.

     

    Larry

     

    02 Juni 2007 7:44
  • Steve,

     

    Do you have any other way to work around ?

     

    I don't.


      At last, is this behaviour a MS bug ?

     

    Personally, I think it is. But the Business Data column type in MOSS works, so I have been trying to follow the Business Data column type through .Net Reflector to see if I can figure out how they do it. If I can figure it out I will post...


    03 Juni 2007 23:01
  • A previous post of mine (shameful plug?) notes the problems I had with getting the above code to work on my own SharePoint installation.  Most notably is the problems I had with GetCustomProperty and SetCustomProperty.  Microsoft's own field types don't seem to use these methods, but instead use an internal method to get/set properties of the column.

     

    I could call this a bug, but then again we all don't seem to have a complete picture as to how SharePoint deals with custom field types.

    05 Juni 2007 20:14
  •  Brian Abram wrote:
     

    I could call this a bug, but then again we all don't seem to have a complete picture as to how SharePoint deals with custom field types.

     

    I tend to agree, we don't really know 100% what the picture is mostly because the SDK is so incomplete in this area. However, it's pretty hard to see why the SetCustomProperties shouldn't just work!

     

    Except of course when you debug and see how many times field objects are instantiated in the save/create/edit process!

     

    The only other option for keeping hold of the property settings alive is to put them in a property bag for the web/list/site. Not very nice at all because if the field fails to survive the save, then you end up with property data that never gets nuked, but it is a thought...

     

     

    06 Juni 2007 4:53
  • Microsoft has noted that this behavior constitutes a bug.  They have a 'hotfix', but aren't releasing it to the general public.  Their claim, apparently, is to wait until a service pack is released for WSS 3.0.

     

    http://support.microsoft.com/kb/932055

     

    07 Juni 2007 16:38
  •  

    Hello,

     

    I followed the tutorial http://msdn2.microsoft.com/en-us/library/bb684919.aspx that explain how to create a custom field type with a listbox.

     

    It works greate excepting when I try to edit my list with this field in DataSheet view. The field is rendered in a textbox instead of with a listbox like in the add and edit form.

     

    How to display this custom field in the datasheet view with a dropdownlist for example ?

     

    PS : could someone give an example of a custom field with a listbox of LoopUp field value please ?

     

    Thanks in advance.

    10 Agustus 2007 10:27
  • I created a custom field type and modified it as your direction. But it could not save custom properties values while creating a new column and updating column. I think, there is a stupid mistake but i cannot imagine it Sad

     

    <FieldTypes>
      <FieldType>
        <Field Name="TypeName">SPFieldSecureableTextField</Field>
        <Field Name="TypeDisplayName">Securable Text Field</Field>
        <Field Name="TypeShortDescription">Securable Text Field</Field>
        <Field Name="ParentType">Text</Field>
        <Field Name="FieldTypeClass">SPFieldSecureableText.SPFieldSecureableTextField, YuBiS.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5</Field>


        <PropertySchema>
          <Fields>
            <Field Name="SecurityGroups" DisplayName="Security Definitions" Type="Text">
     </Field>
          </Fields>
        </PropertySchema>

      </FieldType>
    </FieldTypes>

     

    [CLSCompliant(false)]

    [Guid("cdb00063-5b00-40fb-b1f6-f1671bf27a7e")]

    public class SPFieldSecureableTextField : SPFieldText

    {

    public SPFieldSecureableTextField(SPFieldCollection fields, string fieldName)

    : base(fields, fieldName)

    {

    this.Init();

    }

    public SPFieldSecureableTextField(SPFieldCollection fields, string typeName, string displayName)

    : base(fields, typeName, displayName)

    {

    this.Init();

    }

    private void Init()

    {

    this.SecurityGroups = this.GetCustomProperty("SecurityGroups") + "";

    }

    private static Dictionary<int, string> updatedSecurityGroups = new Dictionary<int, string>();

    private string securityGroups;

    public string SecurityGroups

    {

    get

    {

    if (updatedSecurityGroups.ContainsKey(ContextId))

    {

    return updatedSecurityGroups[ContextId];

    }

    else

    {

    return securityGroups;

    }

    }

    set

    {

    this.securityGroups = value;

    }

    }

     

    public void UpdateSecurityGroups(string value)

    {

    updatedSecurityGroups[ContextId] = value;

    }

    public int ContextId

    {

    get

    {

    return SPContext.Current.GetHashCode();

    }

    }

    public override void Update()

    {

    this.SetCustomProperty("SecurityGroups", this.SecurityGroups);

    base.Update();

    if (updatedSecurityGroups.ContainsKey(ContextId))

    updatedSecurityGroups.Remove(ContextId);

    }

    public override void OnAdded(SPAddFieldOptions op)

    {

    base.OnAdded(op);

    Update();

    }

    }

    12 Agustus 2007 10:51
  • Ugur,

     

    Given it looks to me like you only have one property, which is defined in the fieldtype XML and does not require a custom property control for editing, you should be able to implement the property without all the dictionary stuff.

     

    If you look up a couple of posts you will see a reference to a hotfix which will mean you can define the field in the XML and use the SDK samples to do the rest - ie. no tricky static dictionary and context checking etc.

     

    Aaron.

    12 Agustus 2007 23:16
  •  

    I have created custom field types, it was working fine.

    When I have done extenstive testing, I have found unusual code behaviour.

     

    For one field name (column name) code is working fine and for other field name is was not workign fine.

    I have debug the code for both behaviour.

    For not working field name the

    public override void Update() method is called twice first time directly and it was showing all the property configuration values it it. for second time it was called by following method and this time values are overwritten with "".

    public override void OnAdded(SPAddFieldOptions op)
            {
                base.OnAdded(op);
                Update();
            }

    For  working field name the

    public override void Update()  method is called single time and that is from above OnAdded method. and it was working fine.

     

    is it realed due to the Static Directory bug??.

    single hint wil help me a lot.

     

    Thanks

     

    20 Agustus 2007 15:42
  • Hey Anton,

     

    Your solution, to show property values in edit field page, pretty good sounds to me.

    My question is, is it the only way to perform it (editing and resaving the property values)? Can't we achieve this functionality using PropertySchema? Why I am saying so because in my case I have a simple text box as property and to edit and re-save it I will have to create a new user control which is not good as per Microsoft (Please see http://msdn2.microsoft.com/en-us/library/ms472859.aspx)

     

    We should create field editor user control only when our property is a complex control and having a complex logic. If it's a simple control e.g. text box, check box etc., we should go for PropertySchema, but in that case how to show property values in edit field page?

     

    One more question: How can I make property mandatory (through PropertySchema)? I want user to give value in property text box, if leaves blank, there should be error message.

     

    Thanks.

     

    Ashish

     

    22 Agustus 2007 9:33
  • Anton & all,

    I am a bit new at this. I have the need to create some custom field types and field properties.

    I have successfully developed some simple custom field types that use the PropertySchema and CAML to define the custom properties.

    Now I need to push the envelope a bit and design a custom ASCX control like MyCustomFieldControl.ascx to host my more elaborate custom properties (with the hidden propertyschema fields). My problem is that I can't seem to load that file in Visual Studio 2005 and get it to correctly recognize the ~/controltemplate location and also the
    Template_InputFormControls for example.

    How can I get VS to accept the ASCX file without errors and to allow me to use the design mode view to actually design my control?

    I have searched everywhere for this kind of solution. Either nothing is mentioned or it seems that these ASCX files are crafted by hand. Am I missing something?

    Thanks
    Alain
    12 September 2007 3:39
  •  

    Hi,

    Did you manage to fix the edit in datasheet problem?

    Thanks,

    Dan

    13 September 2007 9:50
  • Anton.

     

    I have created a custom field by inheriting the “SPFIELDUSER”,

    It is working fine when adding and editing. But when displaying in “AllItems.aspx” page, it showing the value as 1;#  and 2;#  ...

    Please give me advice, how I can specify the display pattern for this.

     

    Thanks,

    Andamuthu K

     

    18 September 2007 11:07
  • Hi Andamuthu,

     

    While rendering lists in AllItems.aspx SharePoint is not instantiating .NET object, which you’ve created for your custom field. It uses only current value of the field (stored in database), and rendering patterns from schema xml file of the field. Probably you have not copied the whole rendering patterns part of the field, you are inheriting from to the schema definition of your custom field. XML schema of the SPFieldUser field could be found in %CommonProgramFiles% \Microsoft Shared\web server extensions\12\TEMPLATE\XML\FLDTYPES.XML. Search for the type named User in this file, and copy all RenderPattern nodes from its schema, to the xml file of your custom field.

     

    Hope this helps!

     

    23 September 2007 0:47
  • Hi Anton,

    Thank you for the great article. Really helped me to solve my problem. But I have a doubt. When I create a custom field two addional properties are coming which are Description and Require that this column contains information. When I set the  Require that this column contains information, Sharepoint is ignoring that selection. Evevn if I set the field Require, user can still skip adding data to the field. How can I make this working?

    thank you

    Arun Dutt
    26 September 2007 13:40
  • Hi Arun,

    As I understand, you are probably talking about creating a site column and not a custom field type, because I think there are no such properties for a field type.

    Required property of a site column could be overridden in a content type, where this column is used. That’s why in one content type it can still be required, and in the other – not. When you create site columns and content types via SharePoint interface, by default content types inherit required property value of a site column. However, when you deploy site columns and content types in which they are used with a feature, the default behavior differs – you should always specify is this field required our not in a FieldRef tag of a content type definition.

    For example, if you have a site column:

    <Field

    ID="{292184DD-5C7D-403c-AFE2-7880766C1876}"

          Type="Text"

          Name="MyField"

          DisplayName="MyField"

          StaticName="MyField"

          Group="My Fields"

    Required="TRUE"/>

     

     And you want it to be required in your content type as well, you should reference it as:

    <ContentType ID="0x01005A10185FB67641e396D3C2C58DFF3974"

    Name="MyContentType"

          Group="My Content Types"

          Description=""

          Version="0">

          <FieldRefs>

                <FieldRef ID="="{292184DD-5C7D-403c-AFE2-7880766C1876}" Name="MyField" Required="TRUE"/>

          </FieldRefs>

    </ContentType>

    Hope this helps!

    28 September 2007 12:34
  • Hello,

     

    Im working on a custom field that enables an administrator to select a column in a list in a site collection in the farm. This field is then presented to the user by means of a listbox containing the values for the selected column.

     

    For this functionality I created 3 dropdown lists (ddlSites, ddlLists, ddlColumns) in a usercontrol responsible for displaying the interface to administrators when adding the custom field. After selecting a site collection in the farm, the administrator is presented with the available lists in that site collection. Then when selecting a specific list, the administrator can choose which column to display. After submitting the custom field, the custom field is shown to the user by means of another usercontrol and a codebehind file for the field. So far all works fine.

     

    I am having trouble though displaying the selected values for ddlSites, ddlLists and ddlColumns when an administrator wants to edit the allready created custom field.

     

    Can someone explain to me how I can show the value that was selected when creating the custom dropdownlist in this dropdownlist when editing the custom field?

     

    Any help would be much appreciated.

     

    Thanks,

    Hoek

     

     

     

     

    02 Oktober 2007 15:03
  • Hi Anton,

    Thank you for your reply.

    Actually I was not trying to create content type. I am just trying to create a custom field type for a sharepoint list.
    I'll explain my problem in detail. I don’t know the way I am working is right or wrong because I am not much familiar with SharePoint.
    My aim is to create a custom field type that helps the user to enter data easily. As you explained, I created the Field Definition class, the ASCX files for property rendering and User interface, code-behind files for these usercontrols and the FLDTYPE xml file. Everything is working properly. But my problem is, when I add a new field of my custom type, i can see an additional field setting in the SharePoint UI which specifies whether the field is mandatory or not. For all other sharepoint's buit-in field types like Single Line Text, Currency etc. I can set this option to make it mandatory (in sharepoint UI, it comes as Require that this column contains information under Additional Column Settings Group. But when I set this option for my custom field it is not taking effect. i.e., even if I set the option, user can still skip entering data into the field. As in your sample code, I am not specifying this property in the field property definition. It looks like Sharepoint automatically provides this field setting with all custom field types.

    I am not very familiar with content types. I am planning to deploy my custom field as a feature. Is it really required to go for the content types?


    Thank You,

    Arun
    05 Oktober 2007 6:52
  • Hi,

     

    I have all of this working, however, when I edit my Custom Field, and I pick a new property to display, the old items do not get updated with the new values.

     

    Does anyone know how I can have list items updated with the update on the custom field?

     

    29 Oktober 2007 19:09
  • Hi all,

     

    Thanks for all the info in this thread. You know when I am ready to take on custom field property editors, I know that your work will be very helpful to me indeed. Much of this was also helpful as I learned how to get the field controls working properly too.

     

    But, I was not too excited about writing all that extra code just to fix a bug in the display of the property values, so I dig some digging around in the EditFldEx.aspx page with my debugger, and I think I learned some things you will probably find very interesting.

     

    This is a bit of a hack, it's true, but until MS fixes the problem I think it will reduce the overall amount of code you will need to make custom field properties work properly. My article is posted on my blog at A Workaround for SharePoint Property Bug in Custom Field Types. I hope you find it useful, and I'll be doing a couple more posts about custom field controls later on this month.

     

    I have never tested my workaround to see how it will react to custom field property editors. I don't see why it would break it, but if any of you ever put it to use, pleae let me know.

     

    Did anyone ever find out which (if any) of the security roll ups will incorporate the hotfix that says it will fix this issue? I haven't been bothered to contact MS about it yet because we got it resolved on our own, but I'd like to plan for th eday when I can take all this extra code out of production.

    01 Nopember 2007 19:01
  • Hi Anton,

    Good work.. Probably this was what I was looking for..  I tried to put your code in my machiene.. The only problem I have is inheritance for the user control.

    When u say "public class SelectMyCustomProperty : UserControl, IFieldEditor", should the "usercontrol" be something like SPFieldText or some thing like that.. or should i specify any assembly/namespace for it??

     

    Also, I saw your reply to Smruti. I understand that there are 2 dropdown lists. I am confused about how 2 drop-down lists can togather put a single value into a property/field value.. Could you plz elaborate on the same.

     

    Please help at the earliest.

    Thanx in advance..

    05 Nopember 2007 9:34
  • Hi again..

    thanx for this beautiful piece of code.. this has helped me create a custom drop down property for a field and has solved my problem..

    also, i got this weird idea... i donno how this can be achieved.... thing is ... when i choose a value from the dropdown  property of this custom field, the new field/column created should have the same name as of what is selected.. i tried creating an event handler for "on selected index changed" to populate the textbox (column name) from the selected value...it shows unknown error.... i'm stuck with it... any idea as to how i can do it??

    12 Nopember 2007 9:26
  • Hi Alian,

     

     

    I am facing the same problem , did you figured it out??

     

    please help me ..

     

    Srinivas

    26 Nopember 2007 17:34
  • Hi

    i am facing a similar problem, When i am creating a site column based of the custom field type, i had to pass a parameter,
    I am looking for a way of passing the property while you create a site column in the feature elements file.

    Plz Advise

    Thank you
    10 April 2008 10:43
  • hello,

    I have one question regarding to this forum.

    <PropertySchema>

                        <Fields>

                               <Field Name="MyCustomProperty" DisplayName="My Custom Property"

                                 Type="Text" Hidden="TRUE">

                               </Field>

                        </Fields>

                </PropertySchema>


    I want to access this MyCustomProperty in

    <RenderPattern Name="DisplayPattern">
          <Switch>
            <Expr>
              <Column/>
            </Expr>
            <Case Value="">
            </Case>
            <Default>
              <Property Select="Name" />
              <Property Select="MyCustomProperty" />
            </Default>
          </Switch>
        </RenderPattern>

    In above render pattern Property Name is displayed but property MyCustomProperty is not displayed.

    Even i tried <FieldProperty> but still no success.

    so please guide me what should i do ?

    Thanks.
    31 Mei 2008 18:29
  • Hi,

    can u plz tell me how to get d values of a custom property.

    i hd tried ur code bt its giving error.

    In d basefield control class i want to store d value of custom property in a textbox

    txtFirstName.Text = Field.GetCustomProperty("Size").ToString();

    bt its giving error of object reference.

    So can u plz help me to resolve d error

     

     

    04 Juni 2008 6:25
  • thanks
    21 Mei 2009 15:23
  • Hi,

    I'm dealing with the same problem as described here. I have a custom field that has a SPTreeView control which gets populated with data from a Web Service. Cool, that works fine. What I'm struggling with, is to store the ValuePath of the selected node. I'm saving the Text property of the selected node for normal display in the List and this works fine. However, I do need to store the ValuePath also, in order to set the selected node in Edit mode.

    I have tried the solutions mentioned here, but the value of the CustomProperty is empty when I go to Edit mode on an item.
    What I'm not sure about is if I have to have a custom Field Control for my CustomProperty in addition to my TreeView Field Control (and add that to the field definition XML file)? Or is it enough to just implement the code in my field class (which inherits from SPField)? I don't want to display the ValuePath to the user (except for selecting the right node in the TreeView control).

    I wish I could:
    - Store the TreeView's ValuePath property combined with the node's Text property (i.e. "Parent-Node1-Node2#IDNode2") in my field's 'normal' property and been able to choose to return just "Parent-Node1-Node2" to the List View (typically value.ToString().Split('#')[0]). Then I could do value.ToString().Split('#')[1] to get the node's ID in Edit Mode.

    Thanks!
    22 Oktober 2009 9:10
  • Hi all


    Regarding the suggestion given by u  Anton

    instead of using 


     
    private static Dictionary <int , string > updatedMyCustomProperty = new Dictionary <int , string >();

          private string myCustomProperty;

          public string MyCustomProperty

          {

                get

                {

                      return updatedMyCustomProperty.ContainsKey(ContextId) ? updatedMyCustomProperty[ContextId] : myCustomProperty;

                }

                set

                {

                      this .myCustomProperty = value ;

                }

          }

     

    Thing

     

     

     

     

    we can use something Like




    [ThreadStatic]
            private static string strNumOfLines;

    //Notice this thread static and savwes value all time

     


            public String propNumOfLines
            {
                get
                {
                    return (String)this.GetCustomProperty("NumOfLines"); ;
                }
                set
                {
                    strNumOfLines = value;
                    this.SetCustomProperty("NumOfLines", value);

                }
            }

     

     

    using propNumOfLines anywhere we should be able to get this  custom property

     

    which  is simple and straight forward

    15 Desember 2009 11:20
  • I know that this is marked as closed, but a simpler solution that I came across from Gunnar Peipman is:

    http://weblogs.asp.net/gunnarpeipman/archive/2009/02/03/sharepoint-temporary-solution-for-getcustomproperty-and-setcustomproperty-errors.aspx

    Just uses a bit of reflection, but works very nicely. Do make sure that in OnSaveChange, if your field is new, you don't Update() your field.

    27 Mei 2010 14:45
  • Hi Anton/Aaron,

    This works a treat but there is one issue when the field name is too long or contains special characters.

    Basically when SharePoint creates the field schema, it calls AddFieldAsXmlInternal in SPFieldCollection. Normally this method calls OnAdded after doing its bit, but in the above case, it calls an fieldByInternalName.Update() before doing so.

    Once this happens, the update for our Field Type fires and adds the custom properties, but removes them from the Dictionary. So when Update is called from OnAdded, it goes with a  blank dictionary value and will error out.

    Easiest resolution is to ammend the update call in OnAdded as below

    public override void OnAdded(SPAddFieldOptions op)

          {

                base.OnAdded(op);

                 if(updatedMyCustomProperty.ContainsKey(ContextId))

    Update();

          }

     

    Hope this helps someone.

     

    Cheers,

    Anuj

     

    01 Juli 2010 16:02
  • Hi Anton,

     

    I followed Your procedure. I have an doubt how to raise Selected_Indexchanged Event  and On_CheckedChanged Event in the Customcontrol.ascx.cs.

    customControl.ascx

    <asp:DropDownList id="ddlmyDropDown"   runat="server" Width="200" AutoPostBack="true" OnSelectedIndexChanged="ddlmyDropDown_SelectedIndexChanged">
    <%--<asp:ListItem Selected="True" Text="Select Type" Value="None</asp:ListItem>--%>
    <asp:ListItem Text="Test1" Value="UpDown"></asp:ListItem>

    <asp:ListItem Text="Test2" Value="Checkmark"></asp:ListItem>
    <asp:ListItem Text="Test3" Value="Words"></asp:ListItem>
    </asp:DropDownList>

    How i can take the values from SelectedIndexchanged  event and Call in the On save Change Method.

    22 Nopember 2011 9:25
  • Hi Anton

      I have worked around  your solution but how colud I get the value of custom property as  Field.GetCustomProperty("propertyname");

    this line is always returning null string. I have dropdown as property but I am not getting  selected Items value  using this code pls help me how to save the custom property value through  Field.GetCustomProperty("property name");


    regards, paul

    10 Juli 2012 4:37
  • Thanks, Anton.

    First para was itself very useful. For every Custom Property we use, must be present in fldtypes_xxx.xml 

     base.SetCustomProperty(_key, _value);

    The "_key" must be present in xml file.

    Once again thank you.


    Enjoying life... But these code fixing ...... fix all.

    11 Juli 2012 13:56