Tag: .NET

  • Date issues in Silverlight

    Seeing some strange date behaviours in SL UI components. My local culture is UK but we keep seeing US dates popping up “here and there”.

    Have tried setting the Language= “en-GB” in the upper most control, also setting the thread culture is not effecting across the app.

    Going to have to get help on this one…

  • Restyling Transitions in the Silverlight Toolkit TransitioningContentControl

    (This post extends my example for using cross project merged dictionaries in Silverlight)

    I’m a developer, not a designer and as such using Expression Blend doesn’t feel natural and makes me feel dirty… However I had to bite the bullet to ease the restyling of the transition animation in the Toolkit TransitioningContentControl.

    NOTE: At time of writing this control is in the Experimental Quality Band – the way I have built this might not work in the future!!

    To edit the transition in blend I added a TCC to my page, right clicked and chose “Edit Template Edit a Copy… Define in Application

    You can then start editing the VisualStates. There is tons of information on how to do this, so I won’t repeat that here, but here are the basics:

    Select States tab, Choose a transition to edit (or add a new one) expand the objects and make changes to the states along the time line.

    After making changes to your template open it and examine the changes. Most stuff is pretty self explanatory. Once this is done I can close blend and copy the XAML in to Visual Studio – now I feel safe and clean!!

    So, I wanted to add a flip transition, that makes the page look like it is doing a 360 flip around a vertical axis. First thing to do is edit the content template to include project planes, as these are hooked from my new animation (lines 17-19 and 37-39 below). You won’t need to do this is you are changing basic animation properties (offset, opacity, scale etc):


    <ContentPresenter x:Name="PreviousContentPresentationSite"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Content="{x:Null}"
    ContentTemplate="{TemplateBinding ContentTemplate}">















    <ContentPresenter x:Name="CurrentContentPresentationSite"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Content="{x:Null}"
    ContentTemplate="{TemplateBinding ContentTemplate}">














    Then add my flip animation (lines 53-74 below):

    <Style x:Key="TransitioningContentControlStyle1"
    TargetType="layoutToolkit:TransitioningContentControl">
    <Setter Property="IsTabStop"
    Value="True" />
    <Setter Property="HorizontalContentAlignment"
    Value="Left" />
    <Setter Property="VerticalContentAlignment"
    Value="Top" />
    <Setter Property="Transition"
    Value="DefaultTransition" />



    <Border Background="{TemplateBinding Background}"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}"
    CornerRadius="2">




    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="0" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="1" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="1" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="0" />





    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Visibility)">


    Collapsed







    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)">
    <EasingDoubleKeyFrame KeyTime="00:00:00"
    Value="0" />
    <EasingDoubleKeyFrame KeyTime="00:00:00.3000000"
    Value="90" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)">
    <EasingDoubleKeyFrame KeyTime="00:00:00"
    Value="-90" />
    <EasingDoubleKeyFrame KeyTime="00:00:00.3000000"
    Value="-90" />
    <EasingDoubleKeyFrame KeyTime="00:00:00.6000000"
    Value="0" />






    <ContentPresenter x:Name="PreviousContentPresentationSite"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Content="{x:Null}"
    ContentTemplate="{TemplateBinding ContentTemplate}">















    <ContentPresenter x:Name="CurrentContentPresentationSite"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Content="{x:Null}"
    ContentTemplate="{TemplateBinding ContentTemplate}">



















    NOTE: I have removed the DefaultTransition, UpTransition and DownTransition VisualStates from this code as I am not using them. Normal MUST remain. If you want these transition states back they are copied below for your convenience.

    Finally I copied this style to a separate file so it can be referenced as a MergedDictionary across a multi project solution (as described here).

    When doing this, remember to Add a reference to System.Windows.Controls.Toolkit and System.Windows.Controls.Layout.Toolkit from the resources project, and in the resource xaml file:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit">

    DefaultTransition, UpTransition and DownTransition Visual States



    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="0" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="1" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="1" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="0" />





    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="0" />
    <EasingDoubleKeyFrame KeyTime="00:00:00.7330000"
    Value="0" />
    <EasingDoubleKeyFrame KeyTime="00:00:01.1000000"
    Value="1" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="1" />
    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
    Value="1" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.9000000"
    Value="0" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
    <EasingDoubleKeyFrame KeyTime="00:00:00"
    Value="0">




    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
    Value="0">




    <EasingDoubleKeyFrame KeyTime="00:00:00.9000000"
    Value="0">





    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
    <EasingDoubleKeyFrame KeyTime="00:00:00.7330000"
    Value="0" />
    <EasingDoubleKeyFrame KeyTime="00:00:01.1000000"
    Value="1" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
    <EasingDoubleKeyFrame KeyTime="00:00:00.7330000"
    Value="0" />
    <EasingDoubleKeyFrame KeyTime="00:00:01.1000000"
    Value="1" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
    <EasingDoubleKeyFrame KeyTime="00:00:00"
    Value="1">




    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
    Value="0.75">




    <EasingDoubleKeyFrame KeyTime="00:00:00.9000000"
    Value="1">





    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
    <EasingDoubleKeyFrame KeyTime="00:00:00"
    Value="1">




    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
    Value="0.75">




    <EasingDoubleKeyFrame KeyTime="00:00:00.9000000"
    Value="1">





    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
    Value="0">




    <EasingDoubleKeyFrame KeyTime="00:00:00.9000000"
    Value="-500">





    <PointAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)">
    <EasingPointKeyFrame KeyTime="00:00:00"
    Value="0.5,0.5" />
    <EasingPointKeyFrame KeyTime="00:00:00.5000000"
    Value="0.5,0.5" />

    <PointAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)">
    <EasingPointKeyFrame KeyTime="00:00:00"
    Value="0.5,0.5" />
    <EasingPointKeyFrame KeyTime="00:00:00.7330000"
    Value="0.5,0.5" />
    <EasingPointKeyFrame KeyTime="00:00:01.1000000"
    Value="0.5,0.5" />





    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="0" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="1" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="CurrentContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="-40" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="0" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.Opacity)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="1" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="0" />

    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="PreviousContentPresentationSite"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
    <SplineDoubleKeyFrame KeyTime="00:00:00"
    Value="0" />
    <SplineDoubleKeyFrame KeyTime="00:00:00.300"
    Value="40" />


    Note: UpTransition has been altered to do a funky “drop-back-swing-left-and-fade-in” animation

    Example

    The obligatory example is here…

  • Cross Project MergedDictionaries in Silverlight

    Todd Miranda has posted a video on the use of merged dictionaries on the Learning portal of Silverlight.net (find it here). This video explains the concepts of MergedDictionaries in a very long winded way. IMHO people investigating MergedDictionaries will already know how to layout a grid, and play some simple controls, so the first 8m of the tutorial is pretty boring.

    The description of the use of MergedDictionaries is pretty good, along with a couple of common pitfalls, but this does not explain one core feature well enough: Cross Project

    Anyone writing a Silverlight LOB application is almost certainly going to have multiple projects, and the use of MergedDictionaries corss project is going to be a huge advantage.

    Luckily this isn’t much more difficult than Todd has shown. Imagine the following scenario; we have a bunch of silverlight pages that need to share styles, but are spread across a few different projects. We want to keep the styles (as resources) in one location and reference these.

    So simply create a Resources project, and add your resources files as described by Todd (Add | New Item… | XML file etc) (you can also add these to any sensible location in your existing solution – say a UserControls project)

    Then when referencing the MergedDictionary from the UserControl where the style will be applied, use the Assembly name of the resources location, rather than the assembly name of the UserControl location.

    So the Source value will be formatted as Source=”/[AssemblyName];component/[Path and filename]

    Don’t forget to add a reference to the Resources project from the Target Project.

    Further details and and example of this in action with a re-styled TransitioningContentControl can be found here: http://thoughtjelly.blogspot.com/2009/10/restyling-transitions-in-silverlight.html.

  • Walking the XAML VisualTree to find a parent of type

    To find a parent item of type T, you can use the following helper class:

    public static class DependencyObjectHelper
    {
    public static DependencyObject FindParent(this DependencyObject obj, Predicate where) {
    var parent = VisualTreeHelper.GetParent(obj);
    
    if (parent == null || where(parent)) {
    return parent;
    } else {
    return parent.FindParent(where);
    }
    }
    
    public static T FindParentOfType(this DependencyObject obj) where T : DependencyObject {
    return (T)FindParent(obj, x => x is T);
    }
    }

    This can then be utilised as follows:

    Grid item = ((DependencyObject)childObject).FindParentOfType();

    This was particularly useful when wanting to locate an invalid control from a ValidationSummary in silverlight, that was nested in an accordian panel:

    BIG shout out goes to Jedi Master Twist for the lead on this 🙂

  • Silverlight 2: Nested user controls, data-binding and property change notification.

    The Problem:

    The parent form is in charge. This form has a view-model which has all the relevant information loaded, know which other views have been implemented, what data those view need and how and when to display and update those views. This is the master page.

    Within that page you can add user controls. These controls are discreet and reusable. They know about themselves, and any controls nested within. The values within these controls are bound to properties in a backing store (the view-model). This control does not know about it’s parent, it will just generate a notification event when the property changes. The parent must be enabled to process this event.

    A Solution:

    Start with your child control. These should function irrespective of where they are called from. For example a reusable data-grid control. In our situation, this control not only displays a collection of objects, it also dynamically sets the displayed fields in the data-grid, based on a collection of field definitions. This control has a view-model (to which the UI controls are data-bound). It also has dependency properties (which can be set by a parent class) and notification properties (which can notify the parent class of changed properties).So the ViewModel would be coded as follows:

      1:     /// 
      2:     /// Backing class for the data used within the UserControl_View
      3:     /// 
      4:     public class UserControl_ViewModel : ViewModelBase
      5:     {
      6: 
      7:         private ObservableCollection<object> _objectList;
      8:         public ObservableCollection<object> ObjectList
      9:         {
     10:             get { return _objectList;}
     11:             set
     12:             {
     13:                 _objectList = value;
     14:                 _OnPropertyChanged("ObjectList");
     15:             }
     16:         }
     17: 
     18:         private object _selectedObject;
     19:         public object SelectedObject
     20:         {
     21:             get { return _selectedObject;}
     22:             set
     23:             {
     24:                 _selectedObject;= value;
     25:                 _OnPropertyChanged("SelectedObject");
     26:             }
     27:         }
     28: 
     29:     }

    (where the ViewModelBase class takes care of the notification property interface).

    Within the UserControl_View we implement the INotifyPropertyChanged interface again, add an instance of the ViewModel class, and bind to it (We also set an event handler into the View to process the properties being changed in the ViewModel and pass these back into the respective UI dependency properties):

      1:     public partial class UserControl_View : UserControl, INotifyPropertyChanged
      2:     {
      3:         public UserControl_ViewModel ViewModel = new UserControl_ViewModel();
      4: 
      5:         public UserControl_View()
      6:         {
      7:             InitializeComponent();
      8:             this.DataContext = ViewModel;
      9: 
     10:             ViewModel.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
     11:         }
     12: 
     13: 
     14:         public event PropertyChangedEventHandler PropertyChanged;
     15:         protected virtual void OnPropertyChanged(string propertyName)
     16:         {
     17:             PropertyChangedEventHandler pceh = PropertyChanged;
     18:             if (pceh != null)
     19:             {
     20:                 pceh(this, new PropertyChangedEventArgs(propertyName));
     21:             }
     22:         }
     23:     
     24:         ...
     25:     }

    The event handler for the ViewModel property changed event is as follows:

      1:         /// Watch for the property changed events in teh view model, and get the values
      2:         void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
      3:         {
      4:             if (e!=null)
      5:             {
      6:                 if (e.PropertyName == "SelectedObject")
      7:                 {
      8:                     SelectedObject = ((UserControl_ViewModel)sender).SelectedObject ;
      9:                     OnPropertyChanged("SelectedObject");
     10:                 }
     11:             }
     12:         }

    This will respond to property notification from the ViewModel, check the name of the property, set the respective dependency property on the VIew, and then raise a property notification event for the View (back to the parent).

    We then add dependency properties to the View to handle the objects being passed into the View, for example:

      1:         public ObservableCollection<object> ObjectCollection
      2:         {
      3:             get { return (ObservableCollection<object>)GetValue(ObjectCollectionProperty); }
      4:             set { SetValue(ObjectCollectionProperty, value); }
      5:         }
      6: 
      7:         /// 
      8:         /// Registration of a property container to hold the collection of objects.
      9:         /// 
     10:         /// This HAS to be a dependency property for parent controls to access this.
     11:         public static readonly DependencyProperty ObjectCollectionProperty =
     12:             DependencyProperty.Register("ObjectCollection",
     13:             typeof(ObservableCollection<object>),
     14:             typeof(UserControl_View),
     15:             new PropertyMetadata(new PropertyChangedCallback(ObjectCollectionChanged)));
     16: 
     17:         /// this method is called from the static DependencyProperty "ObjectCollectionProperty"
     18:         /// by the 4th argument as the PropertyMetadata callback value.
     19:         /// This sets the items in the datagrid
     20:         public static void ObjectCollectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
     21:         {
     22:             CaseDataGrid instance = d as CaseDataGrid;
     23:             if (instance != null)
     24:             {
     25:                 if (args.NewValue != null)
     26:                 {
     27:                     instance.ViewModel.ObjectCollection = args.NewValue as ObservableCollection<object> ;
     28:                 }
     29:             }
     30:         }

    Once all the DP’s for the View have been added you are complete with the control. Next you will look at the middle layer.

    Conceptually the middle layer works in exactly the same way as the child layer.

    • A ViewModel is used to maintain and bind data.
    • Notification properties are used from the ViewModel to the View
    • Notification properties are used from the View to any parents.
    • Dependency properties are registered in the view, to accept incoming data from a parent .
    • PropertyChangedCallback methods are used to set the properties on the child controls:

        1:         public static void ObjectCollectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        2:         {
        3:             ChildControl instance = (ChildControl)d;
        4:             if (instance != null)
        5:             {
        6:                 if (args.NewValue != null)
        7:                 {
        8:                     ObservableCollection<object> NewCollection = args.NewValue as ObservableCollection<object>;
        9:                     instance.UserControl_View.ObjectCollection = NewCollection;
       10:                 }
       11:             }
       12:         }

    The Master Control

    Once again the conceptual model is very  similar to the middle layer:

    • A view model is used to manage and bind data.
    • Notification properties are used to pass data from the ViewModel to the View.
    • The Master_View XAML binds the ViewModel properties to the Child Dependency Properties.

    This should work a treat 🙂

  • .NET Debugging and Stack Trace

    When debugging enable the stack trace view to see where code has been triggered from. This is particularly useful for figuring out where events have been triggered from (delegation of event handlers from multiple places etc):

  • Design patterns

    An excellent reference for gang of four design patterns: http://www.dofactory.com/Patterns/Patterns.aspx

  • Silverlight MVVM and Testing

    During my investigations into this crazy land I have found a few good articles (and many not so good…):

    http://www.cauldwell.net/patrick/blog/MVVMAndTestingSilverlight.aspx

    http://silverlight.net/blogs/justinangel/archive/2009/02/25/silverlight-unit-testing-rhinomocks-unity-and-resharper.aspx

    Both use MVVM and both use RhinoMocks, but in subtly different ways.

  • HTML Table to ASP.NET Table

    To convert an HTML table (from a string) to an ASP.NET table:

    Start with an HTML table:

    <table style="width: 100%;">
    <tr>
    <td colspan="2">
    <fieldset title="Policy Information">
    <legend><b>Policy Information</b></legend>
    <table style="width: 100%;">
    <tr>
    <td width="140">Policy Number:</td>
    <td width="150">$$Policy Number$$</td>
    </tr>
    </table>
    </fieldset>
    </td>
    </tr>
    </table>
    

    Create a Helper class:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Xml;
    using System.Web.UI.WebControls;
    using System.Web.UI;
    using System.Drawing;&amp;lt;/pre&amp;gt;
    namespace Whatever
     {
     public static class TableHelper
     {
     public static Table m_table = new Table();
    
    public static Table CreateASPTableFromXML(XmlNode node)
     {
     Table table;
     /// fetch the root table node, this will iteratively fetch the rest.
     table = GetTableFromNode(node);
    
    return table;
     }
    
    static Table GetTableFromNode(XmlNode node)
     {
     Table table = new Table();
     table.BorderStyle = BorderStyle.Solid;
     table.BorderColor = Color.Black;
     table.BorderWidth = Unit.Pixel(1);
    
    /// create the table
     if (node.Name.ToLower() != "table")
     {
     throw new Exception(string.Format("'table' element expected, {0} found.", node.Name));
     }
    
    /// apply the attributes
     ApplyAttributesToControl
    
    (node.Attributes, ref table);// From this table element find all the child rows
     foreach (XmlNode rowNode in node.ChildNodes)
     {
     table.Rows.Add(GetRowFromNode(rowNode));
     }
    
    //TableRow row = new TableRow();
     //TableCell cell = new TableCell() { Text = "here" };
     //row.Cells.Add(cell);
    
    //table.Rows.Add(row);
    
    return table;
     }
    
    static TableRow GetRowFromNode(XmlNode node)
     {
     /// create the tableRow
     TableRow tableRow = new TableRow();
    
    if (node.Name.ToLower() != "tr")
     {
     throw new Exception(string.Format("'tr' element expected, {0} found.", node.Name));
     }
    
    /// apply the attributes
     ApplyAttributesToControl(node.Attributes, ref tableRow);
    
    // From this table row element find all the child cells
     foreach (XmlNode cellNode in node.ChildNodes)
     {
     tableRow.Cells.Add(GetCellFromNode(cellNode));
     }
    
    return tableRow;
    
    }
    
    /// Process each cell and look for content.
     static TableCell GetCellFromNode(XmlNode node)
     {
     /// create the tableRow
     TableCell tableCell = new TableCell();
    
    if (node.Name.ToLower() != "td")
     {
     throw new Exception(string.Format("'td' element expected, {0} found.", node.Name));
     }
    
    /// apply the attributes
     ApplyAttributesToControl(node.Attributes, ref tableCell);
    
    /// From this table row element find all the child objects
     /// these might be tables, text or html objects
     if (node.HasChildNodes)
     {
    
    foreach (XmlNode childNode in node.ChildNodes)
     {
     /// this might be an HTML object or another table... or both... (gulp)
     if (childNode.NodeType == XmlNodeType.Element)
     {
     if (childNode.Name.ToLower() == "table")
     {
     tableCell.Controls.Add(GetTableFromNode(childNode));
     }
    
    if (childNode.Name.ToLower() == "fieldset")
     {
     tableCell.Controls.Add(GetPanelFromNode(childNode));
     }
     }
     else if (childNode.NodeType == XmlNodeType.Text)
     {
     tableCell.Text = childNode.InnerText;
     }
     }
     }
    
    return tableCell;
    
    }
    
    /// Process each cell and look for content.
     static Panel GetPanelFromNode(XmlNode node)
     {
     /// create the tableRow
     Panel panel = new Panel();
    
    if (node.Name.ToLower() != "fieldset")
     {
     throw new Exception(string.Format("'fieldset' element expected, {0} found.", node.Name));
     }
    
    /// apply the attributes
     ApplyAttributesToControl(node.Attributes, ref panel);
    
    /// From this panel element find all the child objects
     /// one of which will be a legend tag
     /// then it might be HTML elements, tables or text
     if (node.HasChildNodes)
     {
     /// the legend node will be applied as a panel GroupingText property
    
    foreach (XmlNode childNode in node.ChildNodes)
     {
     /// this might be an HTML object or another table... or both... (gulp)
     if (childNode.Name.ToLower() == "legend")
     {
     panel.GroupingText = childNode.InnerText;
     }
    
    if (childNode.Name.ToLower() == "table")
     {
     panel.Controls.Add(GetTableFromNode(childNode));
     }
     }
     }
     else if (node.InnerText != string.Empty)
     {
     panel.Controls.Add(new Literal() { Text = node.InnerXml});
     }
    
    return panel;
    
    }
    
    ///
    
     /// Add attributes to any web control
     ///
    
    /// Reference to the control to which the attributes are being added
     /// The attributes being added
     static void ApplyAttributesToControl( XmlAttributeCollection attribs, ref T ctrl)
     where T : WebControl
     {
     foreach (XmlAttribute attrib in attribs)
     {
     ctrl.Attributes.Add(attrib.Name, attrib.Value);
     }
     }
    
    }
     }
    
    

    Open the HTML file, and pass the root node to the helper class:

    Table table;
    
    /// check if a template exists for this request form...
     /// TODO: Update this to use the request form name, not the ID.
     string TemplatePath = Server.MapPath(string.Format("~/Private/RequestFormTemplates/{0}.xml", _selectedRequestId));
     if (File.Exists(TemplatePath))
     {
     System.IO.StreamReader myFile = new System.IO.StreamReader(TemplatePath);
     string myString = myFile.ReadToEnd();
     myFile.Close();
     myFile.Dispose();
    
    FileStream fs = new FileStream(TemplatePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
     XmlDocument xmldoc = new XmlDocument();
     xmldoc.Load(fs);
    
    table = TableHelper.CreateASPTableFromXML(xmldoc.DocumentElement);
    
    }
    

    The helper class needs to be fleshed out some more, to provide support for other elements and valid HTML, but it’s almost there.

    If there is an easier way, let me know!

  • Asynchronous Lambda Method calls

    You won’t get any benefit using this code, but it makes for more manageable source. So from Pete Browns blog:

    All network calls in Silverlight are asynchronous. The proliferation of event handling functions this can cause just makes for really cluttered code. Using lambda expressions seems to make my code a bit cleaner. (You can also use regular anonymous delegates, but the lambdas involve less typing)

    public void LoadPolicyDetail()
    {
    IvcDataServiceClient client = new IvcDataServiceClient();

    client.GetPolicyDetailCompleted += (s, e) =>
    {
    if (e.Result != null)
    {
    _policyDetail = e.Result;

    if (PolicyDetailLoaded != null)
    PolicyDetailLoaded(this, new EventArgs());
    }
    else
    {
    if (PolicyDetailLoadError != null)
    PolicyDetailLoadError(this, new EventArgs());
    }
    };

    client.GetPolicyDetailAsync();
    }

    The event handler is right in-line with the loading function. The event args remain strongly typed, so you have access to everything you normally would with an additional function.