Welcome to WindowsClient.net | Sign in | Join

Rob Relyea - XAMLified

WPF, Silverlight and XAML

Syndication

Sponsors





  • advertise here
Referencing a Named Object in XAML2009

HTML provides a simple way to do references from one property to another object easily.

<LABEL FOR="moreinfo">
  send more information 
  <INPUT NAME="moreinfo" TYPE=CHECKBOX ID="moreinfo">
</LABEL>
From HTMLCodeTutorial.com

We wanted XAML Vocabularies to have the same simplicity (and some more capabilities), so that is why we have invested in Name References in XAML2009 and System.XAML.

Name references should work as backwards or forwards references.

Type Authors – Enable Reference by Name for appropriate Properties

Label.Target is a UIElement, however we’d like to enable a simple Name reference to other objects declared in XAML.

<Label Target="firstName" >_First name:</Label>
<TextBox Name="firstName" />

In order to enable users to do this, type authors should use System.Xaml’s NameReferenceConverter on your property.

[TypeConverter(typeof(NameReferenceConverter))]
public UIElement Target
{ … }

Luke put this example of what he’d like to do in a comment on my blog:

<Table Name="Customer"/>
<Table Name="Order"/>
<Relationship From="Customer" To="Order" Cardinality="OneToMany"/>

See “Code Sample using NameReferenceConverter” at the bottom of this post that implements Table, Relationship and demos them.

XAML Users – Use a reference to another object anywhere

XAML2009 introduces the a new built-in markup extension called {x:Reference}.  Using it, you can explicitly set the value of the target property with a reference to the named object. You can also use it as an object element which can reside in a collection.

If From/To didn’t use NameReferenceConverter (as described above), the XAML author could do this:

<Table Name="Customer"/>
<Table Name="Order"/>
<Relationship From="{x:Reference Customer}" To="{x:Reference Order}" Cardinality="OneToMany"/>

Type Authors – Build more complex minilanguages with integrated Name support

Somebody may want to build an expression engine that could “dot down” to arbitrary properties of objects like this:

<Button Height="{Expression namedObject1.Height + namedObject2.Height / 2}"/>

A markup extension or type converter could call GetService(typeof(IXamlNameResolver)) in order to get access to a service to search for named objects already encountered, or register a request for an object that hasn’t been seen yet. A sample of this may be worthy of another post.

Creating documents with x:Reference

XamlServices.Save() will add x:Reference as appropriate, based on the object graph you pass it.

Summary

Named references in XAML2009 is an important feature, helping to enable a number of scenarios for different XAML Vocabularies. We hope you enjoy.

(Please see “Note – What works where” at the very bottom of this post.)

 

Code Sample using NameReferenceConverter

Requires Beta1 of .NET 4.
(Command Line project with WindowsBase.dll and System.Xaml.dll as additional assembly references).

   1: using System;
   2: using System.Collections.Generic;
   3: using System.ComponentModel;
   4: using System.Windows.Markup;
   5: using System.Xaml;
   6:  
   7: namespace ReferenceExample
   8: {
   9:  
  10:     //when run, this program creates the following output:
  11:     /*
  12:     <DatabaseCollection Capacity="4" xmlns="clr-namespace:ReferenceExample;assembly=ReferenceExample">
  13:       <Table Name="Customer" />
  14:       <Table Name="Order" />
  15:       <Relationship Cardinality="OneToMany" From="Customer" To="Order" />
  16:       <Relationship Cardinality="OneToOne" From="Customer" />
  17:     </DatabaseCollection>
  18:     */
  19:  
  20:     class Program
  21:     {
  22:         static void Main(string[] args)
  23:         {
  24:             Table t1 = new Table();
  25:             t1.Name = "Customer";
  26:             Table t2 = new Table();
  27:             t2.Name = "Order";
  28:             Relationship r1 = new Relationship();
  29:             r1.From = t1;
  30:             r1.To = t2;
  31:             r1.Cardinality = Cardinality.OneToMany;
  32:             Relationship r2 = new Relationship();
  33:             r2.From = t1;
  34:  
  35:             DatabaseCollection dc = new DatabaseCollection();
  36:             dc.Add(t1);
  37:             dc.Add(t2);
  38:             dc.Add(r1);
  39:             dc.Add(r2);
  40:  
  41:             string xamlString = XamlServices.Save(dc);
  42:             Console.WriteLine(xamlString);
  43:  
  44:             Console.WriteLine("--press any key--");
  45:             Console.ReadKey();
  46:         }
  47:     }
  48:  
  49:     public abstract class DatabaseObject {} 
  50:     
  51:     public class DatabaseCollection : List<DatabaseObject> {}
  52:     
  53:     [RuntimeNameProperty("Name")]
  54:     public class Table : DatabaseObject
  55:     {
  56:         public string Name { get; set; }
  57:     }
  58:     public class Relationship : DatabaseObject
  59:     {
  60:         [TypeConverter(typeof(NameReferenceConverter2))]
  61:         [DefaultValue(null)]
  62:         public Table From { get; set; }
  63:  
  64:         [TypeConverter(typeof(NameReferenceConverter2))]
  65:         [DefaultValue(null)]
  66:         public Table To { get; set; }
  67:     
  68:         public Cardinality Cardinality { get; set; }
  69:     }
  70:  
  71:     public enum Cardinality
  72:     {
  73:         OneToOne,
  74:         OneToMany,
  75:         ManyToMany,
  76:     }
  77:  
  78:     //In .NET 4 Beta1, System.Xaml.NameReferenceConverter doesn't have ConvertTo/CanConvertTo implemented.
  79:     //Working around with a version hard coded for this scenario...
  80:     public class NameReferenceConverter2 : NameReferenceConverter
  81:     {
  82:         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
  83:         {
  84:             return destinationType == typeof(string);
  85:         }
  86:         public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
  87:         {
  88:             Table table = value as Table;
  89:             return table.Name;
  90:         }
  91:     }
  92:  
  93: }

 

[Note – what works where]

In .NET 4 Beta1, NameReferenceConverter + IXamlNameResolver should be mostly functional (we’ve fixed a few bugs since). {x:Reference} and <x:Reference /> won’t work when you compile XAML, but we plan to address this in .NET 4 (we believe that moving x:Reference from System.Xaml.Replacements to System.Windows.Markup will just make that work in the compiler).  Cider/Blend will likely won’t work initially.  See “Yes, XAML2009 isn't everywhere yet

Published Thursday, May 28, 2009 12:41 PM by Rob_Relyea
Filed under:

Comments

# re: Referencing a Named Object in XAML2009@ Friday, May 29, 2009 1:15 AM

So is {x:Reference myElement} effectively a shortcut for {Binding ElementName=myElement} ?

# re: Referencing a Named Object in XAML2009@ Friday, May 29, 2009 6:21 AM

Chris-

Yes, {Binding ElementName=myElement} is generally equivalent to {x:Reference myElement}.  However, since it is done at the parser level, it is only reliant on NameScopes during parse, as opposed to the search that Binding ends up doing to find an element.

Beyond that, I don't believe that we want most uses of Name References to have to use {x:Reference}.  NameReferenceConverter should be used for most places where people want to use NameReferences, which gives you just "myElement".

Another thing to realize is that as a "x:" construct, this works with any XAML vocabulary, including non-UI XAML based scenarios.

Thanks, Rob

# Referencing a Named Object in XAML2009 - Rob Relyea@ Friday, May 29, 2009 5:29 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

# System.Xaml: Method calls from Xaml@ Tuesday, June 09, 2009 10:41 AM

Xaml is awesome. I am hearing lot of "yeah"s... So have you tried out the new System.Xaml stack in .NET

# fikrim var netle??tirelim - A in XAML: Ain&#8217;t for WPF/Silverlight@ Sunday, October 25, 2009 10:43 AM

Pingback from  fikrim var netle??tirelim - A in XAML: Ain&#8217;t for WPF/Silverlight

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Page view counter