410 likes | 504 Views
Minneapolis Office Developer Interest Group (MODIG). Neil Iversen Inetium. May 27, 2008 Web Part Development. http://justaddcode.com/. The Plan. Introduction You are here Feature Presentation Web Part Development Next Topic Selection Random Stuff. User Group Goals.
E N D
Minneapolis Office Developer Interest Group (MODIG) Neil Iversen Inetium May 27, 2008 Web Part Development http://justaddcode.com/
The Plan • Introduction You are here • Feature Presentation • Web Part Development • Next Topic Selection • Random Stuff
User Group Goals • Provide a community for SharePoint Developers • Share development knowledge • Exchange tips/tricks/other/free pizza • Add 2,000 attachments to an SPListItem…just for fun
User Group Format • Presentations • 1-2 per meeting (targeting 1.25 Hours) • Hopefully Demo Heavy (Slides are for MBAs) • Highlights of Nifty Things • See next slide • QA/Discussion/Random Things
Call for Cool Stuff • Created something cool? • Send Screenshots or Videos • We’ll try to feature some items here
Sharepointmn.com/modig/ • Our current home • Meeting information • Usually has the right time • Previous presentations • Running on SharePoint • As required by SharePoint User Group Law
Upcoming • Next Meeting • June 24 (Tuesday 5:30pm) • Topic: TBD – Hopefully later today • Location: UNKNOWN! • MNSPUG • June 11(9:00am – Noon) • Topic : TBD (sharepointmn.com) • Twin Cities SharePoint Camp • June 14 • www.twincitiessharepointcamp.com
Developing Web Parts • Web Part Intro • Our First Web Part • Deploying Web Parts • Slightly More Interesting Web Parts
Developing Web Parts • Used to be first exposure to SharePoint Development • Not as true in V3 • Most visual component in SharePoint Development
Our First Decision • Derived From: • SharePoint WebPart v2 • SharePoint WebPart v3 • ASP.NET 2.0 WebPart
Our First Decision • SharePoint WebPart v2 • Its Old, don’t use it • SharePoint WebPart v3 • Use for: • Cross Page Connections • Web Part Caching • Client Side Part to Part Communication (AJAX.net) • ASP.NET 2.0 WebPart • MS Recommended Approach • Even if they don’t follow their own recommendation • Some attributes are different between approaches • Personalization and ‘ToolParts/EditorParts’
The Lifecycle • OnInit • First thing to fire off • OnLoad • Runs after ViewState • CreateChildControls • Main control binding class • Events need to be defined here • PreRender • Last chance to modify before output happens
What about that Render(HtmlWriter) Nonsense? • IMO - Skip it • Begin Mini-Rant • Lots of examples use it, they rarely need it • It causes ‘sync’ issues if you use both CreateChildControls and a write • Check your reason for using it, you can probably restructure your code to eliminate it • End
Exception Management • try/catch in all code called by SharePoint • OnInit • CreateChildControls • PreRender • Any Events • button_Click • selectedIndexChanged
Making Things Personal • Tag your Public Property with: • WebBrowsable(true) • Does it show up in the ToolPane? • Personalizable(PersonalizationScope.User) • Saved with the User or Shared? • WebDisplayName("Favorite Widget") • The name in the ToolPane • WebDescription("Your Favorite Widget") • Tooltip in ToolPane • Category(“My Category") • Category Header in ToolPane • Ex • [Personalizable(PersonalizationScope.Shared)] public string MySavedProperty …
Customizing the ToolPane • Why? • More Configuration Power • ToolParts and EditorParts • SharePoint vs ASP.net • Derive from EditorPart • ApplyChanges • Pushes the Changes back to the Web Part • SyncChanges • Pulls changes that may have happened on the Web Part back to the EditorPart • Web Part • Creates EditorPartCollection in CreateEditorPart()
Playing Well With Others • Part to Part Communication • Providers • Provide the Data • Consumers • Consume the Data
Implementing a Provider • Step 1: • //Step #1: Implement the Connection Interface (ICellProvider) public class CellProvider : WebPart, ICellProvider
Implementing a Provider • Step 2: • //Step #2: Declare Connection Events public event CellProviderInitEventHandlerCellProviderInit; public event CellReadyEventHandlerCellReady;
Implementing a Provider • Step 3: • //Step #3: EnsureInterfaces //Notification to the Web Part that is should ensure that all //its interfaces are registered using RegisterInterface. public override void EnsureInterfaces() { //Registers an interface for the Web Part RegisterInterface("MyCellProviderInterface_WPQ_", //InterfaceNameInterfaceTypes.ICellProvider, //InterfaceTypeWebPart.UnlimitedConnections, //MaxConnectionsConnectionRunAt.ServerAndClient, //RunAtOptions this, //InterfaceObject "CellProviderInterface_WPQ_", //InterfaceClientReference "Provide String from Textbox", //MenuLabel "Provides a Textbox string"); //Description }
Implementing a Provider • Step 4: • //Step #4: CanRunAt - called by framework to determine where a part can run. public override ConnectionRunAtCanRunAt() { //This Web Part can run on both the client and the server return ConnectionRunAt.ServerAndClient; }
Implementing a Provider • Step 5: • //Step #5: PartCommunicationConnect - Notification to the Web Part that it has been connected. public override void PartCommunicationConnect(string interfaceName, WebPartconnectedPart, string connectedInterfaceName, ConnectionRunAtrunAt) { //Check to see if this is a client-side part if (runAt == ConnectionRunAt.Client) { //This is a client-side part _runAtClient = true; return; } //Must be a server-side part so need to create the Web Part's controls EnsureChildControls(); //Check if this is my particular cell interface if (interfaceName == "MyCellProviderInterface_WPQ_") { //Keep a count of the connections _cellConnectedCount++; } }
Implementing a Provider • Step 6: • //Step #6: PartCommunicationInit - Notification to the Web Part that it has been connected. public override void PartCommunicationInit() { //If the connection wasn't actually formed then don't want to send Init event if(_cellConnectedCount > 0) { //If there is a listener, send Init event if (CellProviderInit != null) { //Need to create the args for the CellProviderInit event CellProviderInitEventArgscellProviderInitArgs = new CellProviderInitEventArgs(); //Set the FieldNamecellProviderInitArgs.FieldName = _cellName; cellProviderInitArgs.FieldDisplayName = _cellDisplayName; //Fire the CellProviderInit event. CellProviderInit(this, cellProviderInitArgs); } } }
Implementing a Provider • Step 7: • //Step #7: PartCommunicationMain - Called by the framework to allow part to fire any remaining events public override void PartCommunicationMain() { //If the connection wasn't actually formed then don't want to send Ready event if(_cellConnectedCount > 0) { //If there is a listener, send CellReady event if (CellReady != null) { //Need to create the args for the CellProviderInit event CellReadyEventArgscellReadyArgs = new CellReadyEventArgs(); //If user clicked button then send the value if (_cellClicked) { //Set the Cell to the value of the TextBox text //This is the value that will be sent to the Consumer cellReadyArgs.Cell = _cellInput.Text; } else { //The user didn't actually click the button //so just send an empty string to the Consumer cellReadyArgs.Cell = ""; } //Fire the CellReady event. //The Consumer will then receive the Cell value CellReady(this, cellReadyArgs); } } }
Implementing a Provider • Step 8: • //Step #8: GetInitArgs is not needed in this case. GetInitEventArgs only needs to be //implemented for interfaces that can participate in a transformer which are //the following: ICellConsumer, IRowProvider, IFilterConsumer, IParametersOutProvider, //IParametersInConsumer
Implementing a Provider • Step 9: • //Step #9: Implement CellConsumerInit event handler. public void CellConsumerInit(object sender, CellConsumerInitEventArgscellConsumerInitArgs) { //This is where the Provider part could see what type of "Cell" the Consumer //was expecting/requesting. //For this simple code example, this information is not used anywhere. }
Implementing a Provider • Step 10: • //Step #10: RenderWebPart - defines Web Part UI and behavior protected override void RenderWebPart(HtmlTextWriter output) { //Need to ensure that all of the Web Part's controls are created EnsureChildControls(); //Render client connection code if the connection is client-side if (_runAtClient) { //Connected client-side output.Write(ReplaceTokens("<br><h5>Connected Client-Side</h5><br>\n" + "<input type=\"text\" id=\"CellInput_WPQ_\"/>\n" + "<button id=\"CellButton_WPQ_\" onclick=\"CellButtonOnClick_WPQ_()\">Fire CellReady</button>\n" + "<SCRIPT LANGUAGE=\"JavaScript\">\n" + "<!-- \n" + " varCellProviderInterface_WPQ_ = new myCellProviderInterface_WPQ_();\n" + " function myCellProviderInterface_WPQ_()\n" + " {\n" + " this.PartCommunicationInit = myInit;\n" + " this.PartCommunicationMain = myMain;\n" + " this.CellConsumerInit = myCellConsumerInit;\n" + " function myInit()\n" + " {\n" + " varcellProviderInitArgs = new Object();\n" + " cellProviderInitArgs.FieldName = \"CellName\";\n" + " WPSC.RaiseConnectionEvent(\"MyCellProviderInterface_WPQ_\", \"CellProviderInit\", cellProviderInitArgs);\n" + " }\n" + " function myMain()\n" + " {\n" + " varcellReadyArgs = new Object();\n" + " cellReadyArgs.Cell = \"\";\n" + " WPSC.RaiseConnectionEvent(\"MyCellProviderInterface_WPQ_\", \"CellReady\", cellReadyArgs);\n" + " }\n" + " function myCellConsumerInit(sender, cellConsumerInitArgs)\n" + " {\n" + " }\n" + " }\n" + " function CellButtonOnClick_WPQ_()\n" + " {\n" + " varcellReadyArgs = new Object();\n" + " cellReadyArgs.Cell = document.all(\"CellInput_WPQ_\").value;\n" + " WPSC.RaiseConnectionEvent(\"MyCellProviderInterface_WPQ_\", \"CellReady\", cellReadyArgs);\n" + " }\n" + "//-->\n" + "</SCRIPT>")); } else //Connected server-side { //If connected then display all cell child controls if (_cellConnectedCount > 0) { //Just render some informational text output.RenderBeginTag(HtmlTextWriterTag.Br); output.RenderEndTag(); output.RenderBeginTag(HtmlTextWriterTag.H5); output.Write("Connected Server-Side"); output.RenderEndTag(); output.RenderBeginTag(HtmlTextWriterTag.Br); output.RenderEndTag(); //Render the TextBox control _cellInput.RenderControl(output); //Render the Button _cellButton.RenderControl(output); } else { //There wasn't a cell connection formed, //so just output a message output.Write("NO CELL INTERFACE CONNECTION"); } } }
Implementing a Provider • Step 11: • //Step #11.1 (Supporting Methods): CreateChildControls protected override void CreateChildControls() { //Create the Button _cellButton = new Button(); _cellButton.ID = "CellButton"; _cellButton.Text = "Fire CellReady"; Controls.Add(_cellButton); //Create the TextBox _cellInput = new TextBox(); _cellInput.ID = "CellInput"; Controls.Add(_cellInput); //Set the Cell information. //This information will be passed to the Consumer by //firing the CellProviderInit event. _cellName = "CellInput"; _cellDisplayName = "CellDisplayInput"; _cellClicked = false; // Initialize to false -- user hasn't clicked yet _cellButton.Click += new EventHandler(CellButtonClicked); // listen for Button's click event }
Implementing a Provider • Phew! That’s a lot of code! • Or • [ConnectionProvider(“MyConnectionName“)] • And on the Consumer Side • [ConnectionConsumer(“MyConsumerName“)] • Thanks ASP.NET Team!
Silverlight Web Parts • Its Easy • Add the Silverlight Host Control to the Page • And make 500 web.config changes
Deployment • Deploy using Solutions • Assembly directive to deploy the DLL • Can add to SafeControls • DWP’s can be deployed as well
Summary • Choose who you Derive from • Page Lifecycle • Storing Personalization Settings • Part to Part is much easier • Deployment is nicer than previous CABs
References • Enable Silverlight 2 Beta 1 with a SharePoint Solution • http://blogs.inetium.com/blogs/pjirsa/archive/2008/05/08/enable-silverlight-2-beta-1-with-a-sharepoint-solution.aspx
Next Meeting Planning • Possible Topics • More Web Part Development • Introduction to SharePoint Workflow • PowerShell and SharePoint for Developers • Using the MS AJAX Framework in SharePoint • Silverlight 2 and SharePoint • …
Random Stuff Neil Iversen Inetium http://justaddcode.com Feedback Forms/Giveaway Mingle, Eat, Feedback See you next time!