advanced web statistics

Silverlight ObservableCollection Bug Will Be the Death of Me

BUG: Items are sorted correctly sometimes, other times not so much.

FREQUENCY: Intermittent, never when debugging and stepping through everything, always seems to happen when I'm not.

RATING: Probably the most painful bug I've worked on in some time.

So I've got an ItemsControl in a custom XAML user control.  All this does is display an IEnumerable<T> of video items.  Simple.  To provide a better user experience we implemented an ObservableCollection<T> as the source of the ItemsControl with a Collection_Changed event so we can add one item at a time to the collection so as to not wait for the entire collection to populate before displaying to the user.  Now we're able to display the first 2 items and the scrollbar height shrinks as items are being added.  It's a nice user-experience.

Anyway, so for the implementation.  When the VideoRetrieveComplete event fires (after making a web service request for the data) we call the UpdateVideoCollection method.

UIThread.Run(delegate
{
   videoListControl.UpdateVideos(args.VideoItems);
   videoListControl.itemsControlVideoListing.DataContext = new VideoItem();
}

Notice that we're doing this in the UI Thread.  The code above is located in our Controller class.  The args.VideoItems is an IEnumerable<VideoItem> and they are sorted in the order they need to be in.  I have verified this time and time again with painful debugging.

Now time for VideoList controls properties, objects, and methods:

public int CurrentPageIndex { get; set; }
public ObservableCollection<VideoItem> ObservableCollection { get; set; }
private List<VideoItem> VideoItems = new List<VideoItem>();

Constructor where everything is initialized.  Probably important to include this.

public VideoList()
{
   CurrentPageIndex = 0;
   InitializeComponent();
   ObservableCollection = new ObservableCollection<VideoItem>();
   itemsControlVideoListing.ItemsSource = ObservableCollection;
   ObservableCollection.CollectionChanged += CollectionChanged;
}

public void UpdateVideos(List<VideoItem> videoItems)
{
   UIThread.Run(delegate
         
   {
               VideoItems.AddRange(videoItems);
               ObservableCollection.Clear();

               if (VideoItems != null && VideoItems.Count > 0)
               {
                  VideoItem videoItem = VideoItems[0];
                  VideoItems.RemoveAt(0);
                  ObservableCollection.Add(videoItem);
               }
            });
}

void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
   if (VideoItems.Count > 0)
      UIThread.Run(delegate
               
{
                  VideoItem videoItem = VideoItems[0];
                  VideoItems.RemoveAt(0);
                  ObservableCollection.Add(videoItem);
               });
}

The reason for removing an item, and then re-adding it is that this is the only way we can get our Converters to fire off, otherwise the collection hasn't changed and UI elements don't update.  For example, switching between tabs the user can add videos to their playlist.  Each time the tabs are selected and the VideoListing populates the VideoItems within that listing needs to show either an ADD / DELETE FROM PLAYLIST button depending on whether or not the item is in the playlist.  If there's another way to get those Converters to fire off I'm all ears.

So the problem is that more often than not the videos, which come in sorted correctly, are not always displayed that way.  For example, if I have 5 videos with dates 10/1/2008, 10/1/2008, 9/30/2008, 9/29/2008, 9/28/2008 sometimes the sort will be:

10/1/2008
9/30/2008
9/29/2008
9/28/2008
10/1/2008

or:

9/30/2008
9/29/2008
10/1/2008
9/28/2008
10/1/2008

You get the idea.  Could it be that we are not implementing this correctly?  Do we need to rebind the ItemsControl or is this correct?

I've been working on this bug for a day and a half now and have nothing.  I'm sure it's probably something stupid.

I'm all ears if you have anything. ANYTHING!

Oh, should probably add that if I page to the next listing of videos and then back it'll remedy itself!

kick it on DotNetKicks.com

What's Wrong With This Picture?

Tried to debug a new Silverlight application today.  By new I mean it was hosted in a different web project then the one I had been previously working on due to the fact that I needed to test some stuff locally.  I was trying for about half an hour to get this thing to debug.  The application would start to load up and then just hang on the loading animation.  A co-worker told me to make sure I had the Silverlight debugger checkbox checked.  I then go into the appropriate property tab and am greeted with this:

what's wrong with this picture? (image)

I remember this debugger option used to be located in the appropriate Debuggers group box.  Apparently when I performed my Visual Studio 2008 and .NET Framework updates my Visual Studio 2008 UI ended up getting mutated.

Very strange.

kick it on DotNetKicks.com

Way to Go Vista File Transfers!

Better grab a lunch, or 9.

kick it on DotNetKicks.com

The Zune Update Totally Sucks

Updated the Zune application software this morning at about 7:00am.  Since I had no choice in the matter, I went ahead and did it ;)

Wow.  Talk about a change... for the worst.  The application seems to lag a lot even when I have nothing else open.  If I try to listen to it with Visual Studio 2008, SQL Management Studio, and Outlook forget about it.  Too bad because those are all the things I use on a daily basis for work.  That's also when I listen to the most of my music.

Luckily I've got 4 stereos in the house wired up to my Zune player so depending on where in the house I'm working (laptop) I can listen to my music.  I've also got 2 30GB zunes for this and am thinking of buying another when the new line is released (if it hasn't been already).

Like any Microsoft product there will be a patch released for the Zune software if enough people are experiencing these symptoms and at the end of the day I'm still glad I don't use any Apple products.

Does anyone else find that the Zune software responds a lot like a poorly-written RIA (rich internet application)?  To me it responds like Silverlight applications do when they are first written; before any story board animations / overlays are added to let the user know that SOMETHING is actually happening.  Just a thought....

If anyone from Zune reads this you might want to update the Zune Card widget (see left navigation column) to utilize Silverlight instead of Flash.  It would probably be a good look since, you know; you're Microsoft and you have this new technology you want to promote.

Looks like I'll try this again later.  Maybe rebooting (again) will help.

UPDATE
Unresponsiveness of the application aside, the hardware update seems to be pretty sweet! Now I can play games while listening to tasty licks by The Chameleons.  The wireless feature is pretty sweet. I wonder if I have to be at one of 9,800 McDonald's restaurants to be able to download?  I'd guess not...

kick it on DotNetKicks.com

No Generic List FindAll Method in Silverlight 2 Beta 2

Came across a need this morning to use the FindAll method. To my dismay it wasn't there.  I know that Silverlight uses a subset of the .NET Framework but the System.Collections.Generic namespace is definitely there.

System.Collections.Generic namespace in Silverlight 2 Beta 2

You can clearly see that I'm using the namespace in the above image.

ReSharper List.FindAll Error Silverlight 2 Beta 2

Here you can see that ReSharper's background compiling caught it right away. For a second there I thought: "You know, maybe ReSharper is full of shit. This can't be right." I tried to compile to make sure (which was the case with the version 4 nightly builds).

'System.Collections.Generic.List' does not contain a definition for 'FindAll' and no extension method 'FindAll' accepting a first argument of type 'System.Collections.Generic.List' could be found (are you missing a using directive or an assembly reference?)

Weird.

kick it on DotNetKicks.com

Hacking Silverlight, ObservableCollections, & Scarface

In working with Silverlight lately I've found that there's not a lot of documentation, especially for more complex functionality.  More times than not I find myself sort of scratching my head and wondering if the solution provided is really the best way to accomplish a certain task.

Let's say you're creating an application that serves up articles (i.e. for a library search application).  You have an ItemsControl that uses a article item control as it's DataTemplate. The ItemsSource of this ItemsControl is an ObservableCollection<T> of type, I don't know; SearchResult.  The DataContext for your ItemsControl is, you guessed it; SearchResult.

Now say you have, above your search results, a little panel that provides filtering.  The filters are List<T> -bound that expand when clicked (and roll up when done). In keeping with our library search application let's pretend the filters are by year (Last Week, Last Month, Last Year, Last 2 Years, etc....) and by topic (Sociology, Psychology, Political Science, Computer Science, etc..).  The year filter allows you to select only one (the selection of a listitem triggers the list to hide and the listing of articles below to refresh).  The user can select any number of topics.  Each listitem in the topic filter has an overlay that provides button functionality such as "SELECT / DESELECT, CLEAR ALL, DONE".  When you select an item, it highlights that row.  DESELECT unhighlights the row.  DONE means you are done selecting and rolls (hides) the list back up.  CLEAR ALL is the problem child.  Behind the scenes we are storing the id for the listitem in a List<T>.  We have easy access to these on MouseLeftButtonUp due to our DataContext being set earlier.  Clicking done will trigger the enumeration of this list to build our query and then that is sent to a web service.  There is a subscription to the ArticleRefresh trigger and the ItemsControl listing is updated. Easy.

The issue is the unhighlighting of all the listitems in the topic list upon clicking CLEAR ALL.  That sounds really easy (and it may very well be!) but I haven't seemed to figure out an efficient way to do this.

In ASP.NET it was extremely easy to enumerate all the controls from within, let's say a Repeater.  You have in your ItemTemplate a control that you want to repeat.  You could write a little bit of code to enumerate every RepeaterItem and alter the display of certain text and controls within that Repeater.  It's extremely easy.

In Silverlight you don't have that luxury.  Well, you're supposed to have an easier way of doing business but I haven't yet found it.  By the way, I'm talking about Silverlight 2 Beta 2. 

My first attempt at this was to create a Converter that sets the IsSelected property based on the presence of the topic's id in the List<T> it is bound to.  I get a BAD_PROPERTY_VALUE error when that is attempted.

The next attempt was creating an event handler for the Loaded event of my topic filter control that will cast the sender to the filter object, check to see if the id of the objects DataContext is contained in the List<T>.  If it is, highlight, else, no highlight.  This works the first time the application is loaded but not on subsequent list views.  Reason being the use of the ObservableCollection<T>.  The collection itself hasn't changed, so no rebinding needs to occur.  This is probably a good thing.  What if the collection had 100's, 1000's of items?  Makes for quick UI responsiveness.

The only way I have found to accomplish this is instantiating an IEnumerable object, setting its collection to that of the ObservableCollection<T> that the filter list is bound to (public property), then setting said public property to this IEnumerable object that is, in a sense, the same exact thing.  This way the collection has changed (sort of), and the CollectionChanged event now gets fired.  The list is re-bound and we start from scratch with no highlighted rows.

That seems like kind of a hack to me.  Anyone else care to chime in?

I'll try to get a code sample but this is one of those things that I had to voice out first.  I hope it's not too hard to follow.   For some reason today I had Paul Engemann's "Push it to the Limit" in my head while trying out all sorts of different ways of accomplishing this task.  I kind of laughed to myself at the idea of a programming montage set to this song (kind of like in the South Park episode with the skiing contest. And, of course, Scarface).

For the first time EVER on this blog, musical accompaniment:

kick it on DotNetKicks.com

JSON Serialization with Silverlight Isolated Storage For the Win

I'm going to post this to help others who are killing themselves trying to figure out IsolatedStorage in Silverlight 2 Beta 2.  Ordinarily I'd post stuff like this for my own reference but I have had it beaten into my head for the past 12 straight hours.

The IsolatedStorageFile class abstracts the virtual file system for isolated storage.  It can be used to store stuff such as application settings or user login information.  The application settings being persisted on a user's machine were exactly what we needed to accomplish so that led me down this road.  I read numerous blogs, watched countless videos, and did endless searching and finally crafted my solution as a hodge-podge of all of them!

First, what didn't work.

Channel 9 had a video on "how easy it is to persist user application settings" using IsolatedStorage.  Their solution consisted of the following:

public class LocalStorageHelper
{
    private const string KEY = "FOO";

    public static object RetrieveObjectFromLocalStorage()
    {
        if (IsolatedStorageSettings.ApplicationSettings.Contains(KEY))
            return IsolatedStorageSettings.ApplicationSettings[KEY];

        return null;
    }

    public static void UpdateLocalStorageObject(object value)
    {
        if (IsolatedStorageSettings.ApplicationSettings.Contains(KEY))
            IsolatedStorageSettings.ApplicationSettings[KEY] = value;
        else
           
IsolatedStorageSettings.ApplicationSettings.Add(KEY, value);
    }
}

Simple enough.  The video presenter did all sorts of cool things like shut down the browser, open it back up, press F5 repeatedly and the storage still contained the user data.  I'm guessing this solution worked flawlessly in Beta 1.  I also had to add the checks for whether or not the ApplicationSettings contained the specified key.  Needless to say this implementation isn't very reliable.

It was then that I started looking into JSON and other storage options.  I remember in .NET 2.0 I was used to serializing objects into XML and thought I would take this route.  This was easier said than done because Silverlight is using a subset of the .NET Framework and the XML Serialization namespace didn't make it.  (NOTE: I could've used Linq XML but it was an after thought!).

Enter the DataContractJsonSerializer class.  Since we are only given a default storage of 1MB (more can be requested but the end-user has the option of shutting you down) JSON is a likely candidate since it isn't as verbose as XML.  A simple string written in a text file within the file store is more than sufficient enough to give us an instance of the object which holds the properties we want to persist.

Some code for converting an object to JSON string and vice-versa.

public static string ConvertObjectToJsonString(object input)
{
   try
   
{
      using (MemoryStream memoryStream = new MemoryStream())
      {
         DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(input.GetType());
         dataContractJsonSerializer.WriteObject(memoryStream, input);
         memoryStream.Position = 0;

         using (StreamReader streamReader = new StreamReader(memoryStream))
            return streamReader.ReadToEnd();
      }
   }
   catch (InvalidDataContractException)
   {
      return string.Empty;
   }
}

public static T ConvertJsonStringToObject<T>(string json)
{
   try
   
{
      using (MemoryStream memoryStream = new MemoryStream())
      {
         byte[] bytes = Encoding.Unicode.GetBytes(json);
         memoryStream.Write(bytes, 0, bytes.Length);
         memoryStream.Position = 0;

         DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T));

         return (T)dataContractJsonSerializer.ReadObject(memoryStream);
      }
   }
   catch (SerializationException)
   {
      return default(T);
   }
}

You might notice the InvalidDataContractException I am catching above.  Like with XML Serialization you want to mark a class & properties as Serializable.  If you don't you won't be able to serialize it.  Hence the catch block.  Here's an example of a serializable class:

using System.Runtime.Serialization;

namespace LocalStorage.Objects
{
   [DataContract]
   public class UserAccount
   
{
      [DataMember] public string EmailAddress { get; set; }
      [DataMember] public string Password { get; set; }
   }
}

I'll show an example of how to store the user account in a second.  First how to open / create this in isolated storage.

public static void SaveDataToLocalStorage(string data, string filename)
{
   try
   
{
      using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
      {
         if (!isolatedStorageFile.FileExists(filename))
         {
            using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(filename, FileMode.Create, isolatedStorageFile))
            using (StreamWriter streamWriter = new StreamWriter(isolatedStorageFileStream))
               streamWriter.Write(data);
         }
         else
         
{
            using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(filename, FileMode.Open, isolatedStorageFile))
            using (StreamWriter streamWriter = new StreamWriter(isolatedStorageFileStream))
               streamWriter.Write(data);
         }
      }
   }
   catch (IsolatedStorageException)
   {      
   }
}

public static string RetrieveDataFromLocalStorage(string filename)
{
   try
   
{
      using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
      {
         if (!isolatedStorageFile.FileExists(filename))|
            return string.Empty;

         using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(filename, FileMode.Open, isolatedStorageFile))
         using (StreamReader streamReader = new StreamReader(isolatedStorageFileStream))
            return streamReader.ReadToEnd();
      }
   }
   catch (IsolatedStorageException)
   {
      return string.Empty;
   }
}

I apologize for the mess but those are some pretty lengthy class names and descriptive variable names 8^)

So now how to use:

// instantiate our user
UserAccount user = new UserAccount
                              
{
                                 EmailAddress = "asdf@asdf.asdf"
                                 Password = "stupid"
                              
};

// convert to JSON string
string json = ConvertObjectToJsonString(user);
SaveDataToLocalStorage(json, "UserAccount.txt");

// convert back to UserAccount
string json = RetrieveDataFromLocalStorage("UserAccount.txt");

if (!string.IsNullOrEmpty(json))
{
   UserAccount account = ConvertJsonStringToObject<UserAccount>(json);
   // do stuff with userAccount here...
}

Now the user can be persisted on each site visit.  If you wanted to store the email address and password you could log your user in when they visit the application.  Think "remember me" checkbox or something similar.  Another good use would be to serialize the RSS categories and only display those articles from within your silverlight application.

The possibilities are endless.  Remember that this information is stored with the client in their AppData folder so don't put anything too private in there ;)

Easy.

UPDATE
If this is a little too cluttered for you to read might I suggest viewing the RSS feed.

kick it on DotNetKicks.com

Silverlight Databinding and Interaction with Controls

Busy, busy with Silverlight lately.  I'm starting to really enjoy it and am learning a ton.  It's still so new to me that I don't know if I'm doing everything correctly but I am getting stuff to work ;)

The biggest issue I've had with Silverlight lately is databinding and interacting with the bound data.  For example, with ASP.NET you can bind a List<Foo> to a Repeater and implement a method for ItemDataBound event that wires up each of the hyperlinks, buttons, etc... to perform certain actions when each Repeater item is databound.  In Silverlight you do not have this luxury.  The more I work with Silverlight the more I realize that you don't need this.

The way I have been working with Silverlight is the same as working with ASP.NET in that I am a big fan of encapsulation of functionality.  This means modularizing a XAML control with a C# code-behind much like an ASCX in ASP.NET.  Let's say you have 2 controls: Article, and ArticleList.  ArticleList is simply an ItemsControl of Article's. Simple.  Here is the XAML:

ArticleListing.xaml

<StackPanel x:Name="stackPanelArticleListing">
   <ItemsControl x:Name="itemsControlArticleListing">
      <ItemsControl.ItemTemplate>
         <DataTemplate>
            <Controls:Article x:Name="article" />
         </DataTemplate>
      </ItemsControl.ItemTemplate>
   </ItemsControl>
</StackPanel> 

Simple enough. All the binding syntax is in the Article.xaml.  In the Article.xaml I have a TextBox called "textArticle" that displays the entire article.

What if I have a button in my Article control that, when clicked, displays the full article in an ArticleViewer control?  It's actually pretty easy if you set the DataContext of the ItemsControl control.  I've got another Silverlight Class Library as part of my solution and I've got a class called Article.  Article looks like this:

public class Article
{
   public Guid ArticleId { get; set; }
   public string Author { get; set; }
   public string Body { get; set; }
   public string Introduction { get; set; }
   public DateTime PublishDate { get; set; }
   public string PublishDateShort { get; set; }
   public string AuthorUrl { get; set; }
   public string AuthorImageUrl { get; set; }

So when I go to bind my List<Article> to the ItemsControl I would do this:

itemsControlArticleListing.DataContext = new ArticleLibrary.Article();

var results = ArticleLibrary.Article.RetrieveAllArticles();
itemsControlArticleListing.ItemsSource = results; 

So now in my Article control I can get the current DataContext by way of the following:

TextBlock textBlock = sender as TextBlock;

if (textBlock != null)
{
   var article = textBlock.DataContext as ArticleLibrary.Article;

   if (article != null)
   {
      // set another control's text property to article stuff :D
   
}

So I set a breakpoint and you can see that my article object above won't be null:

Article != null

You can also see that I was able to get the exact object that I clicked on.  Well, you really can't see it because of the lack of screen grabs but take my word that this is the one that I clicked on.

Article object local information

Awesome right?

Sorry if this post is all over the place.  It's been a work in progress and I've been adding snippets here and there in between work!

kick it on DotNetKicks.com

So I'm Zuning Now

I've had a Zune for a little while now and am just getting around to the social side of things.  I'm a Microsoft geekboy for life so that's why I didn't get an iPod.

Peep  my uber-cool Zune username and slick Zune Card gadget on the left.

Feel free to add me to your social if you're a Zuner as well. :)

kick it on DotNetKicks.com

Using Converters for Conditional Silverlight Databinding

Yesterday I posed a question about conditional syntax and how one would accomplish this in xaml / silverlight pages & controls.  There were no responses and I'm attributing that to the fact that it is a Friday.  Anyway, after a day of much next-level blog-reading and trial-and-error I have come up with a solution that might not be the most elegant but it works.

I'm going to use a converter utility to provide this functionality.  This will be a class that implements IValueConverter.  This is is an interface that allows one to apply custom logic to a binding which is pretty much what I wanted to do in the first place.

If you are familiar with Scott Guthrie's 8-part series on Silverlight (which is fairly outdated btw with the new release of Beta 2) I will be building on the Digg example from that as that is the most pertinent "Hello World"'ey example I can think of.

So anyone familiar with Digg will know that there is a little box on the left of a story that displays how many diggs a story has.

Digg Example

That screenshot is from the example I built awhile ago following Scott's tutorial.  See how even if a story has 1 or 2 the text below still says "diggs" ?  With the example I will show you can customize that to where if a story has more than 1 digg it will read "diggs" or else it will simply read "digg".  It sounds like a very trivial task (and it kind of is) but not anywhere near as trivial as with ASP.NET.

First add a class file to your SilverlightUI class library and name it something like NumberOfDiggsConverter.cs (what I did).

Here's my class.  It's very important to implement the IValueConverter interface.

using System;
using System.Windows.Data;
using System.Globalization;

namespace SilverlightSandbox.Converters
{
   public class NumberOfDiggsConverter : IValueConverter
   
{
      public object Convert(object value, 
                              Type targetType, 
                              object parameter, 
                              CultureInfo culture)
      {
         return System.Convert.ToInt32(value) > 1 ? "diggs" : "digg";
      }

      public object ConvertBack(object value, 
                                 Type targetType, 
                                 object parameter, 
                                 CultureInfo culture)
      {
         throw new NotImplementedException();
      }
   }

Easy enough.  Notice I didn't check the value parameter for null or anything fancy.  Again, just a quick example and if you use something like this in production you might want to think about something a little better.

Now that we have our converter class we should register it and use it within our xaml user control.

Here is what my xaml looks like.

BEFORE REGISTERING CONVERTER

<UserControl x:Class="SilverlightSandbox.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">  

AFTER REGISTERING CONVERTER

<UserControl x:Class="SilverlightSandbox.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Converters="clr-namespace:SilverlightSandbox.Converters"> 

Now create a UserControl.Resources section. I added mine at the top of my page right before my main grid.

<UserControl.Resources>
   
<Converters:NumberOfDiggsConverter x:Key="DiggConverter" />
</UserControl.Resources> 

The next, and final, step is to actually implement this.  In our case we will set the text property of the digg block to the NumberOfDiggs property of my Digg object.  I'll show the before and after syntax of the # of diggs text block.

BEFORE

<TextBlock Text="diggs" /> 

AFTER

<TextBlock Text="{Binding Diggs, Converter={StaticResource DiggConverter}}" /> 

Here's the final result:

Easy.

kick it on DotNetKicks.com

<< Newer Entries Older Entries >>