Use C #. Net to create the infopath custom control

Source: Internet
Author: User
ArticleDirectory
    • Comments

Turn: http://blogs.msdn.com/infopath/archive/2005/04/15/creating-an-infopath-custom-control-using-c-and-net.aspx

In Office 2003 Service Pack 1 (SP1), new features and Infopathcontrol And Infopathcontrolsite Objects were added to infopath to support the development of custom controls implemented using Microsoft ActiveX technology. activeX controls are developed using unmanaged com code, typically written in C ++ or Visual Basic 6.0. with the increasing popularity of the Microsoft. net Framework, includevelopers are switching to working with managed code, such as C # and Visual Basic. net. as an alternative to using unmanaged code to create a custom ActiveX control, you can create a user control (a control derived from. net Windows Forms usercontrol Class) that will function as an infopath custom control by using COM InterOP. com InterOP provides interoperability between. net Assembly compiled for your user control and the unmanaged code of infopath. although Windows Forms user controls are not natively supported by infopath SP1, once you handle the details required for com InterOP and security, writing your. net code is really easy. in this blog entry, we'll give you an overview of how to get. net Control to work in infopath. this entry won't go over the basics of writing. net user controls, so if you are not familiar with user controls, you will need to find that information before the discussion in this blog entry will be useful to you. the basic steps for creating a user control are described in Walkthrough: authoring a user control with Visual C #. for additional details on creating custom ActiveX controls for infopath, you can view the creating custom controls for infopath SP1 webcast, and work with the ActiveX controls in infopath 2003 hands-on training.

Adding the Right Attributes
To get. net user control to work with unmanaged code, certain attributes will need to be added to its source code. in the ActiveX world, all controls have guids (globally unique identifiers ). to do this in. net, you will need to use Guidattribute Attribute to specify a guid. This attribute is part of System. runtime. interopservices Namespace.

Com InterOP will expose methods and Properties Based on the setting ofClassinterfaceAttribute. This attribute must be set to classinterfacetype. autodual in order for the control to work correctly in infopath.

[Classinterface (classinterfacetype. autodual)]

But you will still need to exposeValueAndEnabledProperties of your control to infopath. To do this, you declare an interface for these properties that you will implement within the user control class.InterfacetypeAttribute on this interface shocould be set to interfaceisdual as shown in the following line of code:

[Interfacetype (cominterfacetype. interfaceisdual)]

This attribute setting will expose all of the properties on this interface.
Additionally, for the property identifiers to fire you will need to specify com dispatch Identifiers (DISPIDs) for the enabled and value Properties of your control. to assign DISPIDs using COM InterOP, you use the dispid attribute, which is also part of the system. runtime. interopservices namespace.
putting all of this together, the skeletal code for your control shoshould look something like the following example:

[Interfacetype (cominterfacetype. interfaceisdual)]
Public interface icomcontrol
{
[Dispid (usercontrol1.dispid _ value)]
String Value {Get; set ;}
 
[Dispid (usercontrol1.dispid _ enabled)]
Bool enabled {Get; set ;}
}

[GUID ("6e6f8c69-4873-4f45-b111-3abe034940d9")]
[Classinterface (classinterfacetype. None)]
Public class usercontrol1: system. Windows. Forms. usercontrol, icomcontrol
{
...
}

Note that Icomcontrol Is the name we 've given to the interface we defined which must be implemented within the control class to expose Value And Enabled Properties. The user control class derives from this interface, provides the actual implementation of Get AndSet Methods of the properties, and specifies the values for the dispid_value and dispid_enabled constants. See the full listing later in this blog entry for more details.

The ipropertypolicysink Interface
The com Ipropertypolicysink Interface is required for infopath to know when to update the XML field which is bound to the ActiveX control. property configurications shocould be fired by the Control for this to happen .. net user controls do not have an equivalent interface that will work in COM InterOP, But you can work around this by importing the unmanaged Ipropertypolicysink Interface and then writing your own implementation of it in managed code. This is accomplished by using Comimport And Interfacetype Attributes as shown in the following example.

[Comimport]
[GUID ("9bfbbc02-eff1-101a-84ed-00aa00341d07")]
[Interfacetype (cominterfacetype. interfaceisiunknown)]
Public interface ipropertypolicysink
{
Int onchanged (INT dispid );

[Preservesig]
Int onrequestedit (INT dispid );
}

In addition to this Code, You Need To A create a delegate for the two events of your control class. The delegate shocould look like this:

Public Delegate int propertypolicysinkhandler (INT dispid );

And your events shocould look like this:

Public event propertypolicysinkhandler onchanged;
Public event propertypolicysinkhandler onrequestedit;

You also need to specify that the importedIpropertypolicysinkInterface is exposed as a source of COM events. You do this by addingComsourceinterfacesAttribute to your control's class. The attribute shocould look like this:

[Comsourceinterfaces (typeof (ipropertypolicysink)]

and finally, when implementing the value and enabled Properties of the control, don't forget to fire the onchanged event when the value property is changed.

satisfying security

Custom Controls written with. net Language still have the same security restrictions as unmanaged ActiveX controls used in infopath:. cab file for the control must be signed with a digital signature, and the IObjectSafety interface must be implemented on the control. the IObjectSafety interface is an unmanaged interface but can still be implemented if you import and rewrite the interface in. net. this is similar to what we did for the ipropertypolicysink interface above:

[comimport]
[GUID ("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
[interfacetype (cominterfacetype. interfaceisiunknown]
interface IObjectSafety
{
[preservesig]
int getinterfacesafetyoptions (ref guid riid, out int pdwsupportedoptions, out int pdwenabledoptions );
[preservesig]
int setinterfacesafetyoptions (ref guid riid, int dwoptionsetmask, int dwenabledoptions);
}

the user control class must derive from the IObjectSafety interface and implement the getinterfacesafetyoptions and setinterfacesafetyoptions methods. see the complete listing in the following section for details on how to do this.
coding checklist
we 've gone over quite a few things that need to be done to create. net user control that works with infopath. below is a checklist of the things you shoshould have already done:

    • AddGuidAttribute to your control class
    • AddComsourceinterfacesAttribute to your control class
    • Set the control'sClassinterfaceAttributeClassinterfacetype. None
    • Declare an interface forValueAndEnabledProperties of your control, settingInterfacetypeAttributeCominterfacetype. interfaceisdual
    • Import and implement the comIpropertypolicysinkInterface
    • Import and implement the comIObjectSafetyInterface

The following listing provides the code behind a simple. Net user control that contains a read-onlyTextboxControl that can be bound to a field in an infopath form.

Using system;
Using system. collections;
Using system. componentmodel;
Using system. drawing;
Using system. Data;
Using system. Windows. forms;
Using system. runtime. interopservices;

Namespace windowscontrollibrary1
{
/// <Summary>
/// Summary description for usercontrol1.
/// </Summary>

[Interfacetype (cominterfacetype. interfaceisdual)]
Public interface icomcontrol
{
[Dispid (usercontrol1.dispid _ value)]
String Value {Get; set ;}

[Dispid (usercontrol1.dispid _ enabled)]
Bool enabled {Get; set ;}
}

[comimport]
[GUID ("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
[interfacetype (cominterfacetype. interfaceisiunknown]
interface IObjectSafety
{
[preservesig]
int getinterfacesafetyoptions (ref guid riid, out int pdwsupportedoptions, out int pdwenabledoptions );
[preservesig]
int setinterfacesafetyoptions (ref guid riid, int dwoptionsetmask, int dwenabledoptions);
}

[Comimport]
[GUID ("9bfbbc02-eff1-101a-84ed-00aa00341d07")]
[Interfacetype (cominterfacetype. interfaceisiunknown)]
Public interface ipropertypolicysink
{
[Preservesig]
Int onchanged (INT dispid );
 
[Preservesig]
Int onrequestedit (INT dispid );
}

Public Delegate int propertypolicysinkhandler (INT dispid );

[GUID ("1fee489f-a555-4408-8fbf-3f69f8425a43")]
[Classinterface (classinterfacetype. None)]
[Comsourceinterfaces (typeof (ipropertypolicysink)]
Public class usercontrol1: system. Windows. Forms. usercontrol, icomcontrol, IObjectSafety
{
Public event propertypolicysinkhandler onchanged;
Public event propertypolicysinkhandler onrequestedit;

Private system. Windows. Forms. textbox textbox1;
/// <Summary>
/// Required designer variable.
/// </Summary>
Private system. componentmodel. Container components = NULL;

// Constants for implementation of the IObjectSafety interface.
Private const int interfacesafe_for_untrusted_caller = 0x00000001;
Private const int interfacesafe_for_untrusted_data = 0x00000002;
Private const int s_ OK = 0;

// Constants for DISPIDs of the value and enabled properties.
Internal const int dispid_value = 0;
Internal const int dispid_enabled = 1;

Public usercontrol1 ()
{< br> // This call is required by the windows. forms Form Designer.
initializecomponent ();
// todo: add any initialization after the initcomponent call
}

// Implementation of the IObjectSafety methods.
int IObjectSafety. getinterfacesafetyoptions (ref guid riid, out int pdwsupportedoptions, out int pdwenabledoptions)
{< br> pdwsupportedoptions = optional | optional;
pdwenabledoptions = optional | optional;
return s_ OK; // return s_ OK
}< br>
int IObjectSafety. setinterfacesafetyoptions (ref guid riid, int dwoptionsetmask, int dwenabledoptions)
{< br> return s_ OK; // return s_ OK
}

Protected int fire_onrequestedit (INT dispid)
{
If (this. onrequestedit! = NULL)
Return this. onrequestedit (dispid );
Else return 0;
}

Protected int fire_onchanged (INT dispid)
{
If (this. onchanged! = NULL)
Return this. onchanged (dispid );
Else return 0;
}

// Implementation of the value property get and set methods.
Public string value
{< br> get {return textbox1.text ;}< br> set {textbox1.text = value ;}< BR >}

/// <Summary>
/// Clean up any resources being used.
/// </Summary>
Protected override void dispose (bool disposing)
{
If (disposing)
{
If (components! = NULL)
Components. Dispose ();
}
Base. Dispose (disposing );
}

// Component designer generated code goes here.
...

Private void textbox1_textchanged (Object sender, system. eventargs E)
{
Fire_onchanged (usercontrol1.dispid _ value );
}
}
}

Compiling a. Net user control for com InterOP
To compile a. Net user control for com InterOP, follow these steps:

    1. In Visual Studio. NET 2003, openSolution ExplorerAnd right-click on the project item.
    2. ClickPropertiesTo display the properties pane for the project.
    3. UnderConfiguration Properties, ClickBuild.
    4. UnderOutputs, ChangeRegister for com InterOPToTrue.

The next time you compile, your user control will be available to unmanaged code.

Adding a. Net user control to the infopath controls task pane
When you add a new custom control using the infopath Add M control wizard , Infopath will look only for controls that are in the "controls" category. however, when. net controls are compiled, they are categorized ". net controls ", which infopath does not look. to manually add. net Control, you must create. ICT file and store it in the C: \ Documents ents and Settings \ Username \ Local Settings \ Application Data \ Microsoft \ infopath \ controls folder. If you have not added any custom controls to infopath's Controls Task pane, you will need to create this controls folder yourself. the easiest way to create. ICT file is to add an ActiveX control to the controls task pane in infopath, and then copy. ICT file which is created automatically by infopath.

Getting a. Net user control into a self-registering cab file
Infopath requires custom controls to be packaged in cab files for deployment. The normal way for. Net controls to be deployed is to add Setup Project To the solution in Visual Studio, which will produce an MSI file when the solution is compiled. an MSI file is required for. net Control to be registered for com InterOP. the MSI file that is generated by Setup Project Can then be packaged in a cab file, but CAB files do not automatically run and register MSI files. you can work around this by creating. INF file similar to the following example which has hooks to execute. MSI file after the cab file is extracted:

[Setup hooks]
Hook1 = hook1

[Hook1]
Runningmsiexec.exe/I % extract_dir % \ MSI. MSI/Qn

[Version]
; This section is required for compatibility on both Windows 95 and Windows NT.
Signature = "$ Chicago $"
Advancedinf = 2.0

NoteThere is a bug in the. NET Framework that will cause anyLabelControls used in A. Net user control to throw GDI + exceptions. You can workaround this by using GDI + to draw your own text, or you can useTextboxControl instead and set itsReadonlyPropertyTrue.

Comments

How does infopath know what control property to use as the value?
This is determined Soley by the bindingproperty within the ICT file. There is no infopath GUI menu/property menu to control this binding.

What property bindings can infopath handle?
Infopath can only handle a value and an enabled property.
Irrespective of what properties are available within the custom ActiveX control, infopath is only capable of handling a value and an enabled property.

Ipropertypolicysink
Whatever events are declared by the implementation of the ipropertypolicysink interface;


Public interface ipropertypolicysink
{
Int onchanged (INT dispid );

[Preservesig]
Int onrequestedit (INT dispid );
}

The raising of any of these events will only trigger infopath to update the value binding within the xml dom.

Within infopath
Within infopath it is not possible for managed code to hook into the events raised by the custom ActiveX control.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.