{"id":426,"date":"2011-08-08T20:25:25","date_gmt":"2011-08-09T01:25:25","guid":{"rendered":"http:\/\/osric.com\/chris\/accidental-developer\/?p=426"},"modified":"2011-09-01T10:28:39","modified_gmt":"2011-09-01T15:28:39","slug":"sharepoint-user-control-to-display-a-random-image","status":"publish","type":"post","link":"https:\/\/osric.com\/chris\/accidental-developer\/2011\/08\/sharepoint-user-control-to-display-a-random-image\/","title":{"rendered":"SharePoint user control to display a random image"},"content":{"rendered":"<p>The master page of a SharePoint site I work on loaded 7 photographic images, all over 50 kB each, to display at random as a banner adjacent to the site logo. The way it loaded the images was very inefficient: a default image was loaded in the HTML, and Javascript on the page created 7 image objects and returned one at random to overwrite the default. I decided to find a C# way to solve the problem.<br \/>\n<!--more--><\/p>\n<p>Here is the original Javascript code:<\/p>\n<pre><code>&lt;script language=\"javascript\" type=\"text\/javascript\"&gt;\r\n    var bannerImages = new Array();\r\n    var bannerIndex = 0;\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"building.jpg\";\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"tree.jpg\";\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"fountain.jpg\";\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"people.jpg;\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"painting.jpg;\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"statue.jpg;\r\n    bannerImages[bannerIndex] = new Image();\r\n    bannerImages[bannerIndex++].src = \"cafe.jpg;\r\n    var randombannerIndex = Math.floor(Math.random() * bannerImages.length);\r\n    document.images[\"banner\"].src = bannerImages[randombannerIndex].src;\r\n&lt;\/script&gt;<\/code><\/pre>\n<p>Creating image elements caused each file to be downloaded by the browser, meaning that 6 images were loaded that were never displayed to the user! It was also visually jarring, because the default image would be displayed momentarily before the selected random image was loaded.<\/p>\n<p>My quick fix was to adjust the Javascript. Instead of creating new image elements, I selected a filename at random and updated the existing source:<\/p>\n<pre><code>&lt;script language=\"javascript\" type=\"text\/javascript\"&gt;\r\n    var bannerImages = [\r\n        \"building.jpg\",\r\n        \"tree.jpg\", \r\n        \"fountain.jpg\", \r\n        \"people.jpg\", \r\n        \"painting.jpg\", \r\n        \"statue.jpg\", \r\n        \"cafe.jpg\"];\r\n    document.images[\"banner\"].src = \r\n        bannerImages[Math.floor(Math.random() * bannerImages.length)];\r\n&lt;\/script&gt;<\/code><\/pre>\n<p>That was a decent improvement, but it still loaded an unneeded image, and the default image was still momentarily visible.<\/p>\n<p>The site is running SharePoint 2010, so I decided to replace the Javascript by creating a user control. This is only the 2nd user control I&#8217;ve created, so I&#8217;ll be fairly detailed with the steps:<\/p>\n<ol>\n<li>In Visual Studio 2010, create a new Empty SharePoint project. I called mine RandomImage, and set it to deploy as a farm solution.<\/li>\n<li>Right-click the project properties and select Add &#8212; New Item &#8212; User Control. I named mine RandomImageUserControl.ascx.<\/li>\n<li>Expand the new RandomImageUserControl.aspx to access the code-behind file, RandomImageUserControl.aspx.cs.<\/li>\n<\/ol>\n<p>Here&#8217;s the code I added to the code-behind file:<\/p>\n<pre><code>{\r\n    public partial class RandomImageUserControl : UserControl\r\n    {\r\n        protected override void Render(HtmlTextWriter writer)\r\n        {\r\n            \/\/ Array of file names\r\n            string[] strArray = new string[] { \r\n                \"building.jpg\", \r\n                \"tree.jpg\", \r\n                \"fountain.jpg\", \r\n                \"people.jpg\", \r\n                \"painting.jpg\", \r\n                \"statue.jpg\", \r\n                \"cafe.jpg\" };\r\n\r\n            \/\/ Create a random-number generator object\r\n            Random randomIndex = new Random();\r\n            \/\/ Randomly select one of the images from the array\r\n            String imageSrc = images[randomIndex.Next(0, images.Length)];\r\n\r\n            \/\/ Create and render an img element\r\n            writer.AddAttribute(HtmlTextWriterAttribute.Src, imageSrc);\r\n            writer.AddAttribute(HtmlTextWriterAttribute.Alt, \"\");\r\n            writer.RenderBeginTag(HtmlTextWriterTag.Img);\r\n            writer.RenderEndTag();\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<p>I deployed it to my testing server, and added the following to the site master page just above the doctype declaration:<\/p>\n<pre><code>&lt;%@ Register \r\n    TagPrefix=\"customuc\" \r\n    TagName=\"RandomImage\" \r\n    Src=\"~\/_controltemplates\/RandomImage\/RandomImageUserControl.ascx\" %&gt;<\/code><\/pre>\n<p>And I added this in place of the default image tag:<\/p>\n<pre><code>&lt;customuc:RandomImage \r\n    id=\"RandomImage\" \r\n    runat=\"server\"&gt;&lt;\/customuc:RandomImage&gt;<\/code><\/pre>\n<p>Voila! It worked. But I had some reservations about it. What if we needed to update the images later on? Would we really want to edit, recompile, and redeploy a user control just to change an image reference?<\/p>\n<p>I decided to re-write the user control to accept the image filenames as parameters:<\/p>\n<pre><code>namespace RandomImage.CONTROLTEMPLATES.RandomImage\r\n{\r\n    public partial class RandomImageUserControl : UserControl\r\n    {\r\n\r\n        public string imageList { get; set; }\r\n\r\n        protected override void Render(HtmlTextWriter writer)\r\n        {\r\n            \/\/ Split comma-delimited list of image paths into string array\r\n            string[] images = imageList.Split(',');\r\n\r\n            \/\/ Create a random-number generator object\r\n            Random randomIndex = new Random();\r\n            \/\/ Randomly select one of the images from the array\r\n            String imageSrc = images[randomIndex.Next(0, images.Length)];\r\n\r\n            \/\/ Create and render an img element\r\n            writer.AddAttribute(HtmlTextWriterAttribute.Src, imageSrc);\r\n            writer.AddAttribute(HtmlTextWriterAttribute.Alt, \"\");\r\n            writer.RenderBeginTag(HtmlTextWriterTag.Img);\r\n            writer.RenderEndTag();\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<p>I updated the call to the user control on the master page:<\/p>\n<pre><code>&lt;customuc:RandomImage \r\n    id=\"RandomImage\" \r\n    imageList=\"building.jpg,\r\n            tree.jpg,\r\n            fountain.jpg,\r\n            people.jpg,\r\n            painting.jpg,\r\n            statue.jpg,\r\n            cafe.jpg\" \r\n    runat=\"server\"&gt;&lt;\/customuc:RandomImage&gt;<\/code><\/pre>\n<p>I was pleased with this, so I tried to deploy it to the staging server. Deploying it from within Visual Studio was simple&#8211;just right-click the project and select Deploy. Visual Studio takes care of everything. The issue with software that automates everything is that you don&#8217;t always know what it is doing. The staging server doesn&#8217;t have Visual Studio on it, though. How does a user control get installed?<\/p>\n<p>I tried copying the DLL (RandomImage.dll) into the General Assembly Cache (aka &#8220;the GAC&#8221;, located at C:\\Windows\\assembly), and copying the user control file into the 14 hive (14\/TEMPLATE\/CONTROLTEMPLATES\/RandomImage\/RandomImageUserControl.aspx). When I registered the user control and added the call to the user control to the master page, I got the following error:<\/p>\n<p><code>Could not load file or assembly '$SharePoint.Project.AssemblyFullName$' or one of its dependencies. The system cannot find the file specified.<\/code><\/p>\n<p>The right way (or <em>a<\/em> right way, at least) is to deploy a .wsp file to the server:<\/p>\n<ol>\n<li>I packaged the solution with Visual Studio (right-click the project and select Package)<\/li>\n<li>Using the SharePoint Administrator Management Shell, I added the solution:<br \/>\n<code>Add-SPSolution S:\\RandomImage\\bin\\Release\\RandomImage.wsp<\/code><\/li>\n<li>Open SharePoint Central Admin and go to System Settings &#8212; Manage Farm Solutions<\/li>\n<li>Click randomimage.wsp and Deploy Solution<\/li>\n<\/ol>\n<p>A fair amount of effort to replace the clunky, but working, Javascript. I think it&#8217;s worth it, though, for a speedier and improved user experience. If you have any comments, or suggestions as to how to improve the code, let me know!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The master page of a SharePoint site I work on loaded 7 photographic images, all over 50 kB each, to display at random as a banner adjacent to the site logo. The way it loaded the images was very inefficient: a default image was loaded in the HTML, and Javascript on the page created 7 &hellip; <a href=\"https:\/\/osric.com\/chris\/accidental-developer\/2011\/08\/sharepoint-user-control-to-display-a-random-image\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">SharePoint user control to display a random image<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[180],"tags":[202,350,200,160,201,204],"class_list":["post-426","post","type-post","status-publish","format-standard","hentry","category-sharepoint-2","tag-c","tag-javascript","tag-random","tag-sharepoint","tag-user-control","tag-visual-studio"],"_links":{"self":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts\/426","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/comments?post=426"}],"version-history":[{"count":20,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts\/426\/revisions"}],"predecessor-version":[{"id":505,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/posts\/426\/revisions\/505"}],"wp:attachment":[{"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/media?parent=426"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/categories?post=426"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/osric.com\/chris\/accidental-developer\/wp-json\/wp\/v2\/tags?post=426"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}