Tutorial Ajax Rss Image Web Part Slideshare

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    Favorites, Groups & Events

    Tutorial Ajax Rss Image Web Part Slideshare - Presentation Transcript

    1. SharePointMinds.com Tutorial – How To Create a SharePoint Ajax Web Part Using Images from an RSS Feed and Using the Ajax UpdatePanelAnimationExtender Control with Screen Tanning Effect on Load To present an image slide show in SharePoint George Catrombon September 2009
    2. Page 2 of 60 Table of Contents SUMMARY ...................................................................................................................... 3 ABOUT OUR WEB PART ............................................................................................... 6 THE WEB SITE WE ARE TARGETING FOR IMAGES................................................... 6 REQUIREMENTS TO CODE THIS WEB PART ............................................................. 6 CONFIGURING THE ENVIRONMENT TO USE AJAX EXTENSIONS AND THE AJAX TOOL KIT ........................................................................................................................ 7 STEP 1 – CREATE THE PROJECT IN VISUAL STUDIO ............................................. 10 STEP 2 – CHANGE THE FILE AND FOLDER NAMES ................................................ 12 STEP 3 – MODIFY THE CONTENTS OF THE .XML AND .WEBPART FILES ............. 13 STEP 4 – ADD 2 FOLDERS TO THE PROJECT .......................................................... 14 STEP 5 – ADD A STYLESHEET TO THE PROJECT ................................................... 15 DISCUSSION OF SCREEN TANNING CSS ................................................................. 17 STEP 6 – EMBED THE STYLE SHEET AND GIF IMAGES IN THE ASSEMBLY ........ 18 STEP 7 – ADD REFERENCES TO THE AJAX EXTENSIONS DLL AND AJAX TOOL KIT DLL ......................................................................................................................... 22 STEP 7 – ADD THE CODE BEHIND FROM APPENDIX E .......................................... 25 STEP 8 – COMPILE AND DEPLOY THE WEB PART .................................................. 32 STEP 9 – ADD THE WEB PART TO A SHAREPOINT PAGE AND CONFIGURE ....... 37 CONCLUSION .............................................................................................................. 44
    3. Page 3 of 60 REVISION 1 – 9Oct09 – The RSS feed listed in the tutorial is no longer valid. Use the following url for the RSS feed http://feeds.space.com/SpacecomImageOfTheDay
    4. Page 4 of 60 SUMMARY This document describes how to create a somewhat fancy, SharePoint web part that uses images from an RSS feed, and displays them as a slide show. The images are fetched from the RSS feed site dynamically via Ajax XmlHttpRequests. The fancy part of this control is that we display the typical Ajax rotating loading…. gif image in conjunction with the screen tanning effect that we see so much of on the web. The screenTanning effect also prevents the user from clicking the button when the Ajax XmlHttpRequest is in process as the screenTanning <div> tag blocks it (and the whole web part UI for that matter). Figure 1 shows the web part in its normal state in SharePoint. Figure 2 shows a close up of the web part, and Figure 3 shows the Ajax call in progress with the rotating gif and screen tanning in play. Figure 1- Our web part shown in a SharePoint page
    5. Page 5 of 60 Figure 2 – Our slide show web part with button Figure 3 – Rotating gif and screen tanning effect during Ajax call
    6. Page 6 of 60 ABOUT OUR WEB PART Before we get started, let‟s discuss some the details of what we are doing with this web part. What we are really trying to demonstrate is how to code a SharePoint web part that uses the Microsoft extended AjaxToolkit controls to make asynchronous XmlHttpRequests to a third party web site to fetch images when a button is clicked on the web part. We want each click of the button on the web part to initiate an Ajax call to go out and fetch the next image in our slide show off the internet. While the fetching of the image is in progress, we want to present our loading…. rotating gif image, but with the popular screen tanning effect to block the button from being pushed by the user while the Ajax call is in progress. The actual image URL‟s and title of the image will be obtained from an RSS feed from the third party web site we have targeted. When the web part is first initialized, it will fetch the XML of the RSS feed, and parse it for the URL‟s of the images and the titles of those images. We store those URL‟s and titles in a list which is then stored in session scope. Therefore, we only read the RSS feed XML once. However, we will cycle thru the list of URL‟s each time the user clicks our web part button. On each push of the button by the user, the next image bytes will be streamed to our web part from the internet. So, with our image URL‟s in a list, and the titles of those images also in a list, whenever the user clicks our web part button, the web part will use Ajax to contact the third party web site to fetch the image bytes corresponding to our stored URL. This will be a good example of using Ajax to make calls that should not return immediately, since we are streaming the image bytes to the web part with each click of our web part button (depending on the speed of your internet connection). However, you will note in our event handler code for our button, that we do add a time delay so that our rotating gif image and screenTanning effect have enough residence time in the web part to illustrate a long load time Ajax call. THE WEB SITE WE ARE TARGETING FOR IMAGES For this tutorial, we have selected the web site: http://www.livescience.com/amazingimages/ This web site has some interesting photos submitted by users, and also offers an RSS feed to fetch those photos. Rather than just fetch the RSS feed and display it in one shot as per normal practice with RSS feeds, our web part will fetch each image on demand and only display one at a time. Therefore, we will need to parse the XML of the RSS feed to get the required information our web part needs to do its job. REQUIREMENTS TO CODE THIS WEB PART
    7. Page 7 of 60 You should have Virtual PC 2007 or Virtual Server 2005 R2 SP1 installed on your laptop. In either of the above virtual machines, the Windows Server 2003 operating system should be installed, and up and running. Then, the following software packages must be installed: 1. Microsoft ASP.NET 3.5 Framework 2. Microsoft Windows Server 2003 installed on the Virtual Machine (E.g. the VM) 3. Ability of the virtual machine to connect to the internet using the Microsoft Loopback adapter (see the document on this topic by this author on the SharePointMinds.com site). 4. Microsoft SharePoint 2007 5. Microsoft SQL Server 2005 (required by SharePoint) 6. Microsoft Visual Studio 2008 7. Windows SharePoint Services 3.0 Tools: Visual Studio 2005 Extensions, Version 1.2 8. Microsoft Ajax Control Toolkit (May 2009 release, available at http://www.asp.net/ajax/downloads/ 9. A rotating gif image to use during our Ajax call (these can be fetched off the internet after a Google search). 10. A third party web site (of your choice) from which to fetch the RSS image feed data. CONFIGURING THE ENVIRONMENT TO USE AJAX EXTENSIONS AND THE AJAX TOOL KIT SharePoint does not have the ability to recognize Ajax out of the box. There are two levels of Ajax controls that we need to make SharePoint aware of. The first is the Ajax extensions that come with Visual Studio out of the box (E.g. the basic Ajax controls that ship with Visual Studio 2008). The second is a group of fancy controls contained in the Ajax Control Toolkit which is a separate download from Microsoft. We need to configure SharePoint to be aware of these two major Ajax components. This is done in two ways: 1. We need to make significant modifications to the SharePoint web.config file for the SharePoint site we are targeting. 2. We need to place the AjaxControlToolkit.dll in the appropriate location under SharePoint. In this authors implementation, the web.config file that was changed was specific to this authors Li’l Italy SharePoint site that was running on port 8084. Therefore, the changes were made to the web.config file as shown in Figure 4 below (you should change the web.config file specific to your SharePoint web site).
    8. Page 8 of 60 Figure 4 – authors web.config file that was modified The changes pertaining to the basic Ajax Extensions are described in Appendix A. The changes pertaining to the Ajax Control Toolkit are described in Appendix B. After you make these changes, you will need to add the AjaxControlKit.dll to the bin directory of your SharePoint site. Figure 5 shows this DLL added to the bin directory for his Li’l Italy SharePoint site.
    9. Page 9 of 60 Figure 5
    10. Page 10 of 60 STEP 1 – CREATE THE PROJECT IN VISUAL STUDIO Refer to Figure 6. Click File > New > Project. Figure 6 Refer to Figure 7. Notice that the in the left hand pane, there is a line item named SharePoint. This line item will not appear unless you have installed the Windows SharePoint Services 3.0 Tools: Visual Studio 2005 Extensions, Version 1.2. Click on Web Part to create the project. Make sure to name it SPM_RSS_Image_Ajax_WP as shown in the figure. .
    11. Page 11 of 60 Figure 7 Refer to Figure 8. This is how the project initially looks upon creation. We need to make some changes before we write any code. We need to change the file names on the right hand pane, and make some changes to the content of the file. The reason we do this, is that the default name created by Visual Studio is WebPart1 for everything. If we were to create another web part project without changing the name, then there will be conflicts when we deploy to SharePoint. So, make sure you change the names as we describe below.
    12. Page 12 of 60 Figure 8 STEP 2 – CHANGE THE FILE AND FOLDER NAMES Refer to Figure 9. First, we need to change the names of 1 folder and 3 files. This author named the files to SPM_RSS_Image_Ajax_WP as well as the folder name as shown.
    13. Page 13 of 60 Figure 9 STEP 3 – MODIFY THE CONTENTS OF THE .XML AND .WEBPART FILES Refer to Figure 10. Change the text in the xml file to agree with the new name we have assigned to the file with the .xml suffix as shown in the figure. The text is changed in 2 places. Note that the items circled in red must agree with the corresponding file name on the right hand pane. Figure 10
    14. Page 14 of 60 Refer to Figure 11. We now need to change the text that appears in the file with the .webpart suffix as shown in the figure. The text is changed in 3 places in the file named SPM_RSS_Image_Ajax_WP.webpart. Figure 11 STEP 4 – ADD 2 FOLDERS TO THE PROJECT We add 2 folders named CSS and Images. Refer to Figure 12 Figure 12 Place the rotating gif image you downloaded of the internet into the Images folder. Refer to Figure 13 and 14 showing this authors green_rot.gif image.
    15. Page 15 of 60 Figure 13 Figure 14 – Authors rotating gif image STEP 5 – ADD A STYLESHEET TO THE PROJECT Create a style sheet in the project and take the default name of Stylesheet1.css (case matters here!). Refer to Figure 15.
    16. Page 16 of 60 Figure 15 Place the style sheet in our CSS folder. Then add the markup for CSS from Appendix C. Refer to Figure 16.
    17. Page 17 of 60 Figure 16 DISCUSSION OF SCREEN TANNING CSS At this point, lets discuss how our CSS styles work. The markup in our web part consists of 6 simple boxes defined by 6 <div> tags in the markup (although we place our .NET controls in that markup during construction). The outer box named boundingDiv defines the maximum size we want our web part: namely 348 pixels high by 400 pixels wide. We want the other 5 boxes to stay within these confines so they are nested in the outer box. There are 3 boxes that define the header, the body and the footer. The header contains the title, the body contains our button and image, and the footer contains the SharePointMinds.com trademark. These 4 boxes are always visible in the web part. The remaining 2 boxes defined by <div> tags are named screenTanning and popup. These 2 div are hidden until we make the Ajax call. When the Ajax call triggers to start, we set the visibility of these 2 div tags to „block‟ instead of „none”. They then appear on top of the other 4 boxes. When the Ajax call returns, we set these 2 boxes back to display „none‟ and they become invisible again. This triggering is done courtesy of our Ajax Toolkit control UpdatePanelAnimationExtender.
    18. Page 18 of 60 The screen tanning effect is done by simply making the screen tanning box the same size as the bounding div box. It is simply offset upward by setting the margin to -335 pixels. This makes it cover the original 4 boxes. Then, since our popup div box appears below the screenTanning div box in the markup, it appears on top of the screen tanning box. It‟s all very simple Note that we do not specify absolute or relative positioning for the screen tanning or popup boxes. They always participate in the CSS flow as normal. Also, note that we do not specify z-index to make the screen tanning and popup boxes appear on top of the stack order. Simply the strategic placement of the screen tanning and popup boxes in the markup are all that is required. The actual screen tanning effect is done by setting the color of the screen tanning box to black, and making it transparent by setting its alpha value to .50. The 3 variations of the alpha syntax are for different browsers. Note that if we did not set the alpha transparency and left the box black, you would not see the other 4 boxes behind it as the box would be opaque. All you would see is a black box in the web part with the popup showing the rotating gif. So, by adding some transparency to the box, we can see thru it. You have seen this type of screen tanning on many web sites on the internet. It should also be noted that our screen tanning is confined to the web part: not to the entire SharePoint page. Also, it does not matter where on the page our web part is placed: the screen tanning and popup remain in the proper place in the web part. NOTE: The CSS in the Appendix works for IE8. This author did not test cross browser compatibility for the screen tanning and popup div tags. It is not likely that it will render properly in other browsers. STEP 6 – EMBED THE STYLE SHEET AND GIF IMAGES IN THE ASSEMBLY Why do we need to embed our style sheet and image in the assembly? Well, if we didn‟t, we would have to ask an administrator to manually place them in the appropriate folders in the SharePoint directory structure on every server. So, since we don‟t want to do that, we embed them in our web part assembly so our web part is completely self contained. To do this consists of two steps: They are: 1. Change the properties of each from Content to Embedded Resource. 2. Add 2 lines in the Assembly.cs file. Refer to Figures 17 and 18 showing where we change the property of each item.
    19. Page 19 of 60
    20. Page 20 of 60 Figure 17
    21. Page 21 of 60 Figure 18 Now we can add 2 lines to our Assembly.cs file as shown in Figure 19. See Appendix D for the actual code to insert.
    22. Page 22 of 60 Figure 19 STEP 7 – ADD REFERENCES TO THE AJAX EXTENSIONS DLL AND AJAX TOOL KIT DLL Refer to Figures 20, 21 and 22 showing that we add references to these 2 required Ajax DLL‟s. Figure 20
    23. Page 23 of 60
    24. Page 24 of 60 Figure 21
    25. Page 25 of 60 Figure 22 STEP 7 – ADD THE CODE BEHIND FROM APPENDIX E Copy the code behind from Appendix E into the .cs file of the project. At this point, we discuss the functions in the code behind. OnInit Refer to the summary note below (in green text) as to why we include this function. /// <summary> /// We override this method so that we can put in the line /// EnsureChildControls(). We do this since it is reported /// that SharePoint may not call EnsureChildControls() /// reliably. This call is essential. /// </summary> protected override void OnInit(EventArgs e){ base.OnInit(e); EnsureChildControls(); //We hard code this since SharePoint may not call it reliably. }
    26. Page 26 of 60 CreateChildControls This is the main function in which controls are dynamically added to web parts. We see that we are storing the index of the currently displayed image in session. This index is changed whenever the user clicks the button on the web part in the button event handler. Here is where we add our Ajax script manager to the page. Note that we check if a script manager already exists on the page since two ScriptManagers are not allowed. The ScriptManager is the main player in Microsofts Ajax technologies as it manages all the JavaScript required to make Ajax calls. Compare this with using the Ajax Prototype library where you as a programmer code hundreds of lines of JavaScript to do the same thing. Also, note the call to insert the UpdatePanel (E.g. AddUpdatePanel()), and we add our Ajax Toolkit control, the UpdatePanelAnimationExtender (E.g. AddupdaetAnimationExtender()). The last line of code, EnsurePanelFix2() is some special code required to be inserted into a page so that the Ajax works correctly. /// <summary> /// Here we install our controls in the web part. We also initialize /// our RSS Xml feed datasource and add an Ajax required JavaScript /// fix so that our Ajax will work with web parts. /// </summary> protected override void CreateChildControls(){ base.CreateChildControls(); ExportMode = WebPartExportMode.All; if( HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW] == null) HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW] = 0; else _nextPictureToShow = (int)HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW]; InitializeXmlDataSource(); _scriptManager = ScriptManager.GetCurrent(Page); if (_scriptManager == null){ _scriptManager = new ScriptManager{ID = "ScriptManager1", EnablePartialRendering = true}; //ScriptManager MUST be added first! Controls.Add(_scriptManager); } AddUpdatePanel(); AddUpdateAnimationExtender(); EnsurePanelFix2(); }
    27. Page 27 of 60 OnPreRender We call OnPreRender because this is the perfect place in the page life cycle to insert our style sheet <link> tag in the <head> area of the SharePoint page. The link tag is of the form: <link rel=”stylesheet” type=”text/css” url=”our url from the assembly goes here “ /> There is a SharePoint style sheet named core.css that is loaded late in the game by SharePoint. To insure that our style sheet is loaded after core.css, we insert our link tag just before the page is rendered. /// <summary> /// We place our <link> tag with our CSS stylesheet url /// in the head section of the hosting page in this function so /// that we make sure it's added last in the page. /// </summary> protected override void OnPreRender(EventArgs e){ RegisterStyleSheet(GetStyleSheetUrlFromAssembly); base.OnPreRender(e); } RegisterStyleSheet Refer to the summary note (in green text) below for a description of this function. /// <summary> /// Here is where we actually put the link tag in the <head> /// section of the HTML markup for the page hosting our web part. /// </summary> /// <param name="cssUrl">The url of our web part as obtained /// from the assembly in which our style sheet is embedded as /// a resource.</param> private void RegisterStyleSheet(string cssUrl){ HtmlHead header = FindControl<HtmlHead>(Page.Master.Controls); if (header != null){ Literal literal = new Literal{ Text = String.Format( "<link href="{0}" type="text/css" rel="stylesheet">", cssUrl) }; header.Controls.Add(literal); } }
    28. Page 28 of 60 AddUpdatePanel Refer to the notes (in green text) below as to the details of this function. Important! Note that we embed our UpdatePanel in another panel. If you do not do this, you will get an exception when the Ajax call returns! /// <summary> /// This function addes our Ajax UpdatePanel to the control /// collection of the SharePoint page. /// </summary> protected void AddUpdatePanel(){ #region Programmers Notes //Notice that we are placing our UpdatePanel in a Panel control. The reason //for this is that you can't add an UpdatePanel dynamically to a web part //or you will get exceptions thrown when the UpdatePanel gets the return //payload from the XmlHttpRequest. This fix is to embed the UpdatePanel in //another panel and then add that 2nd panel to the controls collection. //This is a somewhat obscure tidbit about dynamically //loaded Ajax UpdatePanels in web parts. #endregion UpdatePanel1 = new UpdatePanel{ ID = "UpdatePanel1", UpdateMode = UpdatePanelUpdateMode.Conditional, ChildrenAsTriggers = true }; AddMarkupToUpdatePanel(); Panel panel = new Panel(); //Our fix panel.Controls.Add(UpdatePanel1); Controls.Add(panel); } GetRssFeed This is the function in which we actually go out and get the RSS Xml feed.
    29. Page 29 of 60 InitializeXmlDataSource Here is where we set up to make the call for the RSS feed. Since we are going to be parsing the XML of the RSS feed, we will need a NameSpace manager so we can use XPath expressions to get the XML tags that we want. Namely, the XML tags that define the URL‟s of the images, and the tags that denote the title of those images. There are 3 namespaces that we need to accommodate in the RSS feed as shown in the code. An important thing to note here is that we are not using the XmlDataSource to actually fetch the feed. We are only using it as a crutch to get the name table of the RSS feed so we can initialize our XmlNameSpaceManager. We actually get the RSS feed in the GetRSSFeed() function by creating a web client. /// <summary> /// Here is where we (conditionally) read the Xml from the RSS feed, /// extract the url's of the images from the XML, and store those /// URL"s in a list. We also do that for the image titles. /// Notice that we only read the RSS feed once, and we only use /// the XmlDataSource once as well. /// </summary> protected void InitializeXmlDataSource(){ if (HttpContext.Current.Session[CS_LIST_IMAGE_URLS] == null || HttpContext.Current.Session[CS_LIST_IMAGE_TITLES] == null){ _ImageUrlList = new List<string>(); _ImageTitleList = new List<string>(); _xmlDataSource = new XmlDataSource { DataFile = CS_RSS_FEED_URL, XPath = "rss/channel/item" }; _xmlNameSpaceManager = new XmlNamespaceManager(_xmlDataSource.GetXmlDocument().NameTable); _xmlNameSpaceManager.AddNamespace("media", "http://search.yahoo.com/mrss"); _xmlNameSpaceManager.AddNamespace("feedburner", "http://rssnamespace.org/feedburner/ext/1.0"); _xmlNameSpaceManager.AddNamespace("atom10", "http://www.w3.org/2005/Atom"); GetRSSFeed(); } else{ _ImageUrlList = (List<string>)HttpContext.Current.Session[CS_LIST_IMAGE_URLS]; _ImageTitleList = (List<string>)HttpContext.Current.Session[CS_LIST_IMAGE_TITLES]; } }
    30. Page 30 of 60 AddUpdateAnimationExtender Here we add the Ajax control UpdatePanelAnimationExtender. This is the Ajax control where the magic happens that controls our screen tanning and popup with rotating gif image. The key thing to note here is the Animation.Parse function. This is where we can insert various types of behavior that can occur during the animation. In our case, we add XML to call some JavaScript that changes the display property of our screen tanning and popup div tags from none to block and vice versa. There are many effects you could perform here depending on your imagination. Refer to Microsoft‟s documentation on this control for many of the other possibilities for animations. /// <summary> /// Here is where we initialize our animation extender /// and add it to the controls collection. Notice that /// we initialize the extender with the JavaScript that executes when the button /// is clicked, and when the XmlHttpRequest returns. /// that executes during the Ajax call. /// </summary> protected void AddUpdateAnimationExtender(){ _animationExtender = new UpdatePanelAnimationExtender{ ID = "animationExtender1", TargetControlID = UpdatePanel1.ID }; const string xml = "<OnUpdating>" + " <ScriptAction script="$get('screenTanning').style.display='block';" + " $get('popup').style.display='block';" /> " + "</OnUpdating>" + "<OnUpdated>" + " <ScriptAction script="$get('screenTanning').style.display='none';" + " $get('popup').style.display='none';" /> " + "</OnUpdated>"; Animation.Parse(xml, _animationExtender); Controls.Add(_animationExtender); }
    31. Page 31 of 60 AddMarkupToUpdatePanel Here is where we add the HTML markup (E.g. our 6 div tag boxes) along with the required ASP.NET Controls to provide the presentation of our web part. This author originally created the markup in SharePointDesigner 2007 to get the basic layout. There is nothing tricky here: we simply add HTML and controls to our UpdatePanel. /// <summary> /// Here is where we add the HTML markup to the UpdatePanel. /// Notice that we intersperse adding ASP controls in there /// as well. /// </summary> protected void AddMarkupToUpdatePanel(){ string markup1 = "<div id="boundingDiv"><div id="headerDiv" >"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup1)); _imageTitleLabel = new Label { ID = "imageTitleLabel" }; UpdatePanel1.ContentTemplateContainer.Controls.Add(_imageTitleLabel); string markup2 = "</div><div id="bodyDiv">"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup2)); Button nextButton = new Button{ID = "nextButton", Height = 20, Width = 50, Text = "-->"}; UpdatePanel1.ContentTemplateContainer.Controls.Add(nextButton); nextButton.Click += NextButton_Click; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl("<br /><br />")); _rssFeedImage = new Image { ID = "rssImage", Width = 254, Height = 180 }; UpdatePanel1.ContentTemplateContainer.Controls.Add(_rssFeedImage); UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl("<br />")); const string markup3 = " <br />" + " </div>" + " <div id="footerDiv">Copyright 2009 &trade; SharePointMinds.com</div>" + " <div id="screenTanning" style="display: none;" />" + " </div>" + " <div id="popup" style="display: none;" >"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup3)); _rotatingGifImage = new Image{ID = "rotatingGifImage", ImageUrl = GetRotatingImageUrlFromAssembly}; UpdatePanel1.ContentTemplateContainer.Controls.Add(_rotatingGifImage); const string markup4 = " &nbsp;&nbsp;&nbsp;&nbsp;Loading Image..... </div>";
    32. Page 32 of 60 UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup4)); AssignWebPartImage(_nextPictureToShow); } OTHER FUNCTIONS The other functions in the code are very straight forward are really require no formal explanation. If you are familiar enough to get this far in the tutorial, then these other functions should be elementary to understand. STEP 8 – COMPILE AND DEPLOY THE WEB PART We need to specify where to deploy the web part. This is done by right clicking on the project in the right hand pane of Visual Studio and clicking Properties as shown in Figure 23.
    33. Page 33 of 60 Figure 23 In the resulting dialog, click Debug. Refer to Figure 24.
    34. Page 34 of 60 Figure 24 Enter the URL of the SharePoint site you wish to deploy the web part to. In our case, we have a SharePoint site at http://localhost;8084. Refer to Figure 25 which shows our SharePoint site for a company called Li’l Italy. Note that the URLof the site in Figure 25 agrees with the entry in Figure 24 (note that localhost maps to george-.5qxg5tx on the authors laptop). Our web part will be deployed to the Li’l Italy site for us when we deploy later in the tutorial.
    35. Page 35 of 60 Figure 25 –We need the URL in the address bar to specify where to deploy. Refer to Figure 26. Compile the project as per standard practice. After it is compiled, deploy the project to SharePoint by clicking the deploy menu option as shown in Figure 26. Wait while the web part is deployed, along with other automated things the deployment process performs like recycling the application pool and so forth.
    36. Page 36 of 60 Figure 26
    37. Page 37 of 60 STEP 9 – ADD THE WEB PART TO A SHAREPOINT PAGE AND CONFIGURE We are now ready to use our web part in SharePoint in our Li’l Italy SharePoint site. On the main page of our Li’l Italy site, we will add our new web part. Click Site Actions > Edit on the main page. This will result in the page going into Edit mode as shown in Figure 27. Figure 27 Click on Add a Web Part in Figure 27. This results in the new list as shown in Figure 29. You should see our new SPM_RSS_Image_Ajax_WP as shown in Figure 27.
    38. Page 38 of 60 Figure 29 Click the check box adjacent to it, and click Add. The web part will then be loaded onto the page as shown in Figure 29.
    39. Page 39 of 60 Figure 29
    40. Page 40 of 60 Exit Edit mode and our web part will appear as in Figure 30 Figure 30
    41. Page 41 of 60 We can now cycle thru the images by clicking the button on the web part. The following sequence shows how things look to the user. Note that the Ajax call takes about 2 seconds since we have a time delay in the code for this tutorial.
    42. Page 42 of 60
    43. Page 43 of 60
    44. Page 44 of 60 And so forth. CONCLUSION This tutorial has demonstrated how to configure SharePoint to understand Ajax. We coded a fancy web part that uses an advanced feature of the UpdatePanelAnimationExtender control. We also discussed how the screen tanning takes place and how our RSS feed is processed. Hopefully, students at SharePoint Minds will be able to use this knowledge to create Ajax web parts in the field. END DOCUMENT APPENDIX FOLLOWS
    45. Page 45 of 60
    46. Page 46 of 60 APPENDIX A – XML TO ADD TO SHAREPOINT WEB.CONFIG FOR AJAX EXTENSTIONS Changes are to be made in 7 places: They are: Change 1 of 7 - Add the following <sectionGroup> elements within the <configSections> element <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" /> <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere" /> <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" /> <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" /> </sectionGroup> </sectionGroup> </sectionGroup>
    47. Page 47 of 60 Change 2 of 7 - Add the following controls declaration within the <pages> element, which is located within the <system.web> element <controls> <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </controls> Change 3 of 7 - Add the following assembly declaration within the <assemblies> element. <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> Change 4 of 7 - Add the following verb handlers within the <httpHandlers> element <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false" /> Change 5 of 7 - Add the following script module handler within the <httpModules> element <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> Change 6 of 7 – Add the following safe control entry within the <SafeControls> element, which is located within the <SharePoint> element <SafeControl Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TypeName="*" Safe="True" /> Change 7 of 7 - Add the following scripting web service handlers within the <configuration> element
    48. Page 48 of 60 <system.web.extensions> <scripting> <webServices> <!-- Uncomment this line to enable the authentication service. Include requireSSL="true" if appropriate. --> <!-- <authenticationService enabled="true" requireSSL = "true|false"/> --> <!-- Uncomment these lines to enable the profile service. To allow profile properties to be retrieved and modified in ASP.NET AJAX applications, you need to add each property name to the readAccessProperties and writeAccessProperties attributes. --> <!-- <profileService enabled="true" readAccessProperties="propertyname1,propertyname2" writeAccessProperties="propertyname1,propertyname2" /> --> </webServices> <!-- <scriptResourceHandler enableCompression="true" enableCaching="true" /> --> </scripting> </system.web.extensions> <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <modules> <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </modules> <handlers> <remove name="WebServiceHandlerFactory-Integrated" /> <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </handlers> </system.webServer> END APPENDIX A
    49. Page 49 of 60 APPENDIX B – XML TO ADD TO SHAREPOINT WEB.CONFIG FOR AJAX CONTROL TOOLKIT Changes are to be made in 2 places: They are: Change 1 of 2 - Add the following assembly declaration within the <assemblies> element. <add assembly="AjaxControlToolkit, Version=3.0.30512.20315, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" /> Change 2 of 2 - Add the following in the <controls> element. <add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" tagPrefix="ajaxToolkit" /> END APPENDIX B
    50. Page 50 of 60 APPENDIX C – CSS STYLES FOR OUR WEB PART #boundingDiv { background:#669999; font-family:Arial; font-size: 10px; height: 347px; width: 400px; text-align: center; } #headerDiv { height: 30px; margin-right: auto; margin-left: auto; width: auto; padding-top: 10px; background: black; font-size: 16px; font-weight: bold; color: white; } #bodyDiv { margin-right: auto; margin-left: auto; width: 100%; height: 270px; padding-top: 20px; } #footerDiv { font-size: 10px; height: 16px; width: 100%; color: black; padding: 10px 10px 10px 10px; } #screenTanning { margin-top: -335px;
    51. Page 51 of 60 width: 400px; height: 347px; background-color: black; filter: alpha(opacity=50); -moz-opacity: .50; opacity: .50; } #popup { margin-top: -220px; width: 300px; background:white; padding: 20px 20px 20px 20px; font-size: 18px; border: solid 3px #00FF99; color:#6600FF; }
    52. Page 52 of 60 APPENDIX D – CODE TO ADD TO OUR ASSEMBLY.CS FILE [assembly: WebResource("SPM_RSS_Image_Ajax_WP.Images.green_rot.gif", "image/gif")] [assembly: WebResource("SPM_RSS_Image_Ajax_WP.CSS.Stylesheet1.css", "text/css")]
    53. Page 53 of 60 APPENDIX E – C# CODE FOR OUR WEB PART #region Using using System; using System.Collections.Generic; using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml; using AjaxControlToolkit; #endregion namespace SPM_RSS_Image_Ajax_WP.SPM_RSS_Image_Ajax_WP { [Guid("4bc4c26e-8534-4ec3-99f0-2843c72b3ad1")] public class SPM_RSS_Image_Ajax_WP : WebPart { #region Declarations private int _nextPictureToShow; private List<string> _ImageUrlList; private List<string> _ImageTitleList; //Controls protected UpdatePanel UpdatePanel1; private XmlNamespaceManager _xmlNameSpaceManager; private UpdatePanelAnimationExtender _animationExtender; private XmlDataSource _xmlDataSource; private ScriptManager _scriptManager; private Image _rssFeedImage; private Image _rotatingGifImage; private Label _imageTitleLabel; //Strings private const string CS_RSS_FEED_URL = "http://feeds.livescience.com/livesciencecomAmazingImages"; private const string CS_NEXT_PICTURE_TO_SHOW = "CS_NEXT_PICTURE_TO_SHOW"; private const string CS_LIST_IMAGE_URLS = "CS_LIST_IMAGE_URLS"; private const string CS_LIST_IMAGE_TITLES = "CS_LIST_IMAGE_TITLES"; #endregion #region OnInit /// <summary> /// We override this method so that we can put in the line /// EnsureChildControls(). We do this since it is reported /// that SharePoint may not call EnsureChildControls() /// reliably. This call is essential. /// </summary> protected override void OnInit(EventArgs e){ base.OnInit(e);
    54. Page 54 of 60 EnsureChildControls(); //We hard code this since SharePoint may not call it reliably. } #endregion #region CreateChildControls /// <summary> /// Here we install our controls in the web part. We also initialize /// our RSS Xml feed datasource and add an Ajax required JavaScript /// fix so that our Ajax will work with web parts. /// </summary> protected override void CreateChildControls(){ base.CreateChildControls(); ExportMode = WebPartExportMode.All; if( HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW] == null) HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW] = 0; else _nextPictureToShow = (int)HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW]; InitializeXmlDataSource(); _scriptManager = ScriptManager.GetCurrent(Page); if (_scriptManager == null){ _scriptManager = new ScriptManager{ID = "ScriptManager1", EnablePartialRendering = true}; //ScriptManager MUST be added first! Controls.Add(_scriptManager); } AddUpdatePanel(); AddUpdateAnimationExtender(); EnsurePanelFix2(); } #endregion #region OnPreRender /// <summary> /// We place our <link> tag with our CSS stylesheet url /// in the head section of the hosting page in this function so /// that we make sure it's added last in the page. /// </summary> protected override void OnPreRender(EventArgs e){ RegisterStyleSheet(GetStyleSheetUrlFromAssembly); base.OnPreRender(e); } #endregion #region RegisterStyleSheet /// <summary> /// Here is where we actually put the link tag in the <head> /// section of the HTML markup for the page hosting our web part. /// </summary> /// <param name="cssUrl">The url of our web part as obtained /// from the assembly in which our style sheet is embedded as /// a resource.</param> private void RegisterStyleSheet(string cssUrl){
    55. Page 55 of 60 HtmlHead header = FindControl<HtmlHead>(Page.Master.Controls); if (header != null){ Literal literal = new Literal{ Text = String.Format( "<link href="{0}" type="text/css" rel="stylesheet">", cssUrl) }; header.Controls.Add(literal); } } #endregion #region AddUpdatePanel /// <summary> /// This function addes our Ajax UpdatePanel to the control /// collection of the SharePoint page. /// </summary> protected void AddUpdatePanel(){ #region Programmers Notes //Notice that we are placing our UpdatePanel in a Panel control. The reason //for this is that you can't add an UpdatePanel dynamically to a web part //or you will get exceptions thrown when the UpdatePanel gets the return //payload from the XmlHttpRequest. This fix is to embed the UpdatePanel in //another panel and then add that 2nd panel to the controls collection. //This is a somewhat obscure tidbit about dynamically //loaded Ajax UpdatePanels in web parts. #endregion UpdatePanel1 = new UpdatePanel{ ID = "UpdatePanel1", UpdateMode = UpdatePanelUpdateMode.Conditional, ChildrenAsTriggers = true }; AddMarkupToUpdatePanel(); Panel panel = new Panel(); //Our fix panel.Controls.Add(UpdatePanel1); Controls.Add(panel); } #endregion #region InitializeXmlDataSource /// <summary> /// Here is where we (conditionally) read the Xml from the RSS feed, /// extract the url's of the images from the XML, and store those /// URL"s in a list. We also do that for the image titles. /// Notice that we only read the RSS feed once, and we only use /// the XmlDataSource once as well.
    56. Page 56 of 60 /// </summary> protected void InitializeXmlDataSource(){ if (HttpContext.Current.Session[CS_LIST_IMAGE_URLS] == null || HttpContext.Current.Session[CS_LIST_IMAGE_TITLES] == null){ _ImageUrlList = new List<string>(); _ImageTitleList = new List<string>(); _xmlDataSource = new XmlDataSource { DataFile = CS_RSS_FEED_URL, XPath = "rss/channel/item" }; _xmlNameSpaceManager = new XmlNamespaceManager(_xmlDataSource.GetXmlDocument().NameTable); _xmlNameSpaceManager.AddNamespace("media", "http://search.yahoo.com/mrss"); _xmlNameSpaceManager.AddNamespace("feedburner", "http://rssnamespace.org/feedburner/ext/1.0"); _xmlNameSpaceManager.AddNamespace("atom10", "http://www.w3.org/2005/Atom"); GetRSSFeed(); } else{ _ImageUrlList = (List<string>)HttpContext.Current.Session[CS_LIST_IMAGE_URLS]; _ImageTitleList = (List<string>)HttpContext.Current.Session[CS_LIST_IMAGE_TITLES]; } } #endregion #region AddUpdateAnimationExtender /// <summary> /// Here is where we initialize our animation extender /// and add it to the controls collection. Notice that /// we initialize the extender with the JavaScript that executes when the button /// is clicked, and when the XmlHttpRequest returns. /// that executes during the Ajax call. /// </summary> protected void AddUpdateAnimationExtender(){ _animationExtender = new UpdatePanelAnimationExtender{ ID = "animationExtender1", TargetControlID = UpdatePanel1.ID }; const string xml = "<OnUpdating>" + " <ScriptAction script="$get('screenTanning').style.display='block';" + " $get('popup').style.display='block';" /> " + "</OnUpdating>" + "<OnUpdated>" + " <ScriptAction script="$get('screenTanning').style.display='none';" + " $get('popup').style.display='none';" /> " + "</OnUpdated>";
    57. Page 57 of 60 Animation.Parse(xml, _animationExtender); Controls.Add(_animationExtender); } #endregion #region AddMarkupToUpdatePanel /// <summary> /// Here is where we add the HTML markup to the UpdatePanel. /// Notice that we intersperse adding ASP controls in there /// as well. /// </summary> protected void AddMarkupToUpdatePanel(){ string markup1 = "<div id="boundingDiv"><div id="headerDiv" >"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup1)); _imageTitleLabel = new Label { ID = "imageTitleLabel" }; UpdatePanel1.ContentTemplateContainer.Controls.Add(_imageTitleLabel); string markup2 = "</div><div id="bodyDiv">"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup2)); Button nextButton = new Button{ID = "nextButton", Height = 20, Width = 50, Text = "-->"}; UpdatePanel1.ContentTemplateContainer.Controls.Add(nextButton); nextButton.Click += NextButton_Click; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl("<br /><br />")); _rssFeedImage = new Image { ID = "rssImage", Width = 254, Height = 180 }; UpdatePanel1.ContentTemplateContainer.Controls.Add(_rssFeedImage); UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl("<br />")); const string markup3 = " <br />" + " </div>" + " <div id="footerDiv">Copyright 2009 &trade; SharePointMinds.com</div>" + " <div id="screenTanning" style="display: none;" />" + " </div>" + " <div id="popup" style="display: none;" >"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup3)); _rotatingGifImage = new Image{ID = "rotatingGifImage", ImageUrl = GetRotatingImageUrlFromAssembly}; UpdatePanel1.ContentTemplateContainer.Controls.Add(_rotatingGifImage); const string markup4 = " &nbsp;&nbsp;&nbsp;&nbsp;Loading Image..... </div>"; UpdatePanel1.ContentTemplateContainer.Controls.Add(new LiteralControl(markup4)); AssignWebPartImage(_nextPictureToShow);
    58. Page 58 of 60 } #endregion #region NextButtonClick /// <summary> /// Our handler for the click of the next image /// button. /// </summary> private void NextButton_Click(object sender, EventArgs e) { _nextPictureToShow += 1; if (_nextPictureToShow > _ImageUrlList.Count - 1) _nextPictureToShow = 0; HttpContext.Current.Session[CS_NEXT_PICTURE_TO_SHOW] = _nextPictureToShow; AssignWebPartImage(_nextPictureToShow); System.Threading.Thread.Sleep(2000); } #endregion #region EnsurePanelFix2 /// <summary> /// This is some JavaScript that we must add to /// allow Ajax to work properly in a web part. /// </summary> private void EnsurePanelFix2(){ if (Page.Form != null){ string formOnSubmitAtt = Page.Form.Attributes["onsubmit"]; if (formOnSubmitAtt == "return _spFormOnSubmitWrapper();") Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();"; ScriptManager.RegisterStartupScript(this, typeof(SPM_RSS_Image_Ajax_WP), "UpdatePanelFixup", "_spOriginalFormAction=document.forms[0].action; _spSupressFormOnsubmitWrapper=true;", true); } } #endregion #region FindControl<T> /// <summary> /// Our generic function that allows us to find /// the <html> tag on the SharePoint page. /// </summary> private T FindControl<T>(ControlCollection controlCollection) where T : Control{ foreach (Control c in controlCollection){ if (c.GetType() == typeof(T)) return (T)c; T child = FindControl<T>(c.Controls); if (child != null) return child; }
    59. Page 59 of 60 return null; } #endregion #region GetRotatingImageUrlFromAssembly /// <summary> /// Here we extract the URL of our rotating gif /// image from the assembly as an embedded resource. /// </summary> public string GetRotatingImageUrlFromAssembly{ get { return ResolveUrl(Page.ClientScript.GetWebResourceUrl(GetType(), "SPM_RSS_Image_Ajax_WP.Images.green_rot.gif")); } } #endregion #region GetStyleSheetUrlFromAssembly /// <summary> /// Here is where we extract the URL of our style sheet /// from the assembly as an embedded resource. /// </summary> public string GetStyleSheetUrlFromAssembly{ get{ return ResolveUrl(Page.ClientScript.GetWebResourceUrl(GetType(), "SPM_RSS_Image_Ajax_WP.CSS.Stylesheet1.css")); } } #endregion #region GetRSSFeed /// <summary> /// Here is where we actually fetch the XML from the RSS feed. /// We also parse it, get the image urls and titles of the images, /// and place them in lists. /// </summary> protected void GetRSSFeed(){ WebClient client; using (client = new WebClient()){ byte[] feedBytes = client.DownloadData(CS_RSS_FEED_URL); string xmlAsString = Encoding.ASCII.GetString(feedBytes); XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlAsString); XmlNodeList nodeList = doc.SelectNodes("rss/channel/item"); if (nodeList != null) foreach (XmlNode node in nodeList){ XmlAttribute attribute = node.SelectSingleNode("media:content/@url", _xmlNameSpaceManager) as XmlAttribute; if (attribute != null){
    60. Page 60 of 60 string url = attribute.Value; _ImageUrlList.Add(url); XmlNode titleNode = node.SelectSingleNode("media:title", _xmlNameSpaceManager); _ImageTitleList.Add(titleNode.InnerText); } } } HttpContext.Current.Session[CS_LIST_IMAGE_URLS] = _ImageUrlList; HttpContext.Current.Session[CS_LIST_IMAGE_TITLES] = _ImageTitleList; } #endregion #region AssignWebPartImage /// <summary> /// This function assignes an image to the web part /// and also populates the title. /// </summary> /// <param name="index">The index of the next image /// to show.</param> protected void AssignWebPartImage(int index){ _rssFeedImage.ImageUrl = _ImageUrlList[index]; _imageTitleLabel.Text = _ImageTitleList[index].ToUpper(); } #endregion } }

    + George CatrombonGeorge Catrombon, 2 months ago

    custom

    457 views, 0 favs, 0 embeds more stats

    Tutorial on creating an Ajax web part for SharePoin more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 457
      • 457 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 0
    • Downloads 9
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories