Tags: , | Categories: Articles, Tutorials Posted by RTomlinson on 2/11/2011 11:02 PM | Comments (0)

Very simple one here, but one that may not seem completely obvious to those new to Silverlight.

The Scenario

A very common scenario in Silverlight is to databing the visibility of a control to a boolean value in your code. At first you may think you can just do inline binding as normal:

<Image Source="AnImage.png" Visibility="{Binding Accepted}" />

 

Today I was trying to do similar with a new project I'm working on. A StackExchange (StackOverflow family of sites) application for Windows Phone 7 that brings the popular family of sites to the mobile. In particular I was trying to indicate which answer in particular was the correct one. To do this I used the Image control (as above) to display a green tick icon, similar to that on the StackOverflow website and bind the Accepted property to controls it's visibility.

The Solution

Unfortunately the visibility property is of type System.Windows.Visibility. Therefore we need to implement IValueConverter to take our boolean property and convert that to System.Windows.Visibility. You can then add this IValueConverter implementation to your XAML as a resource and specify the converter as a part of the binding process in your XAML.

 

   1:      public class VisibilityConverter : IValueConverter
   2:      {
   3:          public object Convert(
   4:              object value,
   5:              Type targetType,
   6:              object parameter,
   7:              CultureInfo culture)
   8:          {
   9:              bool visibility = (bool)value;
  10:              return visibility ? Visibility.Visible : Visibility.Collapsed;
  11:          }
  12:   
  13:          public object ConvertBack(
  14:              object value,
  15:              Type targetType,
  16:              object parameter,
  17:              CultureInfo culture)
  18:          {
  19:              Visibility visibility = (Visibility)value;
  20:              return (visibility == Visibility.Visible);
  21:          }
  22:      }

 

And the XAML:

 

   1:  <helpers:VisibilityConverter x:Key="VisibilityConverter"></helpers:VisibilityConverter>

   1:  <Image Source="/Images/Icons/correct_answer.png" Visibility="{Binding Accepted, Converter={StaticResource VisibilityConverter}}"></Image>

 

Again it may seem a little obvious but I hope this comes in handy for those new to Silverlight databinding.

Tags: , , , | Categories: Articles Posted by RTomlinson on 1/7/2010 7:07 AM | Comments (4)

Today I spent a stupid amount of time trying to resolve an issue that had me banging my head off the desk. To save anyone else from the sheer frustration I thought I would write about it to hopefully save anyone else from wasting their time.

I began writing a custom composite control that contained a dropdownlist. This dropdownlist required data binding to a list of business objects. Simple and common scenario. I would then databind the dropdownlist to the control in the page behind (see code sample below).

   1:  using System;
   2:  using System.Web;
   3:  using System.Web.UI.WebControls;
   4:  using System.ComponentModel;
   5:   
   6:  namespace SSControls
   7:  {
   8:      public class MapControl : CompositeControl
   9:      {
  10:          public MapControl() { }
  11:   
  12:          DropDownList _ddlAccountTypes = new DropDownList();
  13:   
  14:          public DropDownList AccountTypes
  15:          {
  16:             get
  17:             {
  18:                 return _ddlAccountTypes;
  19:             }
  20:          }
  21:   
  22:          protected override void CreateChildControls()
  23:          {
  24:              Controls.Add(_ddlAccountTypes);
  25:          }
  26:      }
  27:  }

   1:  public class AccountMap : System.Web.UI.Page
   2:  {
   3:      protected void Page_Load(object sender, EventArgs e)
   4:      {
   5:        if (!IsPostBack)
   6:        {
   7:            mapControl.AccountTypes.DataSource = Accounts.GetAccounts(123);
   8:            mapControl.AccountTypes.DataBind();
   9:        }
  10:      }
  11:  }

As simple as it sounds whenever a postback was issued the data in the dropdownlist was lost. Now the first thought of any developer is probably that this is either a ViewState issue or a databinding issue.

Let's think about what happens when we perform data binding on a composite control. The benefit of inheriting from CompositeControl is that child controls have their ViewState automatically tracked and we don't have to go through the pain of the whole IPostBackEventHandler complexity and the loading and saving of ViewState.

So why do we lose our data upon postback? The problem is that ViewState is only tracked once it has been added to the Controls collection in the CreateChildControls() method. Therefore if we call DataBind() on a child control before it is added to the Controls collection then the ViewState is not being tracked. The result of this (apart from a massive headache) is that when we issue a postback we lose the ViewState information from out dropdownlist. 

The solution? As painful as it is for me to say, make sure that you data bind after your child control has been added to the controls collection, as follows:

   1:  using System;
   2:  using System.Web;
   3:  using System.Web.UI.WebControls;
   4:  using System.ComponentModel;
   5:   
   6:  namespace SSControls
   7:  {
   8:      public class MapControl : CompositeControl
   9:      {
  10:          public MapControl() { }
  11:   
  12:          DropDownList _ddlAccountTypes = new DropDownList();
  13:   
  14:          public DropDownList AccountTypes
  15:          {
  16:             get
  17:             {
  18:                 return _ddlAccountTypes;
  19:             }
  20:          }
  21:   
  22:          protected override void CreateChildControls()
  23:          {
  24:              Controls.Add(_ddlAccountTypes);
  25:              if (!Page.IsPostBack)
  26:                  _ddlAccountTypes.DataBind();
  27:          }
  28:      }
  29:  }

   1:  public class AccountMap : System.Web.UI.Page
   2:  {
   3:      protected void Page_Load(object sender, EventArgs e)
   4:      {
   5:        if (!IsPostBack)
   6:        {
   7:            mapControl.AccountTypes.DataSource = Accounts.GetAccounts(123);
   8:        }
   9:      }
  10:  }

Now when a postback is issued your dropdownlist will have it's values tracked in ViewState and you will not lose data.