Anything They Can Do Why can't you?

2Feb/100

Silverlight Temp File Issue

I don't know how well known this issue is with Silverlight or exactly what versions that it effects I saw a few form posts about it. But my company has several applications written in Silverlight that use Web Services and it affects all of them. When Silverlight calls a web service it seems to create a temp file of exactly 20,971,520 bytes (exactly 20MB) each time . This is not a big deal if you call a web service only once or even ten times for that matter but when you have your app set to call it every 10 seconds at this rate you application will require 120MB per minute of hard disk space to continue running. It seems that when you reload the page the temp files are cleared but if you want the app to run for weeks on end to drive a display for example you have to manually force them to be cleared out. The files will be created in the %temp% folder and will follow a naming convention of XCP*.tmp (XCP833C.tmp, XCP6FAB.tmp, ect)

This is not so much a bug as something that you need to keep in mind when your using Silverlight to constantly refresh data from the server.

The fix for this is as follows:

GC.Collect();

If you just put that one line of code at the end of your Async Completed handler and all you massive hard drive usage issues will be a thing of the past.

It should also be noted that I can't recreate this issue when the app is running off the development server built into Visual Studio. It seems to only have this issue once I publish to IIS.

29Oct/090

Simple Tree Part 1

For those of you that have been enjoying some of the features in the Silverlight Toolkit over on codeplex like I have been you may have noticed the same things that I have about it. First it works but thats a given after all its made by the same company that brought you Songsmith, and since its from Microsoft you know its easy to use.

But other than that it does way more with visual states then the average developer can probably understand given our limited understanding of the ever so complicated art of making things look pretty. More over it works like a champ if you want to use it with a limited number of levels of depth but as far as I can see with out looking at source for it there is no way for it to automatically go to the n level of depth on its own. So for us data driven guys it wets the appetite but leaves us feeling totally unsatisfied much like running any version of 7 other than Ultimate.

I would like to present a simple solution to give those of you looking for a simple solution to avoid defining a template for each level of depth in you tree. This post is part 1 of a hopeful 3 part look at how to make a slick DynamicTreeView. In part 1 I'll show you how to make the basic tree saving the styling for part 2. In part 3 we will roll the entire thing in to nice reusable UserControl that allows you easily make this fit into your application.

Solution_Files For this demo go ahead an make yourself a new Silverlight Application or Silverlight Class Library in Visual Studio 2008 either will do. I am going to use Silverlight Application so that I can just hit F5 to preview at any time but the Solution that I'll post with this will be a Silverlight Class Library. Now go ahead and make 2 User Controls AutoNode.xaml and DynamicTreeView.xaml. AutoNode is where all the magic happens and DynamicTreeView is the finished product that will work like the current TreeView in the Silverlight Toolkit.
At this point you should have a solution similar to the one on the left.



Lets start with DynamicTreeView.xaml and put an ItemsControl in LayoutRoot like this.

<UserControl
   x:Class="SilverlightApplication1.DynamicTreeView"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Width="200" Height="400">
    <Grid x:Name="LayoutRoot" Background="Black">
        <ItemsControl />
    </Grid>
</UserControl>

Go ahead an build you solution so that everything will be ready to work with Blend when we open it.

For those of you with Expression Blend Lets right click on the DynamicTreeView.xaml in our Solution Explorer and open it with Expression Blend (you can do this with out Expression Blend but for god sakes use Expression Blend cause you don't get extra points for doing it the hard way) on the Objects and Timelines area lets right click on our ItemsControl then go to
Edit Additional Templates -> Edit Generated Items Template (ItemTemplate) -> Create Empty
like shown below.
DynamicTreeView VisualTree 1

DataTemplate RootTreeViewItem
This is creating the template that will house all of the top level tree items for our tree view. You'll be presented with the dialog shown above enter the name you want to call this template I am using RootTreeViewItem. Once you click ok you will be presented with a empty template that has a grid and nothing else. At the far left toolbar select the assets icon and type "auto", you should be able to select the AutoNode UserControl and add it to the grid and clear any attributes for the AutoNode in the XAML.
select autonode
At this point your XAML should now have a pretty simple data template added to it like the following

<UserControl
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:SilverlightApplication1" x:Class="SilverlightApplication1.DynamicTreeView"
   Width="200" Height="400">
    <UserControl.Resources>
        <DataTemplate x:Key="RootTreeViewItem">
            <Grid>
                <local:AutoNode/>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="Black">
        <ItemsControl ItemTemplate="{StaticResource RootTreeViewItem}" />
    </Grid>
</UserControl>

OK next up lets open up AutoNode.xaml and finish the basic function of this tutorial. I am not going to go over the details of the layout as teaching basics of layouts in Silverlight is beyond the scope of this tutorial so lets use this XAML. Interesting note I was seemingly unable to add a instance of AutoNode to a template that lived on AutoNode using drag and drop with Expression Blend (guessing that this is a safe guard against accidental recursion. If anyone can confirm this I would appreciate it.)

<UserControl
   x:Class="SilverlightApplication1.AutoNode"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   mc:Ignorable="d"
   d:DesignWidth="273"
   d:DesignHeight="87"
   VerticalContentAlignment="Top">
    <UserControl.Resources>
        <DataTemplate x:Key="Children">
            <auto:AutoNode VerticalAlignment="Top" />
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="21"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Column="1" />
        <ItemsControl Grid.Column="1" Grid.Row="1" ItemTemplate="{StaticResource Children}" />
    </Grid>
</UserControl>

But the above is somewhat simular to one of the templates used for the TreeViewItem in the Silverlight Toolkit. With just a little bit of data binding this will populate a Tree of nodes that conforms to the same convention for each level with no limit of depth. (short of running out of memory in theory)
I used the following Simple class that would mimic a file system recursive directory listing. If your running a x64 system the paths used should map to real paths on your system. The FileNode class is intended to eventually provide the needed data so that this tree view by the end of part 3 will be able to visually identify if a node is a file or a directory with a different icon.

public class FileNode
{
    public string DisplayValue { get; set; }
    public string Path { get; set; }
    public bool IsFolder { get; set; }
    private ObservableCollection _children = new ObservableCollection();
    public ObservableCollection Children
    {
        get { return _children; }
        set { _children = value; }
    }
    public FileNode() {}
}
public class FileSystemHelper
{
    private ObservableCollection nodes = new ObservableCollection();
    public FileSystemHelper()
        {
            Nodes.Add(new FileNode()
            {
                DisplayValue = "Windows",
                Path = "C:\\Windows",
                IsFolder = true

            });
            Nodes[0].Children.Add(new FileNode()
            {
                DisplayValue = "Microsoft.NET",
                Path = "C:\\Windows\\Microsoft.NET",
                IsFolder = true
            });
            Nodes[0].Children[0].Children.Add(new FileNode()
            {
                DisplayValue = "Framework64",
                Path = "C:\\Windows\\Microsoft.NET\\Framework64",
                IsFolder = true
            });
            Nodes[0].Children[0].Children.Add(new FileNode()
            {
                DisplayValue = "Framework",
                Path = "C:\\Windows\\Microsoft.NET\\Framework",
                IsFolder = true
            });
            Nodes[0].Children[0].Children[0].Children.Add(new FileNode()
            {
                DisplayValue = "v3.5",
                Path = "C:\\Windows\\Microsoft.NET\\Framework64\\v3.5",
                IsFolder = true
            });
            Nodes[0].Children[0].Children[0].Children.Add(new FileNode()
            {
                DisplayValue = "sbscmp10.dll",
                Path = "C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\sbscmp10.dll",
                IsFolder = false
            });
            Nodes[0].Children[0].Children[0].Children.Add(new FileNode()
            {
                DisplayValue = "sbscmp20_mscorwks.dll",
                Path = "C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\sbscmp20_mscorwks.dll",
                IsFolder = false
            });
        }

        public ObservableCollection<FileNode> Nodes
        {
            get { return nodes; }
            set { nodes = value; }
        }
    }
}

Currently we only care about the DisplayValue, Path, and Children properties so lets go ahead and add the data binding to AutoNode.xaml. Change the TextBlock and the ItemsControl to the following

<TextBlock Text="{Binding DisplayValue}" TextWrapping="Wrap" Grid.Column="1" ToolTipService.ToolTip="{Binding Path}"/>
<ItemsControl Grid.Column="1" Grid.Row="1" ItemTemplate="{StaticResource Children}" ItemsSource="{Binding Children}"/>

The Last step that we need to add a data context to the grid on DynamicTreeView.xaml and set an ItemsSource binding for the ItemsControl below is what the final DynamicTreeView.xaml should look like.

<UserControl
   x:Class="SilverlightApplication1.DynamicTreeView"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:SilverlightApplication1"
   Width="300" Height="400">
    <UserControl.Resources>
        <DataTemplate x:Key="RootTreeViewItem">
            <Grid>
                <local:AutoNode/>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="Black">
        <Grid.DataContext>
            <local:FileSystemHelper/>
        </Grid.DataContext>
        <ItemsControl ItemTemplate="{StaticResource RootTreeViewItem}" ItemsSource="{Binding Nodes}" />
    </Grid>
</UserControl>

Lets not forget to add the DynamicTreeView to the MainPage.xaml so it shows up when we hit preview.

<UserControl
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:SilverlightApplication1"
   x:Class="SilverlightApplication1.MainPage"
   Foreground="White">
    <Grid HorizontalAlignment="Left" VerticalAlignment="Top">
        <local:DynamicTreeView />
    </Grid>
</UserControl>

IE Part 1 finished
To the left you can see that we currently have a stunningly bland proof of concept for our recursive TreeView. Its worth noting that there is not one line of programmatic code that is making this happen (other than the code to generate the items to display but with some work you can make the AutoNode use reflection to check to see if its DataContext has any property that implements ICollection/IList/IEnumerable and if so try to map that to the children field.)

Now you must be thinking OK but what can I do with this? Well I was thinking that myself after this was done and so here is an example of what to do with it. With a few changes to the code we had that defined the FileSystemHelper and FileNode classes we can make VisualFamilyTree and FrameworkElementNode classes as below.

    /// <summary>
    /// Modified from FileSystemHelper
    /// </summary>
    public class VisualFamilyTree
    {
        private ObservableCollection<FrameworkElementNode> nodes = new ObservableCollection<FrameworkElementNode>();
        public VisualFamilyTree() {}
        /// <summary>
        /// This method will be called after the rootElement has fully loaded and is ready to be transversed
        /// </summary>
        /// <param name="rootElement"></param>
        public void Populate(FrameworkElement rootElement)
        {
            Nodes.Clear(); // this is done to make the tree only ever have one node
            Nodes.Add(new FrameworkElementNode(rootElement));
        }
        public ObservableCollection<FrameworkElementNode> Nodes
        {
            get { return nodes; }
        }
    }
    /// <summary>
    /// Modified from FileNode
    /// </summary>
    public class FrameworkElementNode
    {
        public string DisplayValue { get; set; }
        public string Path { get; set; }

        private ObservableCollection<FrameworkElementNode> _children = new ObservableCollection<FrameworkElementNode>();
        public ObservableCollection<FrameworkElementNode> Children
        {
            get { return _children; }
            set { _children = value; }
        }

        public FrameworkElementNode() { }
        /// <summary>
        /// constructor that auto builds off of a FrameworkElement
        /// </summary>
        public FrameworkElementNode(FrameworkElement fe)
        {
            // how many child nodes does this element have that are direct children of this FrameworkElement
            int childNodes = VisualTreeHelper.GetChildrenCount(fe);
            if(childNodes> 0)
                for (int i = 0; i < childNodes; i++)
                {
                    // recursively call this for each FrameworkElement that is a child element of the FrameworkElement fe
                    Children.Add(new FrameworkElementNode(VisualTreeHelper.GetChild(fe, i) as FrameworkElement));
                }
            // using path for name so we didn't have to make any changes to the AutoNode.xaml
            Path = fe.Name;
            // the node "header" will be x:Name ( type of this FrameworkElement )
            DisplayValue = Path+ "( " + fe.GetType().Name + " )";
        }
    }

The goal of this is to make our recursive TreeView build in real time from the live code that is running in browser to give us the same kind visual tree that we have in Expression Blend at design time. Looking below you can see a quick collection of controls that I threw on a page. A quick search didn't bring up anyone doing anything like this in real time running in Silverlight. The closest that I could find to doing something like this was Silverlight Spy. Granted currently it only looks for simple parent child relationships and wont peek into templates of any kind (though that should be pretty straight forward to implement) on the other hand the code to make the live tree only took like 10 min so its a fair trade I guess.

random items

Now here is a screen shot of it running live in Silverlight and note that the tree is the same.
random items in browser

Download the full solution for Here.

5Oct/090

Silverlight ComboBox Strong Typed Selected Object

For those of you that use Silverlight and the built in ComboBox here is something that works a little cleaner than the default casting of the SelectedItem on a ComboBox. I am a big fan of extension methods and I plan to post a lot about them in the future so I decided to start with something small.

public static T GetSelectedObject(this ComboBox cb) where T:class
{
    return cb.SelectedItem as T;
}