• 自定义字段类型的开发[转]


     

    自定义字段类型的开发--2级联动Combox

    在网上找了一些关于自定义字段类型开发的文章。发现在MOSS开发中关于这一部分的文章很少。不过这些也够我们入门了。

    1,创建MOSS2007自定义字段类型实例

    2,创建具有属性值的MOSS2007自定义字段实例

    3,How to: Create a Custom Field Type and Field Control

        前两篇是赏梅斋的,后一篇是MSDN上的。都是很好实例,相信看过后都会有不少的领悟。


        好了,废话不多说了,下面就开始开发这个2级联动Combox。

     



        先创建一个SharePoint空项目,然后再添加一个新字段控件项目。在建立好了项目后,模板会自动为我们添加一些文件:

    1,CityCombox.Field.cs;

    2,CityCombox.FieldControl.cs;

    3,fldtypes_CityCombox.xml;




        还得自己再添加一下文件:

    1,CityComboxValue.cs;

    2,CityControl.ascx;

    3,CityXMLFile.xml;

        在创建CityControl.ascx文件时,请注意目录结构,这会省去我们在部署时的一点小操作。

        建好了项目,我们就该开始写代码了。如果看了前面提到的三篇文章,就会发现,自定义字段类型的开发,基本上是继承SharePoint以提供的类型,在源类型上,进行成员方法的重写。


    1,类型对象CityCombox.Field



     
    CODE:
    using System;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Security;
    namespace CityCombox
    {
    // TODO: Replace, as needed, "SPFieldText" with some other class derived from SPField.
    // TODO: Update, as needed, ParentType element in fldtypes*.xml in this solution.
    [CLSCompliant(false)]
    [Guid("48d7dfb3-a1eb-4c96-af40-0a98b98f021d")]
    public class CityComboxField : SPFieldMultiColumn
    {
    public CityComboxField(SPFieldCollection fields, string fieldName)
    : base(fields, fieldName)
    {
    }

    public CityComboxField(SPFieldCollection fields, string typeName, string displayName)
    : base(fields, typeName, displayName)
    {
    }
    public override BaseFieldControl FieldRenderingControl
    {
    [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
    get
    {
    BaseFieldControl fieldControl = new CityComboxFieldControl();
    fieldControl.FieldName = this.InternalName;
    return fieldControl;
    }
    }
    public override object GetFieldValue(string value)
    {
    if (string.IsNullOrEmpty(value))
    return null;
    return new CityComboxValue(value);
    }
    }
    }




        注意蓝色部分,这里继承的是SPFieldMultiColumn。因为我们最终要实现的效果是在一个字段里记录两个数据,所以继承了SPFieldMultiColumn对象。

        红色部分继承之SPField,绿色部分重写了SPFieldMultiColumn的成员方法,用于得到我们自定义的控件。

        黄色部分是需要我们自己添加的,前面的代码都是由模板自动生成的。因为这种特殊的开发方式(重写),就需要我们对源对象有所了解,这样才知道该重写什么部分。那么看源码,也是一个必须的工作。

        类型部分的代码就写完了。而重点在控件部分,我们下面就来看控件部分的代码。

    2,控件对象CityCombox.FieldControl


     
    CODE:
    using System;
    using System.Runtime.InteropServices;
    using System.Web.UI.WebControls ;
    using System.Xml;
    using System.Collections.Generic;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;

    namespace CityCombox
    {
    // TODO: Replace, as needed, "TextField" with some other class derived from Microsoft.SharePoint.WebControls.BaseFieldControl.
    [CLSCompliant(false)]
    [Guid("34e11e08-29f1-4a8e-8ed2-8800c3c1a5dc")]
    public class CityComboxFieldControl : BaseFieldControl
    {
    protected DropDownList ddl_Province, ddl_City;

    protected override string DefaultTemplateName
    {
    get
    {
    return "CityComboxFieldRendering";
    }
    }

    public override object Value
    {
    get
    {
    EnsureChildControls();
    CityComboxValue fieldValue = new CityComboxValue();
    fieldValue.Province = ddl_Province.SelectedValue.Trim();
    fieldValue.City = ddl_City.SelectedValue.Trim();
    return fieldValue;
    }
    set
    {
    EnsureChildControls();
    CityComboxValue fieldValue = (CityComboxValue)value;
    ddl_Province.SelectedValue = fieldValue.Province;
    ddl_Province_SelectedIndexChanged(null, null);
    ddl_City.SelectedValue = fieldValue.City;
    }
    }


    public override void Focus()
    {
    EnsureChildControls();
    ddl_Province.Focus();
    }

    protected override void CreateChildControls()
    {
    if (Field == null)
    return;

    base.CreateChildControls();

    if (ControlMode == SPControlMode.Display)
    return;

    ddl_Province = (DropDownList)TemplateContainer.FindControl("ddl_Province");
    if (ddl_Province == null)
    throw new ArgumentException("Corrupted CityComboxFieldRendering template - missing ddl_Province. ");
    ddl_Province.TabIndex = TabIndex;
    ddl_Province.CssClass = CssClass;
    ddl_Province.ToolTip = Field.Title + " Province";

    ddl_City = (DropDownList)TemplateContainer.FindControl("ddl_City");
    if (ddl_City == null)
    throw new ArgumentException("corrupted CityComboxFieldRendering template - missing ddl_City.");
    ddl_City.TabIndex = TabIndex;
    ddl_City.CssClass = CssClass;
    ddl_City.ToolTip = Field.Title + " City";


    ddl_Province.Enabled = false;
    ddl_City.Enabled = false;

    if (ControlMode == SPControlMode.New || ControlMode == SPControlMode.Edit)
    {
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(Environment.CurrentDirectory +"\\CityXMLFile.xml");
    XmlNode rootNode= xmlDoc.SelectSingleNode("Place");
    XmlNodeList nodeList = rootNode.ChildNodes;
    ddl_Province.Items.Clear();
    foreach (XmlNode node in nodeList)
    {
    ddl_Province.Items.Add(new ListItem(node.Attributes["name"].Value.ToString(), node.Attributes["name"].Value .ToString()));
    }


    if (!ddl_Province.Enabled)
    {
    ddl_Province.Enabled = true;
    ddl_Province.AutoPostBack = true;
    ddl_Province.SelectedIndexChanged += new EventHandler(ddl_Province_SelectedIndexChanged);

    //ddl_City.SelectedIndexChanged += new EventHandler(ddl_City_SelectedIndexChanged);
    }
    if (ddl_Province.Items.Count > 0)
    {
    //ddl_Province.Items[0].Selected = true;
    ddl_Province_SelectedIndexChanged(null, null);
    }
    }



    }

    private string LoadXml(string province)
    {
    string result=string.Empty ;
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(Environment.CurrentDirectory + "\\CityXMLFile.xml");
    XmlNode rootNode = xmlDoc.SelectSingleNode("Place");
    XmlNodeList nodeList = rootNode.ChildNodes;

    foreach (XmlNode node in nodeList)
    {
    if (province == "all")
    {
    result = result + "@" + node.Attributes["name"].Value .ToString();
    }
    else if(node.Attributes["name"].Value.ToString()==province)
    {
    XmlNodeList cityList = node.ChildNodes;
    foreach (XmlNode city in cityList)
    {
    result = result + "@" + city.Attributes["name"].Value .ToString();
    }
    }
    }
    return result ;
    }

    void ddl_Province_SelectedIndexChanged(object sender, EventArgs e)
    {
    //throw new Exception("The method or operation is not implemented.");
    ddl_City.Enabled = true;
    string[] cityList = LoadXml(ddl_Province.SelectedValue).Split(new char[1]{'@'},StringSplitOptions.RemoveEmptyEntries);
    ddl_City.Items.Clear();
    for (int i = 0; i < cityList.Length; i++)
    {
    ddl_City.Items.Add(new ListItem(cityList[i], cityList[i]));
    }
    }

    }
    }



        首先重写了DefaultTemplateName属性,该属性是用来获取模板的,所以这里返回我们自己的模板。

        接着重写了Value属性,类型对象就通过这个属性来获取控件上的值,或者将值传给控件。

        最后重写了CreateChildControls成员方法。在MOSS中需要用到控件时,就会调用这个方法,我们为了实现特殊的功能,就要重写这个方法。

        在这里个例子里,我们想要实现的就是,给用户提供两个Combox控件,第一个Combox控件里是省名数据,当用户选择了第一个Combox控件里的数据,那么就根据第一个Combox控件里的省名来确定第二Combox控件里的城市,提供给用户选择。

        在CreateChildControls方法里,一开始先进行了一些基本的判断,然后就从我们的自定义模板里寻找我们需要的两个控件(我们这里用的是 DropDownList控件)。接着我们就对第一Combox进行初始化。我们这里的数据来至一个XML文档CityXMLFile.xml。在对第一个Combox控件初始化后,我们就要设定该控件进行自动回传,接着绑定它的SelectedIndexChanged事件到事件处理函数 ddl_Province_SelectedIndexChanged。在ddl_Province_SelectedIndexChanged函数里,我们要做的就是根据第一个Combox控件里选定的数据,来绑定第二个Combox。

        控件部分的代码我们就完成了。在这部份代码里,我们用到了CityComboxValue这个对象。

    3,值对象CityComboxValue



     
    CODE:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.SharePoint;
    using System.Web;
    namespace CityCombox
    {
        class CityComboxValue : SPFieldMultiColumnValue
        {
            private const int numberOfFields = 2;
            public CityComboxValue() : base(numberOfFields) { }
            public CityComboxValue(string value) : base(value) { }
            public string Province
            {
                get { return this[0]; }
                set { this[0] = value; }
            }
            public string City
            {
                get { return this[1]; }
                set { this[1] = value; }
            }

        }
    }


        CityComboxValue继承至SPFieldMultiColumnValue。为了在一个字段内保存多个值,所以我们要定义两个属性。

    4,用户控件CityControl.ascx



     
    CODE:
    <%@ Control Language="C#" ClassName="WebUserControl1" %>
    <%@ Assembly Name="Microsoft.SharePoint,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
    <SharePoint:RenderingTemplate ID="CityComboxFieldRendering" runat="server">
        <Template>
            <table>
                <tr>
                    <td>Province:</td>
                    <td><asp:DropDownList ID="ddl_Province" runat="server">
                    </asp:DropDownList></td>
                    <td>City:</td>
                    <td><asp:DropDownList ID="ddl_City" runat="server">
                    </asp:DropDownList></td>               
                </tr>
            </table>
        </Template>
    </SharePoint:RenderingTemplate>


        就是做一个包含两个DropDownList 控件的用户控件。最后我们来看类型描述文档。

    5,类型描述文档fldtypes_CityCombox.xml



     
    CODE:
    <?xml version="1.0" encoding="utf-8"?>
    <FieldTypes>
      <FieldType>
        <Field Name="TypeName">CityComboxField</Field>
        <Field Name="TypeDisplayName">CityComboxField</Field>
        <Field Name="TypeShortDescription">CityComboxField</Field>
        <Field Name="ParentType">MultiColumn</Field>
        <Field Name="UserCreatable">TRUE</Field>
        <Field Name="FieldTypeClass">48d7dfb3-a1eb-4c96-af40-0a98b98f021d</Field>
        <PropertySchema>
          <Fields>
            <Field Name="DefaultProvince" DisplayName="Default Province:" MaxLength="50" DisplaySize="30" Type="Text">
              <Default>四川</Default>
            </Field>
            <Field Name="DefaultCity" DisplayName="Default City:" MaxLength="50" DisplaySize="30" Type="Text">
              <Default>绵阳</Default>
            </Field>
          </Fields>
        </PropertySchema>
        <RenderPattern Name="DisplayPattern">
          <Switch>
            <Expr>
              <Column/>
            </Expr>
            <Case Value="">
            </Case>
            <Default>
              <HTML><![CDATA[省:]]></HTML>
              <Column SubColumnNumber="0" HTMLEncode="TRUE" />
              <HTML><![CDATA[ ---- 城市:]]></HTML>
              <Column SubColumnNumber="1" HTMLEncode="TRUE"/>
            </Default>
          </Switch>
        </RenderPattern>
      </FieldType>
    </FieldTypes>


        Field标签是对字段类型的基础定义。比如<Field Name="TypeShortDescription">指定了在增加栏时显示的名称;<Field Name="ParentType">MultiColumn</Field>则指定了在展示时的表现类型。

        <RenderPattern Name="DisplayPattern">
    部分则确定了在展示时的样式。既是定义用户所看到的样式。

       

    6,数据文档CityXMLFile.xml



     
    CODE:
    <?xml version="1.0" encoding="utf-8" ?>
    <Place>
      <Province name="四川">   
        <City name="绵阳">绵阳</City>
        <City name="广元">广元</City>
        <City name="德阳">德阳</City>
        <City name="成都">成都</City>
      </Province>
      <Province name="新疆">
        <City name="乌鲁木齐">乌鲁木齐</City>
        <City name="阿尔泰">阿尔泰</City>
        <City name="哈密">哈密</City>
        <City name="石河子">石河子</City>
      </Province>
    </Place>



        最后我们来看看最终的效果





     

     

  • 相关阅读:
    13_graphicals_view.md
    8_菜单栏、工具栏和状态栏.md
    2_按钮&对象数.md
    11_事件.md
    9_对话框.md
    序列化与反序列化 未知结构的数据 Any interface类型
    nil 接口不是 nil
    图片存储格式之一,由JPEG格式衍生而来,后缀为".jfif"。
    Why goroutines instead of threads? https://go.dev/doc/faq#atomic_maps
    源码 //go:nosplit
  • 原文地址:https://www.cnblogs.com/yigedaizi/p/1454032.html
Copyright © 2020-2023  润新知