Customizing the Rendering of a Custom SPField (copy from todd's blog)
2010-05-21 10:54
393 查看
http://blogs.msdn.com/toddca/archive/2009/01/23/customizing-the-rendering-of-a-custom-spfield.aspx
I was recently asked by a customer how to use a PropertySchema field value within a RenderPatten's CAML to control how a field is rendered. The idea is to create a new instance of the field and have some method to control how that field will be rendered at the time the column is instantiated. Unfortunately field values from the PropertySchema are not available via a <Property Select='myValue'/> within a ReanderPattern's CAML and nor is it possible to call a custom getter off the SPField derived class of your custom SPField. In most cases when a field is rendered it is done so within native (non-managed) code so the getter on your .net assembly will not get called. The field schema stored in the DB is what gets read to help generate the rendered output. Fortunately this schema can be accessed by SPFIeld.SchemaXml. Adding properties or attributes to the root element of this XML will allow the RenderPattern CAML access.
So let's take a look at a sample. For my scenario I want URL field however I want to control how that field is rendered. By default a URL field just renders the URL without wrapping that URL in an <a> tag. In our example we want to create a true hyperlink so we are going to generate a RenderingPattern which will wrap an <a> tag around the field value. In addition we want the creator of the field to choose what happens when that link is selected by the user. That is, will the navigation happen within the same window or will the browser open the URL in a new window. I call these options "Self" and "New" respectively.
Now that we have our scenario let's take a look at what it will take to wire up the new field. First I need to define our field via fldTypes XML. Code 1 shows what this looks like. As you can see the Parent is "URL" because we want to use the same storage and rendering of the built-in URL however we are going to tweak it a bit. The FieldTypeClass will be outlined in Code 2. The PropertySchema field is used to collect the user's intent on how the URL will behave within the client's browser and finally we have RenderingPattern CAML which will control how the field will be rendered within the browser. Note I have a FieldSwitch on a Property called 'HowOpenUrl', this value will not be chosen from the PropertySchema's HowOpenUrl directly however once you take a look at Code 2 you will see how this is done. The reminder of the RenderPattern uses the FieldSwitch to determine how to render the URL. The default rendering is an <a> tag with the target set to _self so the URL will be navigated to within the same window.
Code 1 – fldtypes_sample.xml
After creating a Class Library project and adding the proper reference to Microsoft.SharePoint I added the following code to define my ConfigurableUrlField. This field derives from the SPFieldURL class which is important because we defined in Code 1 that our ParentType is "URL". Like all custom fields we need to create the two proper constructors which not only allow our type to be constructed but properly instantiates the base type. Next we need to override the OnAdded() and OnUpdated() methods which each get called whenever this field definition is added to a new site column or when the site column definition is updated, for example when someone wants to change from a rendering of this field from "Self" to "New". The magic all happens in ConfigureSchemaXml(), this is where we access the base.SchemaXml and update it with our custom property's value as configured by the user. This is the only chance we get to manipulate the schema before being stored in the DB and used to render the field. Note the name of the attribute being added/updated needs to match the name being used within the FieldSwitch: <Property Select='HowOpenUrl'/>
Code 2 – ConfigurableUrlField.cs
For completeness I have included the manifest.xml used for deployment of the solution. I will not go over that here since the concept is covered in so many other places.
Code 3 – manifest.xml
Once we have our solution added and deployed within our farm it is time to use the field. I created a test list and added a new column based on the Configurable URL field I just deployed. Note the open to set how the URL will open within the browser.
![](http://blogs.msdn.com/photos/toddca/images/9373123/500x316.aspx)
Now back at my list I create a new list item – note that we did not create a custom field control but rather are using the SPFieldUrl's field control for editing of this field.
![](http://blogs.msdn.com/photos/toddca/images/9373150/500x146.aspx)
Finally we can see the URL in action. Obviously an image does not do it justice but if I look at the HTML source I can find what actually got rendered:
<a target="_self" href="http://www.msn.com" href="http://www.msn.com">http://www.msn.com</a>
I was recently asked by a customer how to use a PropertySchema field value within a RenderPatten's CAML to control how a field is rendered. The idea is to create a new instance of the field and have some method to control how that field will be rendered at the time the column is instantiated. Unfortunately field values from the PropertySchema are not available via a <Property Select='myValue'/> within a ReanderPattern's CAML and nor is it possible to call a custom getter off the SPField derived class of your custom SPField. In most cases when a field is rendered it is done so within native (non-managed) code so the getter on your .net assembly will not get called. The field schema stored in the DB is what gets read to help generate the rendered output. Fortunately this schema can be accessed by SPFIeld.SchemaXml. Adding properties or attributes to the root element of this XML will allow the RenderPattern CAML access.
So let's take a look at a sample. For my scenario I want URL field however I want to control how that field is rendered. By default a URL field just renders the URL without wrapping that URL in an <a> tag. In our example we want to create a true hyperlink so we are going to generate a RenderingPattern which will wrap an <a> tag around the field value. In addition we want the creator of the field to choose what happens when that link is selected by the user. That is, will the navigation happen within the same window or will the browser open the URL in a new window. I call these options "Self" and "New" respectively.
Now that we have our scenario let's take a look at what it will take to wire up the new field. First I need to define our field via fldTypes XML. Code 1 shows what this looks like. As you can see the Parent is "URL" because we want to use the same storage and rendering of the built-in URL however we are going to tweak it a bit. The FieldTypeClass will be outlined in Code 2. The PropertySchema field is used to collect the user's intent on how the URL will behave within the client's browser and finally we have RenderingPattern CAML which will control how the field will be rendered within the browser. Note I have a FieldSwitch on a Property called 'HowOpenUrl', this value will not be chosen from the PropertySchema's HowOpenUrl directly however once you take a look at Code 2 you will see how this is done. The reminder of the RenderPattern uses the FieldSwitch to determine how to render the URL. The default rendering is an <a> tag with the target set to _self so the URL will be navigated to within the same window.
Code 1 – fldtypes_sample.xml
<?xml version="1.0" encoding="utf-8" ?> <FieldTypes> <FieldType> <Field Name="TypeName">ConfigurableURL</Field> <Field Name="ParentType">URL</Field> <Field Name="TypeDisplayName">Configurable URL</Field> <Field Name="TypeShortDescription">Configurable URL</Field> <Field Name="UserCreatable">TRUE</Field> <Field Name="ShowInListCreate">TRUE</Field> <Field Name="ShowInSurveyCreate">TRUE</Field> <Field Name="ShowInDocumentLibraryCreate">TRUE</Field> <Field Name="ShowInColumnTemplateCreate">TRUE</Field> <Field Name="FieldTypeClass">SampleConfigurableField.ConfigurableUrlField, SampleConfigurableField, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3de2414d286dff3d</Field> <PropertySchema> <Fields> <Field Name="HowOpenUrl" DisplayName="Choose how to open the URL ('Self' = within same window, 'New' = New Window" Type="Text"> <Default>Self</Default> </Field> </Fields> </PropertySchema> <RenderPattern Name="DisplayPattern"> <FieldSwitch> <Expr> <Property Select='HowOpenUrl'/> </Expr> <Case Value="Self"> <HTML><![CDATA[<a target="_self" href="]]></HTML> <Column HTMLEncode="TRUE" /> <HTML><![CDATA[">]]></HTML> <Column HTMLEncode="TRUE" /> <HTML><![CDATA[</a>]]></HTML> </Case> <Case Value="New"> <HTML><![CDATA[<a target="_blank" href="]]></HTML> <Column HTMLEncode="TRUE" /> <HTML><![CDATA[">]]></HTML> <Column HTMLEncode="TRUE" /> <HTML><![CDATA[</a>]]></HTML> </Case> <Default> <Column HTMLEncode="TRUE" /> </Default> </FieldSwitch> </RenderPattern> </FieldType> </FieldTypes> |
Code 2 – ConfigurableUrlField.cs
namespace SampleConfigurableField { using System; using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls; using System.Xml; public class ConfigurableUrlField : SPFieldUrl { bool _updating = false; public ConfigurableUrlField(SPFieldCollection fields, string fieldName) : base(fields, fieldName) { } public ConfigurableUrlField(SPFieldCollection fields, string typeName, string displayName) : base(fields, typeName, displayName) { } public override void OnUpdated() { //ConfigureSchemaXml() will cause the OnUpdated event to be raised, //to keep out of a stack overflow condition we bail early when updating if (_updating) return; _updating = true; { base.OnUpdated(); ConfigureSchemaXml(); } _updating = false; } public override void OnAdded(SPAddFieldOptions op) { base.OnAdded(op); ConfigureSchemaXml(); } void ConfigureSchemaXml() { string howOpenUrl = (string)base.GetCustomProperty("HowOpenUrl"); howOpenUrl = AreStringsEqual("New", howOpenUrl) ? "New" : "Self"; XmlDocument doc = new XmlDocument(); doc.LoadXml(base.SchemaXml); if (doc.FirstChild.Attributes["HowOpenUrl"] == null) { XmlAttribute attrib = doc.CreateAttribute("HowOpenUrl"); attrib.Value = howOpenUrl; doc.FirstChild.Attributes.Append(attrib); } else { doc.FirstChild.Attributes["HowOpenUrl"].Value = howOpenUrl; } base.SchemaXml = doc.OuterXml; } private bool AreStringsEqual(string s1, string s2) { return (String.Compare(s1, s2, true) == 0); } public override BaseFieldControl FieldRenderingControl { get { BaseFieldControl fldControl = new UrlField(); fldControl.FieldName = InternalName; return fldControl; } } } } |
Code 3 – manifest.xml
<?xml version="1.0" encoding="utf-8" ?> <Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="733641DA-95D9-446E-812E-6070947171B2" DeploymentServerType="WebFrontEnd" ResetWebServer="TRUE"> <Assemblies> <Assembly DeploymentTarget="GlobalAssemblyCache" Location="SampleConfigurableField.dll"> <SafeControls> <SafeControl Namespace="SampleConfigurableField" TypeName="*" Safe="True" /> </SafeControls> </Assembly> </Assemblies> <TemplateFiles> <TemplateFile Location="XML\fldtypes_Sample.xml"/> </TemplateFiles> </Solution> |
Now back at my list I create a new list item – note that we did not create a custom field control but rather are using the SPFieldUrl's field control for editing of this field.
Finally we can see the URL in action. Obviously an image does not do it justice but if I look at the HTML source I can find what actually got rendered:
<a target="_self" href="http://www.msn.com" href="http://www.msn.com">http://www.msn.com</a>
相关文章推荐
- [摘要]Pushing the Limits of Windows: Paged and Nonpaged Pool - From Mark Russinovich's blog
- [摘要]Pushing the Limits of Windows: Physical Memory - From Mark Russinovich's blog
- How do you copy the contents of an array to a std::vector in C++ without looping? (From stack over flow)
- Customizing the Appearance of CSliderCtrl Using Custom Draw
- Xcode4 布置Git环境Your working copy is out of date. Try pulling from the remote to get the latest change
- [摘要]Pushing the Limits of Windows: Virtual Memory -- From Mark Russinovich's blog
- Rails Error: rails a copy of has been removed from the module tree but is still active
- The Meaning of Open (from google's offical blog)
- Xcode4 布置Git环境Your working copy is out of date. Try pulling from the remote to get the latest change
- 布置Git环境Your working copy is out of date. Try pulling from the remote to get the latest change
- ExtJS中表格控件的使用,属性设置和数据的获取(copyfrom:http://www.itzhai.com/extjs-form-controls-in-the-use-of-property-)
- 在Visual Studio.NET中使用自定义插件最大化您的生产力(三)Custom Add-Ins Help You Maximize the Productivity of Visual Studio .NET
- Identify in details the consumption of memory from a specific session
- fatal error C1853: 'Debug\test.pch' precompiled header file is from a previous version of the compil
- This version of the rendering library is more recent than your version of ADT plug-in. Please update ADT plug-in问题
- C++: 为什么我们一般都要将函数的声明和定义分开?(separate the declaration of function from its definition)
- Summing it all up: 35 blog entries in 2 days from the BCL Team [Kit George] --from BCLTeam's Weblog
- Find the substring of length 3 which is present in the reverse order from the string
- Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag
- This version of the rendering library is more recent than your version of ADT plug-in. Please update