Daniel Vaughan

free range code

ALT.NET Swiss group

clock November 26, 2009 21:47 by author Daniel Vaughan

Last night I had the pleasure of speaking at the ALT.NET Swiss group in Geneva. I spoke on composite applications, Prism, Calcium, and T4 Generated Metadata. Valeriu Caraulean spoke on MVVM, BLToolkit and Caliburn. Thanks to Frédéric SCHÄFER for organising the event, and to Atif Aziz and Cargill International SA for the location.

Catch us at the next meeting!



Using T4 to Generate Pack URIs for XAML Files

clock November 25, 2009 15:25 by author Daniel Vaughan

Yesterday my fellow WPF Disciple Paul Stovell got me thinking about resolving XAML file paths.

As Paul points out, there doesn't appear to be an easy way to locate the URI for a XAML file. Internally, the generated .g.cs makes use of the path, as shown in the following excerpt:

public void InitializeComponent() 
{ 
  if (_contentLoaded) 
  { 
    return; 
  } 
  _contentLoaded = true; 
  System.Uri resourceLocater = new System.Uri("/PageCollection;component/pages/page1.xaml", System.UriKind.Relative); 
  #line 1 "..\..\..\Pages\Page1.xaml" 
  System.Windows.Application.LoadComponent(this, resourceLocater); 
  #line default 
  #line hidden 
}

But, how can we get our hands on it? What I’ve done is to incorporate the generation of XAML resource pack URIs into the T4 template I did a little while ago.

To demonstrate I have created a dummy UserControl in a subfolder in the sample application.

Image Figure: Dummy UserControl has a pack URI generated

 

The resulting output from the T4 template now enables us to determine the path to the XAML file in a safe way. The following excerpt shows the generated Pack URI:

namespace CSharpDesktopClrDemo.XamlMetadata.Folder1.Folder2.Metadata
{
    /// <summary>Metadata for XAML UserControl1.xaml</summary>
    public static class UserControl1XamlMetadata
    {
            /// <summary>Resource pack URI for XAML file.</summary>
            public const string XamlPackUri 
= @"/DanielVaughan.MetaGen.Demo;component/Folder1/Folder2/UserControl1.xaml"; } }

Now we have this, we can write:

Uri uri = new Uri(CSharpDesktopClrDemo.XamlMetadata.Folder1.Folder2.Metadata
                 .UserControl1XamlMetadata.XamlPackUri, UriKind.Relative);
var control = System.Windows.Application.LoadComponent(uri) 
       as DanielVaughan.MetaGen.Demo.Folder1.Folder2.UserControl1;

No more magic string pack URIs!

Download the template and sample application: MetaGen_01_04.zip (393.35 kb)

 



Article Published: Calcium Part 3

clock November 21, 2009 17:43 by author Daniel Vaughan

I’ve just published the third part of the Calcium series of articles. Calcium is now provided as an SDK, and comes with 12 VS Project templates (3 for 2008, 2010, C#, and VB.NET)

This article looks at the changes that have taken place in the Calcium project since the first release, a number of months ago. It features an introduction to the File Service, which abstracts the displaying of dialogs and handling common IO exceptions, in a platform agnostic manner; allowing the user to select other alternative locations for files, while providing feedback to the user. It also features an overview of the View Service, allowing content to be shown or hidden using a view type association mechanism.


View Article



Speaking at the Swiss ALT.NET Group on 25 November

clock November 19, 2009 23:47 by author Daniel Vaughan

I will be speaking at the next ALT.NET Swiss user group on the 25th of November. I will be showing of latest version of the Calcium SDK, and looking at some other MVVM frameworks created by my fellow Disciples.

Special thanks go out to Frédéric Schäfer, and Atif Aziz of Cargill International SA, for making the meeting a reality. Nice one guys.

The details are:
25 November at 18:30
Cargill Conference Center
Cargill International SA
14 chemin de Normandie
1206 Geneva

More details



PDC09 and Silverlight 4 Beta Release

clock November 19, 2009 00:21 by author Daniel Vaughan

Wow, what a day. The PDC09 has just exploded a host of new tech that is making my head spin! Not least of which is the Silverlight 4 beta released today.

You can watch this video on Channel 9, with John Papa and Adam Kinney.

There’s also a list of features here.

My top 3 favourite new Silverlight features:

  1. Desktop CLR support for Silverlight (This is huge)
  2. ICommand support (I need this)
  3. 60+ Forms controls, Like it!

My friend Laurent Bugnion will be talking at the notatpdc tomorrow. Laurent is always somebody with his finger placed firmly on the .NET developer community pulse. Be sure to tune in tomorrow at 11:00 AM CST (6pm Geneva Switzerland time), I know I will be.



Compile-Time Validation of Composite Object Data Binding Expressions

clock November 7, 2009 18:06 by author Daniel Vaughan

Introduction

Prompted by a recent comment on the T4 Metadata Generation template article, which I released some weeks ago, I have implemented a new mechanism for concatenating property paths. This allows compile time validation of properties that exist on composite or nested members.

Background

Previously I have demonstrated how generated metadata can be used to provide compile-time validation of binding expressions. Rather than using string literals in binding expressions, one is able to use the x:Static markup extension and a T4 generated constant to indicate the binding path; as shown in the following excerpt.

<Label Content="{Binding Path={x:Static Metadata:PersonMetadata.NamePath}}"/>

Overcoming Limitations

This approach works fine when targeting a property from a single instance in a DataContext, but what happens when we wish to target a nested instance’s property? For example, and as demonstrated in the downloadable sample from the article mentioned above, if we have a ListBox populated with Person instances, and we wish to bind a label to the listbox’s SelectedItem.Address.StreetAddress property, we can do so using the following XAML:

<ListBox x:Name="listBox" Background="Black">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <Label Content="{Binding Path={x:Static Metadata:PersonMetadata.NamePath}}"/>
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
<Label Content="{Binding ElementName=listBox, 
    Path={Demo:JoinPath 
                SelectedItem, 
                {x:Static Metadata:PersonMetadata.Address}, 
                {x:Static Metadata:AddressMetadata.StreetLine}}}"/>

Here we see a custom MarkupExtension called JoinPathExtension is used to enable the concatenation of path strings to create a PropertyPath that is used to target the nested Address instance. In this case, the string values of ‘SelectedItem’, ‘Address’, and ‘StreetLine’ combine to produce a PropertyPath ‘SelectedItem.Address.StreetLine’.

You will notice, when you open the CS Window1.xaml file in the sample download, that errors are reported for the Path expressions. These don’t prevent the designer from loading in either Visual Studio or Blend. They are, however, annoying.

 

Diagram: Visual Studio Xaml designer errors.

Attempting to resolve this issue I switched to using named arguments. No luck there either I’m afraid, with the x:Static expression resulting in a compile time error:

(Unknown property 'Converter' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension. Line x position Y)

My fellow disciple Philipp Sumi has a great post outlining the VS designer bug. 

I have experimented with a number of approaches, including (as Philipp suggests) explicit property syntax, and have settled on the one shown above.

The main parts of the JoinPathExtension are shown:

CS:

/// <summary>
/// Allows a set of property path strings to be concatenates 
/// into a <see cref="PropertyPath"/> instance.
/// </summary>
[MarkupExtensionReturnType(typeof(PropertyPath))]
public class JoinPathExtension : MarkupExtension
{
  readonly List<string> members = new List<string>(); 
 
  public JoinPathExtension()
  {
    /* Intentionally left blank. */
  }
 
  public JoinPathExtension(string member0)
  {
    if (member0 == null)
    {
      throw new ArgumentNullException("member0");
    }
    members.Add(member0);
  }
 
  public JoinPathExtension(string member0, string member1)
    : this(member0)
  {
    if (member1 == null)
    {
      throw new ArgumentNullException("member1");
    }
    members.Add(member1);
  }
 
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    var path = string.Join(".", members.ToArray());
    var result = new PropertyPath(path);
    return result;
  }
 
  void SetMember(int index, string value)
  {
    if (value == null)
    {
      throw new ArgumentNullException("value");
    }
    if (members.Count < index + 1)
    {
      members.Add(value);
      return;
    }
    members[index] = value;
  }
 
  #region Named member properties
  [ConstructorArgument("member0")]
  public string Member0
  {
    get
    {
      return members[0];
    }
    set
    {
      SetMember(0, value);
    }
  }
 
  public string Member1
  {
    get
    {
      return members[1];
    }
    set
    {
      SetMember(1, value);
    }
  }
 
}

VB.NET:

Imports System.Windows.Markup

Public Class JoinPathExtension
    Inherits MarkupExtension
    ' Methods
    Public Sub New()
        Me.members = New List(Of String)
    End Sub

    Public Sub New(ByVal memberList As String())
        Me.members = New List(Of String)
        If (memberList Is Nothing) Then
            Throw New ArgumentNullException("memberList")
        End If
        Me.members.AddRange(memberList)
    End Sub

    Public Sub New(ByVal member1 As String)
        Me.members = New List(Of String)
        If (member1 Is Nothing) Then
            Throw New ArgumentNullException("member1")
        End If
        Me.members.Add(member1)
    End Sub

    Public Sub New(ByVal member1 As String, ByVal member2 As String)
        Me.New(member1)
        If (member2 Is Nothing) Then
            Throw New ArgumentNullException("member2")
        End If
        Me.members.Add(member2)
    End Sub

    Public Overrides Function ProvideValue(ByVal serviceProvider As IServiceProvider) As Object
        Return New PropertyPath(String.Join(".", Me.members.ToArray), New Object(0 - 1) {})
    End Function


    ' Properties
    <ConstructorArgument("member1")> _
    Public Property Member() As String
        Get
            Return Me.members.Item(0)
        End Get
        Set(ByVal value As String)
            If (value Is Nothing) Then
                Throw New ArgumentNullException("value")
            End If
            If (Me.members.Count < 1) Then
                Me.members.Add(value)
            Else
                Me.members.Item(0) = value
            End If
        End Set
    End Property

    <ConstructorArgument("member2")> _
    Public Property Member2() As String
        Get
            Return Me.members.Item(1)
        End Get
        Set(ByVal value As String)
            If (value Is Nothing) Then
                Throw New ArgumentNullException("value")
            End If
            If (Me.members.Count < 2) Then
                Me.members.Add(value)
            Else
                Me.members.Item(1) = value
            End If
        End Set
    End Property


    ' Fields
    Private ReadOnly members As List(Of String)
End Class

Conclusion

We have seen how by using a custom MarkupExtension we are able to concatenate generated property name constants to produce PropertyPaths, which can be consumed by Path binding expressions. Having the capability to join path expression adds a lot to the flexibility of the generated metadata approach. We are now able to fully express property paths for nested objects in binding expressions, without resorting to string literals; increasing dramatically the flexibility of this approach.

Download the sample code from here.

 

 



Calcium SDK Website Launch

clock November 5, 2009 12:03 by author Daniel Vaughan

I’ve just launched a new website for the Calcium project. It includes a video on how to use the new version of the Calcium SDK, which I’ve also just released. I’m pretty excited about this one. The new version includes an installer that makes working with Calcium much easier, and a bunch of API refinements.

 




Windows Phone Experts Windows Phone Experts
LinkedIn Group

 

About the author

Daniel VaughanDaniel Vaughan is a Microsoft MVP for Client Application Development, with a decade of commercial experience across a wide range of industries including finance, e-commerce, and multimedia. While originally from Australia and the UK, Daniel is currently based in Geneva Switzerland; consulting on Windows Phone 7, WPF, Silverlight, WCF, and WF. Daniel is a Silverlight and WPF Insider, a member of the WPF Disciples, and a CodeProject MVP. Daniel is currently writing Windows Phone 7.5 Unleashed, which is due out in early 2011. Daniel is also the creator of a number of open-source projects, including Calcium, and Clog. E-mail me Send mail

 

Microsoft MVP logo Disciple
CodeProject MVP
WPF and Silverlight Insiders

 

 

Books

Order Windows Phone 7 Unleashed

RecentComments

Comment RSS

Sign in