Databinding on silverlight combo boxes

 

I went round the houses looking for a solution to Silverlight combo boxes not resizing when its been initially bound to a list that is empty and found out that  there is a bug with combo boxes in Silverlight which manifests only if the collection that the combobox bound to is empty the first time the combo box is bound. Even if the observable collection that the combobox is bound to changes underneath the covers, you can see that its item source reflects the new number of items but the combobox itself just doesn’t know how to re-draw itself!!

I found a few helpful links detailing how people have got round it…such as

http://silverlight.net/forums/t/48520.aspx

http://silverlight.net/themes/silverlight/forums/thread.aspx?ThreadID=65311&AspxAutoDetectCookieSupport=1

All in all, my research found 4 work-arounds to solving it, all of which work BUT were not really ideal for me

  1. Remove the combo box then add it back in BUT relies on you creating an exact duplicate so styles, location etc [not ideal in my opinion]
   1: int index =  gridWhereComboboxLives.Children.IndexOf(_myOriginalCombobox);
   2: var cb = new ComboBox();
   3: cb.ItemsSource = _myOriginalCombobox.ItemsSource;
   4: cb.DisplayMemberPath = "DisplayText";
   5: cb.Style = _myOriginalCombobox.Style;
   6: gridWhereComboboxLives.Children.RemoveAt(index);
   7: gridWhereComboboxLives.Children.Insert(index, cb);


2.    Call comboBox.Arrange which will force the combo box to re-draw itself but you have to pass in a rectangle which dictates its location [relies on you getting its location right!]

   1: var transform = _myOriginalCombobox.TransformToVisual(null);
   2: Point transform1 = transform.Transform(new Point(0, 0));
   3: Rect r = new Rect();
   4: r.Height = 100;
   5: r.Width = _myOriginalCombobox.ActualWidth;
   6: r.X = transform1.X;
   7: r.Y = transform1.Y;
   8: _myOriginalCombobox.Arrange(r);
   9:  
  10: //OR 
  11:  
  12: var transform = _myOriginalCombobox.TransformToVisual(null);
  13: Point transform1 = transform.Transform(new Point(0, 0));
  14: _myOriginalCombobox.Arrange(new Rect(transform1.X, transform1.Y, _myOriginalCombobox.ActualWidth, _myOriginalCombobox.ActualHeight));


3.    Add empty items to the databound list on initialising the view [the best solution so far as it also solves the issue of the combobox width being set to the size of the longest item in the list. But this means that you need to remember to remove these items (and put the right items in the list) at some point before you show the drop down!!  ]. One issue with this is that if 10 items where originally added, then the combobox will always be 10 items high which looks naff if say only 2 items were added to the list.

4.    Populate the list before initialising the view so that when the binding occurs, there are always items in the list BUT this is clearly not ideal as you may want to get the list from the server async at some later point on and also, what happens if the list does get populated but there genuinely are no items in the list then… we are back to square one

So the solution I came up with is extremely easy. To understand the solution, I’d suggest you familiarise yourself with the Combobox style on MSDN. Extend the combobox class, get the border that's wrapped around the popup and resize it to the item template’s desired height when the combobox is dropped down [i.e. on the DropDownOpened event]…you can also set the width so that it is not determined by the width of the longest item in the list…..works like a treat!!!

   1: public class ResizableComboBox : ComboBox
   2: {
   3:    private Border _elementBorder;
   4:    private ItemsPresenter _elementItemsPresenter;
   5:    private ContentPresenter _elementContentPresenter;
   6:  
   7:    public override void OnApplyTemplate()
   8:    {
   9:       base.OnApplyTemplate();
  10:       DropDownOpened += ResizableComboBox_DropDownOpened;
  11:  
  12:       _elementItemsPresenter = GetTemplateChild("ItemsPresenter") as ItemsPresenter;
  13:       _elementContentPresenter = GetTemplateChild("ContentPresenter") as ContentPresenter;
  14:       _elementBorder = GetTemplateChild("PopupBorder") as Border;
  15:    }
  16:  
  17:    private void ResizableComboBox_DropDownOpened(object sender, EventArgs e)
  18:    {
  19:       int numberOfItemsInCombobox = Items.Count;
  20:     
  21:       if (_elementBorder != null && numberOfItemsInCombobox > 0)
  22:       {
  23:          Dispatcher.BeginInvoke(() =>
  24:          {
  25:             _elementBorder.Height = _elementItemsPresenter.DesiredSize.Height;
  26:             _elementBorder.Width = _elementContentPresenter.ActualWidth;
  27:          });
  28:       }
  29:    }
  30: }

Enjoy!

The art of writing functional specs

No spec is the same but what remains the same is the art of writing the spec.

I don’t know if you get the feeling “where do I start from” when you have been approached to write a spec. Usually, the customer has a vague idea of what they want and explain it to you in what seems like a blurb of a seemingly excellent idea. You jot down notes madly during your initial conversation with the customer and still think “where the heck do I start from?”…

The pointers detailed in this blog have guided me through producing detailed specs which have contained “just enough” information sufficient for the right audience. I hope this will prove useful pointers…..

Firstly, I would say, consider the audience of your spec. By audience, I mean the architects that will design solutions based on the requirements in the spec, the developers that will need to understand the requirements and develop the application, the customer that will need to understand the spec from a layman's perspective and see straight away that the spec addresses all their needs, the tester that will need to understand the acceptance criteria and functionality required in order to test the developed application orthe business users who will benefit from the application.

You might instantly think, how can one spec cater for all these people…my answer will be; certainly do-able if you capture “enough” of the right information.

Next find out the key stakeholders. These may be the same people as the audience but sometimes you may have project sponsors, senior management, marketing staff or business users interested in the spec. So in this case, you are going to want to talk to these stakeholders to get their expectations\requirements while bearing in mind that its the known audience [architects, developers etc] that will use the information in the spec.  More often than not, the people involved in the requirements gathering phase  will be determined by the customer although you may request participation of people you see fit to contribute.

Arrange a meeting with the most knowledgeable person about the proposed application \ product owner. The aim of this meeting is to get a picture of what is intended. This person may provide you with a set of business cases, maybe financial or business implications as well. At this point, you would ask general questions about what the problem is, what the current solution is, what the vision of the project is, who would be involved, what the budget is and who the intended users of the system will be.

By now you would have a vague list of functionality required by the system, group functionality together then kick start the requirements gathering process. For each functionality jot down the requirements. Already your table of content is beginning to take shape. For each requirement, ask the 6 W’s [Who, What, Why, Where, When , How] you’d be amazed by how many questions you would gather together. Imagine a scenario where the customer says, “I would like to send out notification when errors occur”. It sounds straight forward initially but who would the notifications be sent to, what is the content of the notification, what errors should trigger off notifications, how will the notification be sent, when should it be sent, where would the notifications get generated …and the list goes on. Answers to these questions may even lead into discussions about flows. From the notification being sent, the user may respond and expect an action which will only happen if….The picture will have started forming.

By now you should have anoverview of the application required. You would also have a few business requirements and an understanding of any current systems which may exist. As with any application, data must flow between 2 end points. Subconsciously, scenarios would have discussed data flows for example the user will be authenticated with the server before any of the configuration data is saved. Already, there is a concept of authentication data flowing to the server from the client. There is also configuration data being mentioned. 

Start the spec by summarizing requirements into an overview section. Diagrams are always useful and you don’t have to be a UML guru to put one together. If your diagram effectively paints the picture then its good enough … you may have something similar to

image

Already, you have catered for the marketing department who more often than not  don’t want to get bugged down in the detail. They just need enough information to sell it. Sometimes the business users just look at the table of content and the screen mockups to determine functionality coverage. Instantly, you’ve satisfied these sort of customers. In addition to this overview, you’d have started building a table of content which will may now look like:

1    Document Control
1.1    Document Location
1.2    Revision History
2    Background
3    Current Solution Overview
4    High Level Requirements Summary   
5    Business Requirements   
6    Use case models
7    Functionality 1
7.1     Requirement 1
7.2     Requirement 2
7.3     Requirement 3
8    Functionality 8
8.1     Requirement 1
8.2     Requirement 2
8.3     Requirement 3

Get the customer to review what you have so far to ensure you are on the same page.

Next arrange workshops with like-minded stakeholders i.e. techies together, business users together. It will be your job to bring these varying perspectives into a consolidated spec. By now you would have a list of questions which you want answers to. Ask the relevant questions to the right disciplines. Sometimes you may find you are asking the same questions in different meetings. It doesn’t matter provided you are getting a clearer picture of the requirements. At the start of the workshops let everyone talk, listen attentively, let them express what issues they are expecting the application to resolve, ask them about the current system… they may answer your questions and new ones may be raised. Encourage discussions of scenarios and user stories. Make note of as much as you can. Sometimes you may need to provide a gap analysis, this is the point where most of the information you’ll need would be gathered. Always remember that during this process there will always be industry specific terminology being used here and there. Make a note of these, already your glossary is building up.

From the information gathered at the workshops, you can start fleshing out functionality without loosing sight of the audience. With every line you write ask yourself what information you are trying to present, think outside the box, suggest other ways of doing things [maybe include this as comments which the customer may respond to] then decide the best way to represent it. For example, a tester will like to see a flow chart which represent exceptional flows. A developer will like to see field lengths and validation required during data capture. An architect would like to know if external servers will cater for certain functionality. A business user will like to see a use case diagram showing what users can do with the application.  Where possible mock screens up. An excellent site a colleague told me about recently is http://www.balsamiq.com. Always think things through and where possible link functionality to business cases. Relate functionality where appropriate for example, if you imagine a set of configuration data which will be used in various parts of an application. Consider when the configuration data changes consider where the updates will need to be applied, what will be affected, should notification be sent, will this cause loss of data and a lot more questions should start springing to mind.

A lot of times Non functional requirements are shoved to the side until its too late to be considered. Every spec must contain a Non functional requirements section. Depending on the nature of the application, these would be requirements like performance, memory usage or requirements relating to graphical user interface constraints.

By now you should have a spec that has grown considerably from a summary to a detailed spec.

At this point, I’d say your spec is ready for review. Take a break from it, then come back to it with fresh eyes. Its difficult to spot errors or missing information from a document you wrote, and have been looking at for days. Get other people to review it. Incorporate feedback and send an initial draft to the customer. Its likely you’d get feedback like “Oh I didn’t envisage this happening this way” in which case, you have more requirements gathering to do and more writing. The spec might go through a couple of review cycles but not too many otherwise, there is probably something wrong. Either you are not accurately representing the information you’ve been given or the customer is not giving you accurate information. This will need to be addressed otherwise you’d find yourself in an endless review cycle.

Create a requirements catalogue. the requirements should be finalized by this point. You can do this as a spreadsheet with each sheet representing each piece of functionality and each entry in the sheet representing each requirements. The catalogue, at the minimum must contain the following information:


Project/System
 

the name of the application \ project
Author your name
Date the date you start writing the catalogue
Version the version of the catalogue e.g. 0.1, 0.2 for drafts and 1.0 for live versions
Spec version  the version of the functional spec the catalogue relates to
Requirement ID a consistent ID for the requirement. I would say abbreviate the functionality name and add a number e.g SavePref1
Requirement name  the name of the requirement e.g. Save User preferences 
Priority MoSCoW [Must have, Should have, Could have, Want to \Nice to have]
Spec reference  Reference to the chapter\section of the spec
Functional Requirement a description of the requirement. Usually an extract of the spec    
Description a more detailed description of the requirement and bullet points of what is needed to achieve the requirement. e.g. Request user preferences from server, report conflicts, save to server, notify all users of changes
Non-Functional Requirement  a description of any associated non functional requirements e.g. save must be asynchronous
Description a more detailed description of the requirement
Estimate An estimate of development efforts in points or time
Additional info
Comments

 

You may ask, what's the point in this when there is already a spec? Firstly as the person that wrote the spec, this exercise should not take long [I’d say a couple of hours depending on the complexity of the functionality]. A project manager will definitely instantly see value in a summarized list of the requirements detailing development efforts \ estimates. A customer may decide at this point to de-scope time demanding requirements which bring little business value. A tester may use this to kick start test case writing lastly the solution provider will definitely want to provide a cost estimate which is as accurate as possible so that the project doesn’t go over budget.

At the end of the review cycle, you should be confident that your customer is happy with the spec and is ready to sign it off!.

Simple web services gateway

I wanted a way of limiting the number of clients that could call a long running and memory intensive web method which exported or imported several thousand lines of data into my database ....so a colleague of mine suggested semaphores. I implemented a singleton class which looked like code snippet B. It all seemed honkey dorey only that we found it turned out to be a pointless use of semaphores.

Semaphores add value when there was a requirement to queue up threads so that if there were 10 threads trying to access the service via a semaphore which allowed only 3 threads, the other threads will be queued up and will wait until the executing threads completed.

Using this singleton semaphore class to limit the number of clients that could call my long running and memory intensive web method was not fully taking advantage of the queuing ability of semaphores. I was monitoring the count of threads and throwing an exception when the limit I set was reached - which is why I said it was pointless.

One other issue with using semaphores for this purpose is that if the IIS application pool was limited to say 10 threads, and 10 users attempted to call my slow running web method call, the threads will be queued which means that if an 11th thread which wanted to make a really fast web method call tried to make its request, it will get a thread aborted exception because the number of threads allowed for the app pool has been exceeded.

So .......what I did instead was to implement a really simple web services gateway which implemented IDisposable so that when called within a using, the count was incremented and on Disposal of the instance, the count is decremented. I created a static instance of it within my web service and just used it when I needed to. It works like a treat and is dead easy to implement. See code snippet A_1 and code snippet A_2.

================ CODE SNIPPET A_1 =========================

   1: private static WebServicesGateway webServicesGateway = new WebServicesGateway(["noOfThreadsPermittedForWebCall"]); 
   2:  
   3: [WebMethod] 
   4: public byte[] RunMyLongRunningMemoryIntesiveMethod() 
   5: { 
   6:     using (webServicesGateway.GatewayRequest()) 
   7:     { 
   8:  
   9:     //do something 
  10:  
  11:     } 
  12: }

================ CODE SNIPPET A_2 =========================

   1: using System; 
   2: using System.Data; 
   3: using System.Configuration; 
   4: using System.Web; 
   5: using System.Web.Security; 
   6: using System.Web.UI; 
   7: using System.Web.UI.HtmlControls; 
   8: using System.Web.UI.WebControls; 
   9: using System.Web.UI.WebControls.WebParts; 
  10:  
  11: namespace Server 
  12: { 
  13:    /// <summary> 
  14:    /// 
  15:    /// </summary> 
  16:    public class WebServicesGateway 
  17:    { 
  18:       private int maxThreadCount = 3; 
  19:       private static int currentThreadCount; 
  20:       private static Gateway gateway; 
  21:       private object instanceLock = new object(); 
  22:  
  23:       public WebServicesGateway(int threadCount) 
  24:       { 
  25:          maxThreadCount = threadCount; 
  26:          gateway = new Gateway(this); 
  27:       } 
  28:  
  29:       private void DecrementCount() 
  30:       { 
  31:          lock (instanceLock) 
  32:          { 
  33:             currentThreadCount--; 
  34:          } 
  35:       } 
  36:  
  37:       public IDisposable GatewayRequest() 
  38:       { 
  39:          lock (instanceLock) 
  40:          { 
  41:             if (currentThreadCount >= maxThreadCount) 
  42:             { 
  43:                throw new WebServicesGatewayLimitException("Gateway has reached its limit"); 
  44:             } 
  45:             currentThreadCount++; 
  46:          } 
  47:          return gateway; 
  48:       } 
  49:  
  50:       private class Gateway : IDisposable 
  51:       { 
  52:          WebServicesGateway webServicesGateway; 
  53:  
  54:          public Gateway(WebServicesGateway webServicesGateway) 
  55:          { 
  56:             this.webServicesGateway = webServicesGateway; 
  57:          } 
  58:  
  59:          public void Dispose() 
  60:          { 
  61:             this.webServicesGateway.DecrementCount(); 
  62:          } 
  63:       } 
  64:    } 
  65:  
  66:    public class WebServicesGatewayLimitException : Exception 
  67:    { 
  68:       private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 
  69:  
  70:       public WebServicesGatewayLimitException(string message) 
  71:          : base(message) 
  72:       { 
  73:          log.Error(message); 
  74:       } 
  75:       public WebServicesGatewayLimitException(string message, Exception exception) 
  76:          : base(message, exception) 
  77:       { 
  78:          log.Error(message, exception); 
  79:       } 
  80:    } 
  81: }
  82:  

================ CODE SNIPPET B =========================

   1: using System; 
   2: using System.Data; 
   3: using System.Configuration; 
   4: using System.Web; 
   5: using System.Threading; 
   6: using System.Web.Security; 
   7: using System.Web.UI; 
   8: using System.Web.UI.HtmlControls; 
   9: using System.Web.UI.WebControls; 
  10: using System.Web.UI.WebControls.WebParts; 
  11: namespace Server 
  12: { 
  13:    /// <summary> 
  14:    /// 
  15:    /// </summary> 
  16:    public class WebMethodCallLimiter : IDisposable 
  17:    { 
  18:       static WebMethodCallLimiter instance = null; 
  19:       static readonly object instanceLock = new object(); 
  20:       private static Semaphore semaphore = null; 
  21:       private static int currentThreadCount = 0; 
  22:       private static int maxThreadCount = 3;
  23:  
  24:       private WebMethodCallLimiter() 
  25:       { 
  26:         semaphore = new Semaphore(0, maxThreadCount);         
  27:       } 
  28:       public void Pool() 
  29:       {        
  30:          if (currentThreadCount >= maxThreadCount) 
  31:          { 
  32:             throw new SemaphoreReachedLimitException("Semaphore has reached its limit"); 
  33:          }
  34:  
  35:          lock (instanceLock) 
  36:          { 
  37:             currentThreadCount++; 
  38:          } 
  39:          semaphore.WaitOne(); 
  40:       }
  41:  
  42:       public void Dispose() 
  43:       { 
  44:          currentThreadCount--; 
  45:          semaphore.Release(); 
  46:       }
  47:  
  48:       public static WebMethodCallLimiter Instance 
  49:       { 
  50:          get 
  51:          { 
  52:             lock (instanceLock) 
  53:             { 
  54:                if (instance == null) 
  55:                { 
  56:                   instance = new WebMethodCallLimiter(); 
  57:                } 
  58:                return instance; 
  59:             } 
  60:          } 
  61:       }
  62:  
  63:    } 
  64:    public class SemaphoreReachedLimitException : Exception 
  65:    { 
  66:       private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 
  67:       public SemaphoreReachedLimitException(string message) 
  68:          : base(message) 
  69:       { 
  70:          log.Error(message); 
  71:       } 
  72:       public SemaphoreReachedLimitException(string message, Exception exception) 
  73:          : base(message, exception) 
  74:       { 
  75:          log.Error(message, exception); 
  76:       } 
  77:    }
  78:  
  79: }
Deleting TFS builds

If you ever wanted to write a C# utility which allows you to delete more than one tfs build at the same time you'll love me for this....

TFS TeamPlain will allow you to delete one build at a time. Visual Studio's Team Explorer for TFS 2008 now lets you delete multiple builds at the same time ..what's also cool is that you can configure the builds you will like to preserve so say, only store the last 2 failed builds and the last 2 stopped builds but preserve all successful builds.  That way you may never need a utitlty to clean up your builds...

However, like me, you may want to write a utility that cleans up the builds should you wish to preserve more or if you don't have team server 2008.....and perhaps schedule it to run as a service. In any case, what you need to do is....

  • Write a filter which takes in specific search criteria so that you can return and act on builds that match the specified criteria.

List<BuildData> buildsToAdd = new List<BuildData>();
TeamFoundationServer tfs = new TeamFoundationServer(this.tfsDetails.ServerName);
BuildController controller = (BuildController)tfs.GetService(typeof(BuildController));

BuildStore bs = (BuildStore)tfs.GetService(typeof(BuildStore));
BuildData[] builds = bs.GetListOfBuilds(this.tfsDetails.Project, this.tfsDetails.BuildType);

  • Then write the code to delete the builds. I stuck the result in a checkedListBox so that the user was able to select which of the builds from the result he'd like to delete.  

         TeamFoundationServer tfs = new TeamFoundationServer(this.tfsDetails.ServerName);
         BuildController controller = (BuildController)tfs.GetService(typeof(BuildController));
         if (!string.IsNullOrEmpty(this.tfsDetails.Project))
         {
            BuildStore bs = (BuildStore)tfs.GetService(typeof(BuildStore));
            BuildData[] builds = bs.GetListOfBuilds(this.tfsDetails.Project, this.tfsDetails.BuildType);
            foreach (string buildSelected in this.chkListOfBuilds.CheckedItems)
            {
               foreach (BuildData build in builds)
               {
                  if (buildSelected.Contains(build.BuildNumber))
                  {
                     string failure = string.Empty;

                     try
                     {
                        controller.DeleteBuild(build.BuildUri, out failure);
                     }
                     catch (Exception e)
                     {
                        //MessageBox.Show( string.Format("Build delete failed for {0} : {1}\n\n", build.BuildNumber, e.Message));
                     }

Any easy way to populate grab the list of team build types is:

 Project p = (Project)this.cmbProjects.SelectedItem;
         if (p != null && IsValidTfsServerUri(this.txtServer.Text))
         {
            TeamFoundationServer tfs = new TeamFoundationServer(this.txtServer.Text);
            VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
            ItemSet itemSet = vcs.GetItems("$/" + p.Name + "/TeamBuildTypes", VersionSpec.Latest,
            RecursionType.OneLevel, DeletedState.NonDeleted, ItemType.Folder);
            foreach (Item item in itemSet.Items)
            {
               string buildType = Path.GetFileName(item.ServerItem);
               if (!buildType.Equals("TeamBuildTypes"))
               {
                  //can add it to a combobox list .....this.cmbBuildTypes.Items.Add(buildType);
               }
            }
            this.cmbBuildTypes.Enabled = true;           
         }

12 Comments Filed Under [ MSBuild ]