<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Serkan's Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/serkani/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/serkani/feed.xml</link>
    <description>About Team Web Access</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:28:53 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Consuming VSS.SDK.js</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/consuming-vss-sdk-js</link>
      <pubDate>Mon, 30 Nov 2015 03:11:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2015/11/30/consuming-vss-sdk-js/</guid>
      <description><![CDATA[VSS.SDK.js has a new home https://github.com/Microsoft/vss-sdk, where it is being updated with each...]]></description>
      <content:encoded><![CDATA[<p>VSS.SDK.js has a new home <a href="https://github.com/Microsoft/vss-sdk">https://github.com/Microsoft/vss-sdk</a>, where it is being updated with each update of Visual Studio Team Services. It can be accessed using three options:</p>
<ol>
<li>From the repo under lib folder</li>
<li class="console">Run <code>npm install vss-sdk</code></li>
<li class="console">Run <code>bower install vss-sdk</code></li>
</ol>
<p>If a specific version is required, below options can be followed:</p>
<ol>
<li>Go to <a href="https://github.com/Microsoft/vss-sdk/releases/tag/0.90.0">https://github.com/Microsoft/vss-sdk/releases/tag/0.90.0</a> and click <strong>Source code (zip)</strong> at the bottom</li>
<li class="console">Run <code>npm install vss-sdk@0.90.0</code></li>
<li class="console">Run <code>bower install vss-sdk#0.90.0</code></li>
</ol>
<p>If you use TypeScript, the types of VSS.SDK.js are also available in typings/vss.d.ts. Additionally, types for REST Client Libraries are available in typings/tfs.d.ts.</p>
<p>Although these declare files do not exist at DefinitelyTyped repo, they can still be consumed by <a href="https://www.npmjs.com/package/tsd" target="_blank">TypeScript Definition Manager for DefinitelyTyped</a>. Here are the steps:</p>
<ol>
<li>Make sure that the dependencies are loaded using below command:
<ul>
<li class="console"><code>tsd install jquery knockout q &ndash;save</code></li>
</ul>
</li>
<li>Run below command to get vss-sdk types added to tsd.d.ts:
<ul>
<li class="console"><code>tsd link</code></li>
</ul>
</li>
<li>Add reference to typings/tsd.d.ts in your TypeScript files.</li>
</ol>
<p>Please let us know if you see any issue or what you want to see in docs and samples <a href="https://www.visualstudio.com/en-us/integrate/extensions/support/help" target="_blank">here</a>.</p>
<p><em>Follow me at </em><em><a href="https://twitter.com/serkan_inci">twitter.com/serkan_inci</a></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Documents and Samples for Visual Studio Online Extensions</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/documents-and-samples-for-visual-studio-online-extensions</link>
      <pubDate>Sat, 24 Oct 2015 05:48:58 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2015/10/24/documents-and-samples-for-visual-studio-online-extensions/</guid>
      <description><![CDATA[We have been working hard to get ready for making Visual Studio Online Extensions public and one of...]]></description>
      <content:encoded><![CDATA[<p>We have been working hard to get ready for making <a href="https://www.visualstudio.com/en-us/integrate/extensions/overview" target="_blank">Visual Studio Online Extensions</a> public and one of the most important piece for us is documentation and samples. Last couple of months, we worked hard on this and added a lot of docs and samples to our site.</p>  <p>As I mentioned in my <a href="https://blogs.msdn.com/b/serkani/archive/2015/05/22/using-typescript-for-visual-studio-online-extensions.aspx" target="_blank">last post</a>, we encourage you to use <a href="https://www.typescriptlang.org/" target="_blank">TypeScript</a> for extension development since you can get nice tooling support using the declare file we provide. Our codebase is based in TypeScript as well, which gives as a chance to write our own tool generate API docs automatically.</p>  <p>Here are list of some docs we added lately:</p>  <ul>   <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/core-sdk" target="_blank"><strong>Core Client SDK</strong></a><strong>:</strong> This is the API doc for <a href="https://raw.githubusercontent.com/Microsoft/vso-extension-samples/master/build-inspector/sdk/scripts/VSS.SDK.js" target="_blank">VSS.SDK.js</a>, which extension developers use to interact with Visual Studio Online on the client side. </li>    <li><strong>Rest Client Libraries:</strong> These are the TypeScript client libraries to talk to various REST endpoints on Visual Studio Online including:       <ul>       <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/Build/RestClient/BuildHttpClient2_1" target="_blank">Build</a> </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/Core/RestClient/CoreHttpClient2_1" target="_blank">Projects and Teams</a> </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/TestManagement/RestClient/TestHttpClient2_1" target="_blank">Test Management</a> </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/VersionControl/GitRestClient/GitHttpClient2_1" target="_blank">Git</a> </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/VersionControl/TfvcRestClient/TfvcHttpClient2_1" target="_blank">Version Control</a> </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/Work/RestClient/WorkHttpClient2_1" target="_blank">Work</a> </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/WorkItemTracking/RestClient/WorkItemTrackingHttpClient2_1" target="_blank">Work Item Tracking</a> </li>     </ul>   </li>    <li><strong>UI Controls:</strong> Controls which can be used by developers in their extensions with a less effort. VSS.SDK.js can set up everything necessary for controls (scripts and styles) which makes using controls really easy. See <a href="https://www.visualstudio.com/integrate/extensions/reference/client/core-sdk#method_init" target="_blank">VSS.init</a> and its options <a href="https://www.visualstudio.com/integrate/extensions/reference/client/api/VSS/References/VSS_SDK_Interfaces/IExtensionInitializationOptions" target="_blank">IExtensionInitializationOptions</a> for more details. Here is the list of controls we documented so far:       <ul>       <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/grid" target="_blank">Grid</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/grido" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/menubar" target="_blank">MenuBar</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/menubaro" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/tree" target="_blank">TreeView</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/treeviewo" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/combo" target="_blank">Combo</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/comboo" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/modaldialog" target="_blank">Modal dialog</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/modaldialogo" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/splitter" target="_blank">Splitter</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/splittero" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/controls/waitcontrol" target="_blank">Wait control</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/ui-controls/waitcontrolo" target="_blank">samples</a>) </li>     </ul>   </li>    <li><strong>Client Services:</strong> These are the services provided to extension developers on the client to get some operations done by the host. This might be important for some scenarios since the extensions are sandboxed. The services we provide are:       <ul>       <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/VSS/SDK/Services/ExtensionData/ExtensionDataService" target="_blank">Extension data service</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/data-storage" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/VSS/SDK/Services/Dialogs/HostDialogService" target="_blank">Host dialog service</a> (<a href="https://www.visualstudio.com/integrate/extensions/develop/using-host-dialog" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/VSS/SDK/Services/Navigation/HostNavigationService" target="_blank">Host navigation service</a> (<a href="https://www.visualstudio.com/en-us/integrate/extensions/develop/host-navigation" target="_blank">samples</a>) </li>        <li><a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/api/TFS/WorkItemTracking/Services/IWorkItemFormNavigationService" target="_blank">Work item form navigation service</a> </li>     </ul>   </li> </ul>  <p>This is a pretty big list and we are adding more each sprint. Please let us know if you see any issue or what you want to see in docs and samples <a href="https://www.visualstudio.com/en-us/integrate/extensions/support/help" target="_blank">here</a>.</p>  <p><em><font size="2">Follow me at<span class="Apple-converted-space">&#160;</span></font></em><em><font size="2"><a href="https://twitter.com/serkan_inci" target="_blank">twitter.com/serkan_inci</a></font></em></p>]]></content:encoded>
    </item>
    <item>
      <title>Using TypeScript for Visual Studio Online Extensions</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/using-typescript-for-visual-studio-online-extensions</link>
      <pubDate>Fri, 22 May 2015 10:07:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2015/05/22/using-typescript-for-visual-studio-online-extensions/</guid>
      <description><![CDATA[The new VSO extensibility model needs extensions to have a webserver today for hosting content like...]]></description>
      <content:encoded><![CDATA[<p><a href="https://blogs.msdn.com/b/serkani/archive/2015/05/04/extensions-for-visual-studio-online.aspx" target="_blank">The new VSO extensibility model</a> needs extensions to have a webserver today for hosting content like pages, javascript and css files and images. This webserver can be IIS, Node.js or something else. We are thinking to add an option in the future to host content inside VSO where the extension developers will not need to setup a website and they will provide a package which will contain all the content required by the UI integration. This will be especially helpful for integrations like menu actions where a javascript file is enough for action handlers (like <a href="https://github.com/Microsoft/vso-extension-samples/tree/master/branch-delete" target="_blank">this one</a>).</p>
<p>However, no matter a website or a package is used for an extension, communication with the host is through javascript. There may be some extensions which do not require host communication like displaying a static page inside a hub but this scenario is out of the subject of this post.</p>
<p>The only thing needs to be done for communication is adding a reference for <a href="https://raw.githubusercontent.com/Microsoft/vso-team-calendar/master/Calendar/sdk/Scripts/VSS.SDK.js" target="_blank">VSS.SDK.js</a> to the page. This lets an extension:</p>
<ol>
<li>initialize VSS.SDK for communication</li>
<li>register an action handler</li>
<li>get notified when the page is ready (to talk to host)</li>
<li>get context information about the host or extension</li>
<li>use host services like dialog or history</li>
<li>use a UI control provided by the host</li>
<li>make a rest call to VSO for build, work, code, etc.</li>
</ol>
<p>Starting from M82 (<a href="https://www.visualstudio.com/integrate/extensions/support/release-notes#m82" target="_blank">release notes</a>), we generate a TypeScript declare file <a href="https://raw.githubusercontent.com/Microsoft/vso-team-calendar/master/Calendar/scripts/ref/VSS/VSS.d.ts" target="_blank">VSS.d.ts</a> which will significantly improve the development experience if you use TypeScript (and we encourage you to do so). This declare file not only contains types for above listed communication steps but also for UI Controls and Rest Clients provided by VSO.</p>
<p>Once you add the below reference to the top of the TypeScript file, you should be good to go.</p>
<pre style="background: #181818; color: #f8f8f8;"> <span style="color: #8f9d6a;">/// &lt;reference path='../typings/VSS' /&gt;</span></pre>
<p>Please note that, <strong>you should also have jquery.d.ts, knockout.d.ts and q.d.ts right next to VSS.d.ts since some of the classes and interfaces rely on these libraries</strong>. You can find them either <a href="https://github.com/Microsoft/vso-team-calendar/tree/master/Calendar/scripts/ref/VSS" target="_blank">here</a> or in <a href="https://github.com/borisyankov/DefinitelyTyped" target="_blank">DefinitelyTyped</a> repo.</p>
<p>Then you&rsquo;ll get the intellisense for VSS module.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/7573.vss-intellisense_2CE5BF55.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/7573.vss_2D00_intellisense_5F00_2CE5BF55.png"><img style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="vss-intellisense" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/4718.vss-intellisense_thumb_03054B20.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/4718.vss_2D00_intellisense_5F00_thumb_5F00_03054B20.png" alt="vss-intellisense" width="518" height="272" border="0" /></a></p>
<h3>Declarations for UI Controls and Rest Clients</h3>
<p>As mentioned before, VSS.d.ts contains types for both UI Controls and Rest Clients. However, they are different than SDK types. VSO uses&nbsp; Asynchronous Module Definition (<a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md" target="_blank">AMD</a>) for loading javascript files and in order to use UI Controls and Rest Clients which requires the host to be instructed to setup module loader first using below code snippet. <strong>This will add necessary VSO styles and javascript files to the extension page and configure AMD loader</strong>.</p>
<pre style="background: #181818; color: #f8f8f8;"> VSS.init({
    setupModuleLoader: <span style="color: #cf6a4c;">true</span> 
 });</pre>
<p>The rest is about adding necessary require statement and start using UI controls or Rest Clients. Here is a sample for our grid:</p>
<pre style="background: #181818; color: #f8f8f8;"><span style="color: #cda869;">import</span> Controls <span style="color: #cda869;">=</span> require(<span style="color: #8f9d6a;">"VSS/Controls"</span>);
<span style="color: #cda869;">import</span> Grids <span style="color: #cda869;">=</span> require(<span style="color: #8f9d6a;">"VSS/Controls/Grids"</span>);

<span style="color: #f9ee98;">var</span> container <span style="color: #cda869;">=</span> <span style="color: #cda869;">$</span>(<span style="color: #8f9d6a;">".my-container"</span>);
<span style="color: #f9ee98;">var</span> gridOptions: Grids.IGridOptions <span style="color: #cda869;">=</span> {
    height: <span style="color: #8f9d6a;">"300px"</span>,
    width: <span style="color: #8f9d6a;">"100%"</span>,
    <span style="color: #9b703f;">source</span>: <span style="color: #f9ee98;">function</span> () {
        <span style="color: #f9ee98;">var</span> result <span style="color: #cda869;">=</span> [], i;
        <span style="color: #cda869;">for</span> (i <span style="color: #cda869;">=</span> <span style="color: #cf6a4c;">0</span>; i <span style="color: #cda869;">&lt;</span> <span style="color: #cf6a4c;">100</span>; i<span style="color: #cda869;">++</span>) {
            result[result.<span style="color: #cf6a4c;">length</span>] <span style="color: #cda869;">=</span> [i, <span style="color: #8f9d6a;">"Column 2 text"</span> <span style="color: #cda869;">+</span> i, <span style="color: #8f9d6a;">"Column 3 "</span> <span style="color: #cda869;">+</span> <span style="color: #9b859d;">Math</span>.<span style="color: #dad085;">random</span>()];
        }

        <span style="color: #cda869;">return</span> result;
    } (),
    columns: [
        { text: <span style="color: #8f9d6a;">"Column 1"</span>, index: <span style="color: #cf6a4c;">0</span>, width: <span style="color: #cf6a4c;">50</span> },
        { text: <span style="color: #8f9d6a;">"Column 2"</span>, index: <span style="color: #cf6a4c;">1</span>, width: <span style="color: #cf6a4c;">200</span>, canSortBy: <span style="color: #cf6a4c;">false</span> },
        { text: <span style="color: #8f9d6a;">"Column 3"</span>, index: <span style="color: #cf6a4c;">2</span>, width: <span style="color: #cf6a4c;">450</span> }]
};

<span style="color: #f9ee98;">var</span> grid <span style="color: #cda869;">=</span> Controls.create<span style="color: #cda869;">&lt;</span>Grids.Grid, Grids.IGridOptions<span style="color: #cda869;">&gt;</span>(Grids.Grid, container, gridOptions);</pre>
<p>Here is a sample for a Rest Client which gets the list of projects from the account where extension is hosted:</p>
<pre style="background: #181818; color: #f8f8f8;"><span style="color: #cda869;">import</span> Service <span style="color: #cda869;">=</span> require(<span style="color: #8f9d6a;">"VSS/Service"</span>);
<span style="color: #cda869;">import</span> Core_Contracts <span style="color: #cda869;">=</span> require(<span style="color: #8f9d6a;">"TFS/Core/Contracts"</span>);
<span style="color: #cda869;">import</span> Core_Client <span style="color: #cda869;">=</span> require(<span style="color: #8f9d6a;">"TFS/Core/RestClient"</span>);
<span style="color: #cda869;">import</span> WebApi_Constants <span style="color: #cda869;">=</span> require(<span style="color: #8f9d6a;">"VSS/WebApi/Constants"</span>);

<span style="color: #f9ee98;">var</span> client <span style="color: #cda869;">=</span> Service.VssConnection
    .getConnection()
    .getHttpClient(Core_Client.CoreHttpClient, WebApi_Constants.ServiceInstanceTypes.TFS);

    client.getProjects().then((projects: Core_Contracts.TeamProjectReference[]) <span style="color: #cda869;">=</span><span style="color: #cda869;">&gt;</span> {
    <span style="color: #cda869;">for</span> (<span style="color: #f9ee98;">var</span> p of projects) {
        <span style="color: #9b703f;">console</span><span style="color: #dad085;">.log</span>(`Project name: <span style="color: #cda869;">$</span>{p.<span style="color: #cf6a4c;">name</span>}, project id: <span style="color: #cda869;">$</span>{p.<span style="color: #cf6a4c;">id</span>}, state: <span style="color: #cda869;">$</span>{p.state}`);
    }
 });</pre>
<h3>How about Documentation?</h3>
<p>We are working hard to add reference and samples for our client libraries. We do not have anything yet for SDK and UI Controls but added <a href="https://www.visualstudio.com/en-us/integrate/extensions/reference/client/rest-clients" target="_blank">Reference for Rest Clients</a> recently. Even Rest Client reference has a lot of missing doc but we are filling the gaps. We are also expecting to add doc and samples for SDK and UI Controls really soon.</p>
<p>Let us know if you have any feedback <a href="https://www.visualstudio.com/en-us/integrate/extensions/support/help" target="_blank">here</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Extensions for Visual Studio Online</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/extensions-for-visual-studio-online</link>
      <pubDate>Mon, 04 May 2015 02:00:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2015/05/04/extensions-for-visual-studio-online/</guid>
      <description><![CDATA[Last week at //build conference, we announced a new extensibility model for Visual Studio Online...]]></description>
      <content:encoded><![CDATA[<p>Last week at <a href="https://www.buildwindows.com/" target="_blank">//build</a> conference, we announced a new extensibility model for Visual Studio Online which is called extensions. Part of this new model includes integration to web UI. For now, you can only contribute to:</p>
<ul>
<li>Add a hub group</li>
<li>Add a hub</li>
<li>Add an action to some popup menus and toolbars</li>
</ul>
<p>Please note that extension are in private preview right now but you can get access by <a title="joining the Visual Studio Partners program" href="https://www.vsipprogram.com/join" target="_blank">joining the Visual Studio Partners program</a>.</p>
<p>To find out more about extensions, visit below links:</p>
<ul>
<li><a href="https://blogs.msdn.com/b/visualstudioalm/archive/2015/05/01/extensions-for-visual-studio-online-rest-apis-for-tfs-2015-rc-and-more-from-build-2015.aspx" target="_blank">Extensions for Visual Studio Online, REST APIs for TFS 2015 RC, and more from Build 2015</a></li>
<li><a title="https://www.visualstudio.com/integrate/extensions/overview" href="https://www.visualstudio.com/integrate/extensions/overview" target="_blank">https://www.visualstudio.com/integrate/extensions/overview</a></li>
</ul>
<div>
<p>It is not clear when extensions are going to be available for TFS and how it will work with work item custom controls together but we will share details soon.</p>
</div>
<p>Let us know if you have any questions.</p>]]></content:encoded>
    </item>
    <item>
      <title>Attaching to saving and saved events of a Work Item in a Custom Control</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/attaching-to-saving-and-saved-events-of-a-work-item-in-a-custom-control</link>
      <pubDate>Tue, 14 Jan 2014 09:54:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2014/01/14/attaching-to-saving-and-saved-events-of-a-work-item-in-a-custom-control/</guid>
      <description><![CDATA[We have been asked lately about whether it is possible to do something before or after save...]]></description>
      <content:encoded><![CDATA[<p>We have been asked lately about whether it is possible to do something before or after save operation of a work item inside a custom control. The answer is, yes, you can do that.</p>
<p>When a change occurs in a work item, there is actually a lot of events fired like field change, revert, saving, saved, etc. All you need to do is subscribing to the work item change event and then applying appropriate filtering on the change type when the work item is bound to the form (bind event of all controls on the form is called when a work item is bound to a form).</p>
<p>Please do not forget unsubscribing during unbind. Also note that these are all read-only notifications which means none of them can be cancelled.</p>
<p>Let's see some code:</p>
<div class="tfs-syntax-highlight">
<pre>bind: <span style="color: #7f0055; font-weight: bold;">function</span> (workItem) {
    <span style="color: #7f0055; font-weight: bold;">this</span>._base(workItem);
    <span style="color: #7f0055; font-weight: bold;">this</span>._workItemChangeDelegate = <span style="color: #7f0055; font-weight: bold;">function</span>(sender, args) {
        <span style="color: #7f0055; font-weight: bold;">if</span> (args.change === <span style="color: #2a00ff;">"</span><span style="color: #2a00ff;">saving</span><span style="color: #2a00ff;">"</span>) {
            <span style="color: #3f7f59;">// Do something...</span>
        } <span style="color: #7f0055; font-weight: bold;">else</span> <span style="color: #7f0055; font-weight: bold;">if</span> (args.change === <span style="color: #2a00ff;">"</span><span style="color: #2a00ff;">saved</span><span style="color: #2a00ff;">"</span>) {
            <span style="color: #3f7f59;">// Do something...</span>
        }
    }
    
    <span style="color: #3f7f59;">// Delegate enables the specified function to run under current custom control's context</span>
    <span style="color: #3f7f59;">// so that you can access other methods inside _workItemChangeDelegate </span>
    workItem.attachWorkItemChanged(TFS.Core.delegate(<span style="color: #7f0055; font-weight: bold;">this</span>, <span style="color: #7f0055; font-weight: bold;">this</span>._workItemChangeDelegate));
}

unbind: <span style="color: #7f0055; font-weight: bold;">function</span> (workItem) {
    <span style="color: #7f0055; font-weight: bold;">this</span>._base(workItem);
    workItem.detachWorkItemChanged(<span style="color: #7f0055; font-weight: bold;">this</span>._workItemChangeDelegate);
    delete <span style="color: #7f0055; font-weight: bold;">this</span>._workItemChangeDelegate;
}
</pre>
</div>
<p>&nbsp;</p>
<p>And one last comment about "Save &amp; Close". The above events are fired from Object Model but &nbsp;"Save &amp; Close" happens in UI level which prevents custom controls to attach that event. Because we do not have any API's for UI commands, it is not possible to intervene. Sorry for any inconvenience.</p>
<p>Hope this code piece helps and <span>let us know if you have any questions or feedback.</span></p>]]></content:encoded>
    </item>
    <item>
      <title>Adding Content Files to Work Item Custom Control Extension Package</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/adding-content-files-to-work-item-custom-control-extension-package</link>
      <pubDate>Thu, 12 Jul 2012 07:41:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2012/07/12/adding-content-files-to-work-item-custom-control-extension-package/</guid>
      <description><![CDATA[In the previous 2 posts, we talked about how you can develop and deploy work item custom controls...]]></description>
      <content:encoded><![CDATA[<p>In the previous 2 posts, we talked about how you can <a href="https://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-development.aspx" target="_blank">develop</a> and <a href="https://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-deployment.aspx" target="_blank">deploy</a> work item custom controls using the new architecture of TF Web Access 2012. In the previous posts we developed work item custom controls using HTML and JavaScript. However, in a real world scenario, developers will often need to use content files like images or css for a custom control. This post is about how to include these files in a WICC extension package.</p>  <p>We will continue to use VoteButton as the sample custom control and add an icon to the button.</p>  <p>First thing you need to do is have a reference to the base URL of the module. This URL is used to construct a reference to the content files included in the extension package. Defining the base URL module scoped is better because it will be available to all the controls inside that module:</p>  <div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">   <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet">TFS.module(<span style="color: rgb(0, 96, 128);">&quot;ACME.VoteButton&quot;</span>, [<span style="color: rgb(0, 96, 128);">&quot;TFS.WorkItemTracking.Controls&quot;</span>, <span style="color: rgb(0, 96, 128);">&quot;TFS.WorkItemTracking&quot;</span>, <span style="color: rgb(0, 96, 128);">&quot;TFS.Core&quot;</span>], <span style="color: rgb(0, 0, 255);">function</span> () {<br />    <span style="color: rgb(0, 0, 255);">var</span> WITOM = TFS.WorkItemTracking,<br />        WITCONTROLS = TFS.WorkItemTracking.Controls,<br />        <span style="color: rgb(0, 0, 255);">delegate</span> = TFS.Core.<span style="color: rgb(0, 0, 255);">delegate</span>,<br />        moduleBaseUrl = <font style="background-color: rgb(255, 255, 0);">TFS.getModuleBase(<span style="color: rgb(0, 96, 128);">&quot;ACME.VoteButton&quot;</span>);</font><br /><br /><br />    <span style="color: rgb(0, 128, 0);">// Constructor for VoteButton</span><br />    <span style="color: rgb(0, 0, 255);">function</span> VoteButton(container, options, workItemType) {<br />        <span style="color: rgb(0, 0, 255);">this</span>.baseConstructor.call(<span style="color: rgb(0, 0, 255);">this</span>, container, options, workItemType);<br />    }</pre>
</div>

<p>Using this base URL, it is really easy to construct the URL to access any content file using the name specified in the extension package.</p>

<div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">
  <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet">_init: <span style="color: rgb(0, 0, 255);">function</span> () {<br />    <span style="color: rgb(0, 0, 255);">this</span>._base();<br /><br />    <span style="color: rgb(0, 128, 0);">// Create vote button</span><br />    <span style="color: rgb(0, 0, 255);">this</span>._control = $(<span style="color: rgb(0, 96, 128);">&quot;&lt;button type='submit' /&gt;&quot;</span>).appendTo(<span style="color: rgb(0, 0, 255);">this</span>._container).bind(<span style="color: rgb(0, 96, 128);">&quot;click&quot;</span>, <span style="color: rgb(0, 0, 255);">delegate</span>(<span style="color: rgb(0, 0, 255);">this</span>, <span style="color: rgb(0, 0, 255);">this</span>._onClick));<br /><br />    <span style="color: rgb(0, 128, 0);">// Add vote icon</span><br />    $(<span style="color: rgb(0, 96, 128);">&quot;&lt;img /&gt;&quot;</span>).attr(<span style="color: rgb(0, 96, 128);">&quot;src&quot;</span>,<font style="background-color: rgb(255, 255, 0);"> moduleBaseUrl + <span style="color: rgb(0, 96, 128);">&quot;vote.png&quot;</span></font>).attr(<span style="color: rgb(0, 96, 128);">&quot;align&quot;</span>, <span style="color: rgb(0, 96, 128);">&quot;absMiddle&quot;</span>).prependTo(<span style="color: rgb(0, 0, 255);">this</span>._control);<br /><br />    <span style="color: rgb(0, 128, 0);">// Add button text</span><br />    <span style="color: rgb(0, 0, 255);">this</span>._buttonText = $(<span style="color: rgb(0, 96, 128);">&quot;&lt;span /&gt;&quot;</span>).text(<span style="color: rgb(0, 96, 128);">&quot;Vote&quot;</span>).appendTo(<span style="color: rgb(0, 0, 255);">this</span>._control);<br />}</pre>
</div>

<p>The following changes also need to be made in order to have the control work correctly.</p>

<div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">
  <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet"><span style="color: rgb(0, 128, 0);">// Update the control data</span><br /><span style="color: rgb(0, 128, 0);">// Framework calls this method when the control needs to update itself, such as when:</span><br /><span style="color: rgb(0, 128, 0);">//  - work item form is bound to a specific work item</span><br /><span style="color: rgb(0, 128, 0);">//  - underlying field value has changed due to rules or another control logic</span><br />invalidate: <span style="color: rgb(0, 0, 255);">function</span> (flushing) {<br /><br />    <span style="color: rgb(0, 128, 0);">// Get the vote count from the underlying field</span><br />    <span style="color: rgb(0, 0, 255);">var</span> voteCount = <span style="color: rgb(0, 0, 255);">this</span>._getField().getValue() || 0;<br /><br />    <span style="color: rgb(0, 128, 0);">// Display the number of votes if any</span><br />    <span style="color: rgb(0, 0, 255);">if</span> (voteCount &gt; 1) {<br />        <font style="background-color: rgb(255, 255, 0);"><span style="color: rgb(0, 0, 255);">this</span>._buttonText</font>.text(voteCount + <span style="color: rgb(0, 96, 128);">&quot; votes&quot;</span>);<br />    } <span style="color: rgb(0, 0, 255);">else</span> <span style="color: rgb(0, 0, 255);">if</span> (voteCount == 1) {<br />        <font style="background-color: rgb(255, 255, 0);"><span style="color: rgb(0, 0, 255);">this</span>._buttonText</font>.text(voteCount + <span style="color: rgb(0, 96, 128);">&quot; vote&quot;</span>);<br />    } <span style="color: rgb(0, 0, 255);">else</span> {<br />       <font style="background-color: rgb(255, 255, 0);"> <span style="color: rgb(0, 0, 255);">this</span>._buttonText</font>.text(<span style="color: rgb(0, 96, 128);">&quot;Vote&quot;</span>);<br />    }<br />},<br /><br /><span style="color: rgb(0, 128, 0);">// Clear the control data</span><br /><span style="color: rgb(0, 128, 0);">// Framework calls this method when the control needs to reset its state to &quot;blank&quot;, such as when:</span><br /><span style="color: rgb(0, 128, 0);">//  - work item form is unbound from a specific work item</span><br />clear: <span style="color: rgb(0, 0, 255);">function</span> () {<br />    <font style="background-color: rgb(255, 255, 0);"><span style="color: rgb(0, 0, 255);">this</span>._buttonText</font>.text(<span style="color: rgb(0, 96, 128);">&quot;Vote&quot;</span>);<br />}</pre>
</div>

<p>Then the extension package is recreated by including the content file as well.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/8004.image_168C7F55.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/8004.image_5F00_168C7F55.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/1050.image_thumb_47ABB9F5.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/1050.image_5F00_thumb_5F00_47ABB9F5.png" width="689" height="180" /></a></p>

<p>After uploading the package to TFS, VoteButton should be seen with an icon.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/2627.image_74C0A6C3.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/2627.image_5F00_74C0A6C3.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/1651.image_thumb_264C1459.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/1651.image_5F00_thumb_5F00_264C1459.png" width="222" height="108" /></a></p>

<p>Beside images, you can have your own css file inside the package. With the following JavaScript trick, it is possible to get css file working for the document.</p>

<div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">
  <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet">$(<span style="color: rgb(0, 96, 128);">&quot;&lt;link /&gt;&quot;</span>).attr(<span style="color: rgb(0, 96, 128);">&quot;href&quot;</span>, <font style="background-color: rgb(255, 255, 0);">moduleBaseUrl + <span style="color: rgb(0, 96, 128);">&quot;my.css&quot;</span></font>)<br />    .attr(<span style="color: rgb(0, 96, 128);">&quot;type&quot;</span>, <span style="color: rgb(0, 96, 128);">&quot;text/css&quot;</span>)<br />    .attr(<span style="color: rgb(0, 96, 128);">&quot;rel&quot;</span>, <span style="color: rgb(0, 96, 128);">&quot;stylesheet&quot;</span>)<br />    .appendTo($(<span style="color: rgb(0, 96, 128);">&quot;head&quot;</span>).first());</pre>
</div>

<p>Let us know if you have any questions or feedback.</p>]]></content:encoded>
    </item>
    <item>
      <title>Work Item Custom Control Development in TF Web Access 2012 – Deployment</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/work-item-custom-control-development-in-tf-web-access-2012-deployment</link>
      <pubDate>Fri, 22 Jun 2012 16:28:21 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-deployment/</guid>
      <description><![CDATA[In the previous post, we talked about the development changes of a Work Item Custom Control in the...]]></description>
      <content:encoded><![CDATA[<p><a href="https://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-development.aspx" target="_blank">In the previous post</a>, we talked about the development changes of a Work Item Custom Control in the new version of Team Foundation Web Access. In this post, we’ll dive into details of Work Item Custom Control deployment which is completely different than the previous version.</p>  <p>In TF Web Access 2010, you needed to place the assembly which contains the Work Item Custom Control implementation along with a manifest file in one of the search folders under Web Access installation folder. The manifest file (.wicc) was necessary for Web Access to resolve details about the custom control like assembly name the control lives in and the control type name.</p>  <p>New Web Access requires a zip package to be created which includes JavaScript files and a manifest file. <b>The name of the manifest file must be manifest.xml</b> and a typical content of it is as follows:</p>  <div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">   <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet"><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">WebAccess</span> <span style="color: rgb(255, 0, 0);">version</span><span style="color: rgb(0, 0, 255);">=&quot;11.0&quot;</span><span style="color: rgb(0, 0, 255);">&gt;</span><br />  <span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">plugin</span> <span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">=&quot;Voting Button Custom Control&quot;</span> <span style="color: rgb(255, 0, 0);">vendor</span><span style="color: rgb(0, 0, 255);">=&quot;Acme&quot;</span> <span style="color: rgb(255, 0, 0);">moreinfo</span><span style="color: rgb(0, 0, 255);">=&quot;https://www.acme.com&quot;</span> <span style="color: rgb(255, 0, 0);">version</span><span style="color: rgb(0, 0, 255);">=&quot;2.0.0&quot;</span> <span style="color: rgb(0, 0, 255);">&gt;</span><br />    <span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">modules</span><span style="color: rgb(0, 0, 255);">&gt;</span><br />      <span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">module</span> <span style="color: rgb(255, 0, 0);">namespace</span><span style="color: rgb(0, 0, 255);">=&quot;Acme.VoteButton&quot;</span> <span style="color: rgb(255, 0, 0);">kind</span><span style="color: rgb(0, 0, 255);">=&quot;TFS.WorkItem.CustomControl&quot;</span><span style="color: rgb(0, 0, 255);">/&gt;</span>  <br />    <span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">modules</span><span style="color: rgb(0, 0, 255);">&gt;</span><br />  <span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">plugin</span><span style="color: rgb(0, 0, 255);">&gt;</span><br /><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">WebAccess</span><span style="color: rgb(0, 0, 255);">&gt;</span></pre>
</div>

<p>Plugin name, vendor, moreInfo and version attributes will appear in the extensions list of Web Access. It is possible to specify multiple modules inside a single extension package. Also please note that, the namespace attribute of the module should match the highlighted value below which exists in your JavaScript file and was explained in the previous post:</p>

<div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">
  <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet">TFS.module(<span style="color: rgb(0, 96, 128);"><font style="background-color: rgb(255, 255, 0);">&quot;Acme.VoteButton&quot;</font></span>,<br />    [<br />        <span style="color: rgb(0, 96, 128);">&quot;TFS.WorkItemTracking.Controls&quot;</span>,<br />        <span style="color: rgb(0, 96, 128);">&quot;TFS.WorkItemTracking&quot;</span>,<br />        <span style="color: rgb(0, 96, 128);">&quot;TFS.Core&quot;</span><br />    ],<br />    <span style="color: rgb(0, 0, 255);">function</span> () {<br />        <span style="color: rgb(0, 128, 0);">// custom control implementation</span><br />    }<br />);</pre>
</div>

<p>The kind attribute of a module specifies the type of the module. Specify <strong>TFS.WorkItem.CustomControl</strong> as the kind value which ensures Web Access will load your module whenever the custom control is needed.</p>

<p>As mentioned in the previous post, you have to have two versions of the .js file, debug and min. During the development and testing phase, you can use the debug version of the .js file by cloning and renaming it to min.js but it is suggested that, you minify your .js file when the custom control is ready for the production.</p>

<p>Now you have the .js files and the manifest file ready, you can create your package. The simplest way of doing this is to place these three files in a temporary folder, select them all, right click and send to compressed folder.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/7444.image_41F566DE.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/7444.image_5F00_41F566DE.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/7357.image_thumb_3A69F771.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/7357.image_5F00_thumb_5F00_3A69F771.png" width="556" height="172" /></a></p>

<p>You are free to specify any name for your package as it will not be used by Web Access.</p>

<p>After you created your package, you need to upload the package to Web Access and this is going to be done inside Web Access. Please note that, the scope of an extension package is for the application (or account for hosted TFS) meaning that it will be available to all project collections and projects. Extensions are not supported for <a href="https://www.tfspreview.com" target="_blank">TFS Hosted Preview</a> because there is no way to customize the work item types for now.</p>

<p>In order to navigate to extensions management page you can either navigate directly to <a href="https://tfsinstance:8080/tfs/_admin/_Extensions">https://tfsinstance:8080/tfs/_admin/_Extensions</a> page or navigate to <a href="https://tfsinstance:8080/tfs">https://tfsinstance:8080/tfs</a> and click the administration icon on the upper right corner first.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/8233.image_67A2CBF7.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/8233.image_5F00_67A2CBF7.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/3857.image_thumb_6585CD2E.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/3857.image_5F00_thumb_5F00_6585CD2E.png" width="564" height="188" /></a></p>

<p>And then click to extensions link to go to extensions management page.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/6746.image_2B2A574D.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/6746.image_5F00_2B2A574D.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/6237.image_thumb_0A36E4A6.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/6237.image_5F00_thumb_5F00_0A36E4A6.png" width="403" height="250" /></a></p>

<p>Inside the extensions management page, click the plus icon to install your package.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/0383.image_08F24BC7.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/0383.image_5F00_08F24BC7.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/4062.image_thumb_4F0308DA.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/4062.image_5F00_thumb_5F00_4F0308DA.png" width="317" height="211" /></a></p>

<p>From the dialog, click the browse button and specify the package you previously created. Then click OK button to upload the package.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/1732.image_0DF48976.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/1732.image_5F00_0DF48976.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/1030.image_thumb_54054689.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/1030.image_5F00_thumb_5F00_54054689.png" width="451" height="226" /></a></p>

<p>By default, newly installed extensions are disabled. You need to activate the extension package by clicking “Enable” button on the right. Then click “OK” to pass the confirmation.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/2061.image_12F6C725.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/2061.image_5F00_12F6C725.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/7183.image_thumb_2B1A3180.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/7183.image_5F00_thumb_5F00_2B1A3180.png" width="570" height="80" /></a></p>

<p>Also note that, as we mentioned earlier, you can see the extension details you specified in the manifest file in this list.</p>

<p>After having the extension package installed, you need to change the definition of the work item type which you want to add the custom control to. You can use witadmin command line tool to export and import work item type definitions. </p>

<p>On a computer which has Visual Studio installed, open the developer command prompt from All Programs\Visual Studio\Visual Studio Tools. Then export the desired work item type definition using the following command:</p>

<p><font style="background-color: rgb(0, 0, 0);" color="#ffffff" face="Courier New">witadmin exportwitd /n:Bug /f:c:\temp\bug.xml /collection:https://tfsinstance:8080/tfs/collectionname /p:projectname</font></p>

<p>Open the exported work item type definition from the file path you specified in the command and add the field definition to Fields section if necessary (you can use the existing fields).</p>

<div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">
  <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet"><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">FIELD</span> <span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">=&quot;VoteButton&quot;</span> <span style="color: rgb(255, 0, 0);">refname</span><span style="color: rgb(0, 0, 255);">=&quot;ACME.VoteButton&quot;</span> <span style="color: rgb(255, 0, 0);">type</span><span style="color: rgb(0, 0, 255);">=&quot;Integer&quot;</span><span style="color: rgb(0, 0, 255);">&gt;</span><br />  <span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">HELPTEXT</span><span style="color: rgb(0, 0, 255);">&gt;</span>Vote button<span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">HELPTEXT</span><span style="color: rgb(0, 0, 255);">&gt;</span><br /><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">FIELD</span><span style="color: rgb(0, 0, 255);">&gt;</span></pre>
</div>

<p>Then add the necessary entry to Form\Layout section for your custom control.</p>

<div style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: rgb(244, 244, 244);" id="codeSnippetWrapper">
  <pre style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: &quot;Courier New&quot;, courier, monospace; font-size: 8pt; direction: ltr; background-color: rgb(244, 244, 244);" id="codeSnippet"><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">Control</span> <span style="color: rgb(255, 0, 0);">FieldName</span><span style="color: rgb(0, 0, 255);">=&quot;ACME.VoteButton&quot;</span> <span style="color: rgb(255, 0, 0);">Type</span><span style="color: rgb(0, 0, 255);">=&quot;VoteButton&quot;</span> <span style="color: rgb(255, 0, 0);">Label</span><span style="color: rgb(0, 0, 255);">=&quot;Vote&quot;</span> <span style="color: rgb(255, 0, 0);">LabelPosition</span><span style="color: rgb(0, 0, 255);">=&quot;Left&quot;</span> <span style="color: rgb(0, 0, 255);">/&gt;</span></pre>
</div>

<p>Save the file and import the work item type definition using the following command to make your custom control appear in the work item form.</p>

<p><font style="background-color: rgb(0, 0, 0);" color="#ffffff" face="Courier New">witadmin importwitd /f:c:\temp\bug.xml /collection:https://tfsinstance:8080/tfs/collectionname /p:projectname</font></p>

<p>You’re done. After connecting to web access and opening a work item which has the custom control, you can see it in the form.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/0564.image_06C63FF6.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/0564.image_5F00_06C63FF6.png"><img style="display: inline; background-image: none;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/19/21/metablogapi/3782.image_thumb_199AC3A0.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-19-21-metablogapi/3782.image_5F00_thumb_5F00_199AC3A0.png" width="499" height="338" /></a></p>

<p>While implementing the custom control, package creation and upload steps will probably occur several times and we know that it is not fun. However, we are planning to make improvements on this area to have a seamless development environment. At the same time, you can refer to <a href="https://blogs.msdn.com/b/edhintz/archive/2012/06/22/safely-test-a-javascript-change-without-touching-the-server-a-huge-time-sever.aspx" target="_blank">this blog post about a Fiddler trick</a> to be able to change your JavaScript file without ever needing to install your package again and again.</p>

<p>Let us know if you have any questions or feedback.</p>]]></content:encoded>
    </item>
    <item>
      <title>Work Item Custom Control Development in TF Web Access 2012 - Development</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/work-item-custom-control-development-in-tf-web-access-2012-development</link>
      <pubDate>Fri, 22 Jun 2012 13:54:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-development/</guid>
      <description><![CDATA[One of the biggest investments we have made in the new version of Web Access is on the Work Item...]]></description>
      <content:encoded><![CDATA[<p>One of the biggest investments we have made in the new version of Web Access is on the Work Item Tracking area. In TF Web Access 2010, we used to rely on WIT Client Object Model running on the server and it had been causing a number of issues (especially around shared cache) since it was initially designed to work for a single user through Visual Studio Team Explorer.</p>
<p>TF Web Access 2012 has a completely new architecture for Work Item Tracking where the rule processing logic is moved from the server to the browser. WIT Client Object Model is not used anymore and there is a thin Object Model written in JavaScript runs in the browser. The rules are executed in the browser and a direct communication is made to the server via XHR for only a few operations like save. Because there is no need for a roundtrip to the server to process the rules, performance significantly improved.</p>
<p>These changes impacted our Work Item Custom Control Development story significantly as you might have expected. We can categorize the changes in 2 areas: development and deployment. This post covers the development only and deployment is going to be a subject of another blog post.</p>
<p>In TF Web Access 2010, you needed to work on both server and client side when you were developing a custom control. Server side code was needed to interact with the work item object where you needed to inherit your custom control from IWorkItemWebControl. At the same time, JavaScript code needed in order to handle the UI interaction.</p>
<p>In the new version of Web Access, there is no server side development involved. Everything happens in the browser meaning that custom controls are written completely in JavaScript. Along with Web Access framework, <a href="https://www.jquery.com" target="_blank">jQuery</a> and <a href="https://www.jqueryui.com" target="_blank">jQuery UI</a> is also available for custom control developers.</p>
<p>You can start implementing your custom control with an empty JavaScript file. When specifying a name for your .js file, you'll need to have 2 separate versions of your JavaScript file for different flavors which is debug and min. If you chose a name like Acme.VoteButton for your JavaScript file, you'll need to have two files named Acme.VoteButton.debug.js and Acme.VoteButton.min.js. Web Access module loading system will then decide which file to load. We can ignore minified version for now, we&rsquo;ll talk about more on this in the deployment section.</p>
<p>The next thing you are going to do is define a module for your custom control(s). This is necessary to make your .js file integrate with the Web Access module loader so that it can take the advantage of on-demand loading and automatic flavor selection.</p>
<div id="codeSnippetWrapper" style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: 'Courier New', courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: #f4f4f4;">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: 'Courier New', courier, monospace; font-size: 8pt; direction: ltr; background-color: #f4f4f4;">TFS.module(<span style="color: #006080;">"Acme.VoteButton"</span>,<br />    [<br />        <span style="color: #006080;">"TFS.WorkItemTracking.Controls"</span>,<br />        <span style="color: #006080;">"TFS.WorkItemTracking"</span>,<br />        <span style="color: #006080;">"TFS.Core"</span><br />    ],<br />    <span style="color: #0000ff;">function</span> () {<br />        <span style="color: #008000;">// custom control implementation</span><br />    }<br />);</pre>
</div>
<p>Let&rsquo;s get into details of this expression.</p>
<p>TFS is a global variable belonging to Web Access framework which provides a utility method to define your module.</p>
<p>The first parameter of the module is a string which specifies a namespace for the module. Please note that this namespace should match the filename you specified for your .js file (the part before flavor).</p>
<p>The second parameter is an array of strings which specifies the dependencies of your module. The list in the above line is a typical list for the custom control development. Web Access module loader makes sure that the dependent modules are first loaded before your module gets executed.</p>
<p>The last parameter is a function which gets executed when the module is loaded and the actual module implementation lives in here. Optionally you can expose anything you want from your module by return an object.</p>
<p>The next step is adding shortcuts for common framework objects and functions to the top of main function. This step is optional but it makes the code cleaner and more readable.</p>
<div id="codeSnippetWrapper" style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: 'Courier New', courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: #f4f4f4;">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: 'Courier New', courier, monospace; font-size: 8pt; direction: ltr; background-color: #f4f4f4;"><span style="color: #0000ff;">var</span> WITOM = TFS.WorkItemTracking,<br />    WITCONTROLS = TFS.WorkItemTracking.Controls,<br />    <span style="color: #0000ff;">delegate</span> = TFS.Core.<span style="color: #0000ff;">delegate</span>;</pre>
</div>
<p>Then you can start implementing your custom control. The custom control <strong>must to be inherited from WorkItemControl</strong> which is provided by TFS.WorkItemTracking.Controls module. You&rsquo;ll also leverage the inheritance support of Web Access framework by using inherit utility function.</p>
<p>First, you define the constructor of your custom control. You never instantiate your custom control directly. It is going to be instantiated by Web Access. The only thing you need to do is register your custom control and we will get to that soon.</p>
<div id="codeSnippetWrapper" style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: 'Courier New', courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: #f4f4f4;">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: 'Courier New', courier, monospace; font-size: 8pt; direction: ltr; background-color: #f4f4f4;"><span style="color: #008000;">// Constructor for VoteButton</span><br /><span style="color: #0000ff;">function</span> VoteButton(container, options, workItemType) {<br />    <span style="color: #0000ff;">this</span>.baseConstructor.call(<span style="color: #0000ff;">this</span>, container, options, workItemType);<br />}</pre>
</div>
<p>And then your control implementation takes place by inheriting it from WorkItemControl. WorkItemControl provides a number of functions to be overridden by the custom control which is called during the life cycle of a custom control like bind, unbind, invalidate and flush.</p>
<p>&nbsp;</p>
<div id="codeSnippetWrapper" style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: 'Courier New', courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: #f4f4f4;">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: 'Courier New', courier, monospace; font-size: 8pt; direction: ltr; background-color: #f4f4f4;"><span style="color: #008000;">// VoteButton inherits from WorkItemControl</span><br />VoteButton.inherit(WITCONTROLS.WorkItemControl, {<br />    _control: <span style="color: #0000ff;">null</span>,<br /><br />    <span style="color: #008000;">// Initialize the control UI without data (in "blank" state).</span><br />    <span style="color: #008000;">// Framework calls this method when the control needs to render its initial UI</span><br />    <span style="color: #008000;">// Notes: </span><br />    <span style="color: #008000;">// - The work item data is NOT available at this point</span><br />    <span style="color: #008000;">// - Keep in mind that work item form is reused for multiple work items </span><br />    <span style="color: #008000;">// by binding/unbinding the form to work item data</span><br />    _init: <span style="color: #0000ff;">function</span> () {<br />        <span style="color: #0000ff;">this</span>._base();<br />        <span style="color: #008000;">// Initialize your control by creating some UI elements and attaching to events</span><br />    }<br />});</pre>
</div>
<p>Finally, the custom control must be registered using a control name. The control name is the name which is used in the work item type definition. When a work item form is rendered, Web Access looks for a registered control for the specified control name and if exists, it creates an instance of the registered control by providing a container, options and the work item type.</p>
<div id="codeSnippetWrapper" style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: 'Courier New', courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: #f4f4f4;">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: 'Courier New', courier, monospace; font-size: 8pt; direction: ltr; background-color: #f4f4f4;"><span style="color: #008000;">// Register a work item custom control called "VoteButton"</span><br />WITCONTROLS.registerWorkItemControl(<span style="color: #006080;">"VoteButton"</span>, VoteButton);</pre>
</div>
<p>Here is a list of most commonly used functions for a work item control:</p>
<p><strong>_init()</strong></p>
<p>This is called when a control is created. At this point, there is no work item bound to the control yet. When you think of Work Items View in Web Access, there is a possibility that a work item can be visible and invisible multiple times (especially when navigating through result of a query using keyboard). A control is not created every time it is displayed. Instead, it is created at first appearance and bound to the current work item. When another work item is displayed, control is unbound from the previous work item and bound to the new one (if the work items are of the same type).</p>
<p><strong>bind(workItem)</strong></p>
<p>This method is called when the control is being bound to a new work item.</p>
<p><strong>unbind(workItem)</strong></p>
<p>This method is called when the control is no longer bound to the specified work item</p>
<p><strong>invalidate(flushing)</strong></p>
<p>This method is called when the control needs to display with the current value (which is a field change caused by work item refresh, revert or save). If flushing is true then the value is being written to the work item field.</p>
<p><strong>getControlValue()</strong></p>
<p>This method is called to get the value of the control to write to the corresponding Work Item Tracking field</p>
<p><strong>cleanup()</strong></p>
<p>This method is called to allow the control to release reference to work item, detach from events, set members to null to free memory which is called after unbind.</p>
<p><strong>clear()</strong></p>
<p>This method is called to set control value to empty which is called after cleanup.</p>
<p><strong>_container</strong></p>
<p>This property is a jQuery object (DIV) which contains the control and sub elements are placed.</p>
<p><strong>_getField()</strong></p>
<p>This method gets the work item form field that corresponds to this control. _getField().getValue() and _getField().setValue(value) are used to read and modify the underlying work item fields. This method returns null if no field is associated with the control in the work item type definition.</p>
<p>And below is the complete content of the sample custom control.</p>
<div id="codeSnippetWrapper" style="margin: 20px 0px 10px; padding: 4px; border: 1px solid silver; width: 97.5%; text-align: left; line-height: 12pt; overflow: auto; font-family: 'Courier New', courier, monospace; font-size: 8pt; cursor: text; direction: ltr; max-height: 200px; background-color: #f4f4f4;">
<pre id="codeSnippet" style="margin: 0em; padding: 0px; width: 100%; text-align: left; color: black; line-height: 12pt; overflow: visible; font-family: 'Courier New', courier, monospace; font-size: 8pt; direction: ltr; background-color: #f4f4f4;"><span style="color: #008000;">// Register this module as "ACME.VoteButton" and declare </span><br /><span style="color: #008000;">// dependencies on TFS.WorkItemTracking.Controls, TFS.WorkItemTracking and TFS.Core modules</span><br />TFS.module(<span style="color: #006080;">"Acme.VoteButton"</span>,<br />    [<br />        <span style="color: #006080;">"TFS.WorkItemTracking.Controls"</span>,<br />        <span style="color: #006080;">"TFS.WorkItemTracking"</span>,<br />        <span style="color: #006080;">"TFS.Core"</span><br />    ],<br />    <span style="color: #0000ff;">function</span> () {<br /><br />    <span style="color: #008000;">// module content</span><br /><br />    <span style="color: #0000ff;">var</span> WITOM = TFS.WorkItemTracking,<br />        WITCONTROLS = TFS.WorkItemTracking.Controls,<br />        <span style="color: #0000ff;">delegate</span> = TFS.Core.<span style="color: #0000ff;">delegate</span>;<br /><br />    <span style="color: #008000;">// Constructor for VoteButton</span><br />    <span style="color: #0000ff;">function</span> VoteButton(container, options, workItemType) {<br />        <span style="color: #0000ff;">this</span>.baseConstructor.call(<span style="color: #0000ff;">this</span>, container, options, workItemType);<br />    }<br /><br />    <span style="color: #008000;">// VoteButton inherits from WorkItemControl</span><br />    VoteButton.inherit(WITCONTROLS.WorkItemControl, {<br />        _control: <span style="color: #0000ff;">null</span>,<br /><br />        <span style="color: #008000;">// Initialize the control UI without data (in "blank" state).</span><br />        <span style="color: #008000;">// Framework calls this method when the control needs to render its initial UI</span><br />        <span style="color: #008000;">// Notes: </span><br />        <span style="color: #008000;">// - The work item data is NOT available at this point</span><br />        <span style="color: #008000;">// - Keep in mind that work item form is reused for multiple work items </span><br />        <span style="color: #008000;">// by binding/unbinding the form to work item data</span><br />        _init: <span style="color: #0000ff;">function</span> () {<br />            <span style="color: #0000ff;">this</span>._base();<br />            <span style="color: #0000ff;">this</span>._control = $(<span style="color: #006080;">"&lt;button type='submit'&gt;Vote&lt;/button&gt;"</span>).appendTo(<span style="color: #0000ff;">this</span>._container).bind(<span style="color: #006080;">"click"</span>, <span style="color: #0000ff;">delegate</span>(<span style="color: #0000ff;">this</span>, <span style="color: #0000ff;">this</span>._onClick));<br />        },<br /><br />        <span style="color: #008000;">// Update the control data</span><br />        <span style="color: #008000;">// Framework calls this method when the control needs to update itself, such as when:</span><br />        <span style="color: #008000;">// - work item form is bound to a specific work item</span><br />        <span style="color: #008000;">// - underlying field value has changed due to rules or another control logic</span><br />        invalidate: <span style="color: #0000ff;">function</span> (flushing) {<br /><br />            <span style="color: #008000;">// Get the vote count from the underlying field</span><br />            <span style="color: #0000ff;">var</span> voteCount = <span style="color: #0000ff;">this</span>._getField().getValue() || 0;<br /><br />            <span style="color: #008000;">// Display the number of votes if any</span><br />            <span style="color: #0000ff;">if</span> (voteCount &gt; 1) {<br />                <span style="color: #0000ff;">this</span>._control.text(voteCount + <span style="color: #006080;">" votes"</span>);<br />            } <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (voteCount == 1) {<br />                <span style="color: #0000ff;">this</span>._control.text(voteCount + <span style="color: #006080;">" vote"</span>);<br />            } <span style="color: #0000ff;">else</span> {<br />                <span style="color: #0000ff;">this</span>._control.text(<span style="color: #006080;">"Vote"</span>);<br />            }<br />        },<br /><br />        <span style="color: #008000;">// Clear the control data</span><br />        <span style="color: #008000;">// Framework calls this method when the control needs to reset its state to "blank", such as when:</span><br />        <span style="color: #008000;">// - work item form is unbound from a specific work item</span><br />        clear: <span style="color: #0000ff;">function</span> () {<br />            <span style="color: #0000ff;">this</span>._control.text(<span style="color: #006080;">"Vote"</span>);<br />        },<br /><br />        <span style="color: #008000;">// Handle the click event on the vote button</span><br />        <span style="color: #008000;">// Note: This is a private method for this control</span><br />        _onClick: <span style="color: #0000ff;">function</span> () {<br />            <span style="color: #008000;">// Get the vote count from the underlying field</span><br />            <span style="color: #0000ff;">var</span> voteCount = <span style="color: #0000ff;">this</span>._getField().getValue() || 0;<br /><br />            <span style="color: #008000;">// Increment vote count</span><br />            voteCount++;<br /><br />            <span style="color: #008000;">// Store new vote count in the underlying field</span><br />            <span style="color: #0000ff;">this</span>._getField().setValue(voteCount);<br /><br />        }<br /><br />    });<br /><br /><br />    <span style="color: #008000;">// Register this module as a work item custom control called "VoteButton"</span><br />    WITCONTROLS.registerWorkItemControl(<span style="color: #006080;">"VoteButton"</span>, VoteButton);<br /><br />    <span style="color: #0000ff;">return</span> {<br />        VoteButton: VoteButton<br />    };<br />});</pre>
</div>
<p>In the next post, we are going to talk about the deployment of a Work Item Custom Control.</p>
<p>Let us know if you have any questions or feedback.</p>]]></content:encoded>
    </item>
    <item>
      <title>Specifying TFS URL explicitly for Team Web Access 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/specifying-tfs-url-explicitly-for-team-web-access-2010</link>
      <pubDate>Wed, 11 Apr 2012 07:29:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2012/04/11/specifying-tfs-url-explicitly-for-team-web-access-2010/</guid>
      <description><![CDATA[We have been getting questions lately about how you can specify TFS (Team Foundation...]]></description>
      <content:encoded><![CDATA[<p>We have been getting questions lately about how you can specify TFS (Team Foundation Server)&nbsp;URL explicitly for Team Web Access 2010. When communicating to TFS application, Web Access uses the following order to resolve TFS URL:</p>
<ul>
<li>Get the web.config setting</li>
<li>If no web.config setting is specified, use server's machine name to construct the URL</li>
<li>If machine name is not obtainable, use "localhost" to construct the URL</li>
</ul>
<p>By default, there is no setting in web.config which causes Web Access to use machine name. However, there might be situations like TFS is configured to use a&nbsp;<span>fully-qualified domain name. Adding&nbsp;</span>FQDN to web.config would solve the issue in this case.</p>
<p>Here is a sample setting (which should be placed under <span style="font-family: 'courier new', courier;"><span style="color: #993300;">configuration</span><span style="color: #0000ff;">/</span><span style="color: #993300;">webAccessSettings</span>)</span>:</p>
<pre><span style="font-family: 'courier new', courier;"><span style="color: #0000ff;">&lt;!--</span><span style="color: #008000;"> Specifies the default Team Foundation Server to initially connect</span></span><br /><span style="font-family: 'courier new', courier; color: #008000;">when Integrated Windows Authentication is enabled. When more than </span><br /><span style="font-family: 'courier new', courier; color: #008000;">one server is specified, these servers are displayed as a selection on </span><br /><span style="font-family: 'courier new', courier;"><span style="color: #008000;">the login form.</span> <span style="color: #0000ff;">--&gt;</span></span><br /><span style="font-family: 'courier new', courier;"><span style="color: #0000ff;">&lt;</span><span style="color: #993300;">tfServers</span><span style="color: #0000ff;">&gt;</span></span><br /><span style="font-family: 'courier new', courier;"><span style="color: #0000ff;"> &lt;</span><span style="color: #993300;">add</span> <span style="color: #ff0000;">name</span>="<span style="color: #0000ff;">https://tfs.mycompany.com:8080/tfs</span>" <span style="color: #0000ff;">/&gt;</span></span><br /><span style="font-family: 'courier new', courier;"><span style="color: #0000ff;">&lt;/</span><span style="color: #993300;">tfServers</span><span style="color: #0000ff;">&gt;</span></span></pre>
<p>Let us know if you have any questions or feedback about this.</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>How to Bulk Edit Work Items in Team Web Access 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/serkani/how-to-bulk-edit-work-items-in-team-web-access-2010</link>
      <pubDate>Fri, 22 Jan 2010 09:48:00 GMT</pubDate>
      <dc:creator><![CDATA[Serkan Inci]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/serkani/2010/01/22/how-to-bulk-edit-work-items-in-team-web-access-2010/</guid>
      <description><![CDATA[Team Web Access had bulk work item editing feature since TeamPlain times but it was in a really...]]></description>
      <content:encoded><![CDATA[Team Web Access had bulk work item editing feature since TeamPlain times but it was in a really limited manner, where you were only provided a number of core fields to change like Assigned To, State, Reason, Area Path, Iteration Path and Notes for the history. When the work item types or states of the selected work items were different, it wasn't even possible to change State and Reason Fields. 
<P>Another limitation with that implementation was to the lack of providing additional steps if an error occurred when the work item was saved.</P>
<P>We came up with a new design in Team Web Access 2010 where you can pick the fields to change yourself from a list of alternatives, pause and resume the operation and be able to jump to the failed work item easily.</P>
<P>To access the new bulk editing window, open up a query result and select the work items you want to bulk edit.</P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit1_2.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit1_2.png" target=_blank mce_href="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit1_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=bulkedit1 border=0 alt=bulkedit1 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit1_thumb.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit1_thumb.png" width=534 height=332 mce_src="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit1_thumb.png"></A> </P>
<P>Click "Tools" from the toolbar and then click "Bulk Edit Selected Work Items…".</P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit2_2.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit2_2.png" target=_blank mce_href="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit2_2.png"><IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title=bulkedit2 border=0 alt=bulkedit2 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit2_thumb.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit2_thumb.png" width=534 height=333 mce_src="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit2_thumb.png"></A> </P>
<P>The new bulk editing window shows up with the selected work items listed at the bottom part of the windows.</P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit3_2.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit3_2.png" target=_blank mce_href="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit3_2.png"><IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=bulkedit3 border=0 alt=bulkedit3 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit3_thumb.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit3_thumb.png" width=534 height=318 mce_src="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit3_thumb.png"></A> </P>
<P>You can start to pick the fields from the fields section and you can also select as many fields as you want by clicking the plus icon.</P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit4_2.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit4_2.png" target=_blank mce_href="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit4_2.png"><IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=bulkedit4 border=0 alt=bulkedit4 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit4_thumb.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit4_thumb.png" width=534 height=318 mce_src="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit4_thumb.png"></A> </P>
<P>Once you are finished with setting the new values for the selected work items you can start the save operation by clicking "Start" button. Please note that you have the ability to pause and resume the operation as well.</P>
<P>At this point, we should mention more about the list of fields especially how the it is populated. The fields are extracted from the UI layout of the work item type definition which means <STRONG>only the fields which are bound to a visible control </STRONG>are displayed in the fields drop down. </P>
<P>What happens if the work item types of the selected items differ? We make <STRONG>a union operation on the field name</STRONG> in this case to populate the fields. This design seems to be more elastic but also might cause errors when a work item is saved as each work item type has its unique UI and work flow.</P>
<P>With the new design, when saving of a work item fails, <STRONG>it is possible to jump to the work item editor by clicking the work item link where the applied fields changes are pre-populated on the editor</STRONG>.</P>
<P><STRONG><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit5_2.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit5_2.png" target=_blank mce_href="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit5_2.png"><IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=bulkedit5 border=0 alt=bulkedit5 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit5_thumb.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit5_thumb.png" width=534 height=318 mce_src="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit5_thumb.png"></A> </STRONG></P>
<P>It's easy to fix the change on the editor from this point as the wrongly set fields are highlighted.</P>
<P><A href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit6_2.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit6_2.png" target=_blank mce_href="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit6_2.png"><IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=bulkedit6 border=0 alt=bulkedit6 src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit6_thumb.png" original-url="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit6_thumb.png" width=534 height=334 mce_src="https://blogs.msdn.com/blogfiles/serkani/WindowsLiveWriter/HowtoBulkEditWorkItemsinTeamWebAccess201_AD60/bulkedit6_thumb.png"></A> </P>
<P>Please let us know if you have any questions or feedback about this feature.</P>]]></content:encoded>
    </item>
  </channel>
</rss>