Showing posts with label DataTemplate. Show all posts
Showing posts with label DataTemplate. Show all posts

Wednesday, 8 April 2009

Intercepting xaml DataTemplate of a given DataType

Since a few months I am working on a project where we use integrate WPF with and IOC, Castle Windsor (through the extension of the Composite WPF Contrib).

One of our xaml file would look like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/
xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Presentation="clr-namespace:XXX.Modules.MyForm.Presentation"
xmlns:WinForms="clr-namespace:XXX.Modules.Common.WinForms"
xmlns:Converters="clr-namespace:XXX.Modules.Common.Converters"

<converters:booleanenumconverter key="YYYConverter">
[snipped other converters]
<DataTemplate DataType="{x:Type
Presentation:MyFormPresentationModel}">
[snipped template xaml]
</datatemplate>
</resourcedictionary>
I wrote a couple of interceptors (inheriting from IInterceptor and implementing Intercept), but when I try to use them resolving the presentation model, the xaml DataTemplate resolves to a string (the name of the generated proxy, something as IMyFormPresentationModelProxy1de831fc74a341249b67...), not to the instanced object (which stepping in in debug I can see it is registered and then created and then also proxied correctly, as far as I can understand). This is exactly the same behaviour we get if we try to use the interface (i.e. setting the DataType to "{x:Type Presentation:IMyFormPresentationModel}" we get a string as well instead of the object).

Using the .Net reference source symbols (and/or deblector) I have been trying to step in on the exact bit of code which is setting that string instead of the correct proxied object or even the underlying instanced object, but with no luck so far.

I do think the issue may be with the xaml engine being unable to match the proxied type with the DataType of the DataTemplate, and I found out the .Net framework may perform that using the TypeExtension/MarkupExtension/DataTemplateSelector classes and possibly some implementation of the IXamlTypeResolver interface. From a quick search, I found out nowadays people is using those mostly to provide some support for generics in xaml (see i.e. "How To Get ParserContext" or "Limited generics support in Xaml").

From a purely theoretical point of view, I don't like much the idea to have to modify the xaml files to be able to intercept them, so I am not absolutely sure I have been missing something.

Before trying to spend some time on that (i.e. writing our own TypeExtension), I thought it could be better asking around if there is someone with previous experience or also some insight on this kind of scenario, so I have been posting a similar text to various newsgroups and mailing lists.

Last but not least, although I don't guess this is a Windsor bug (or at last I cannot yet see why it should be :)), we are using Castle project assemblies built from the revision 5380 of the 19th October 2008 in the trunk.

Intercettare/Ereditare il DataType per un DataTemplate in xaml

Da qualche mese lavoro ad un progetto dove usiamo WPF integrato con un IOC container (Castle Windsor, tramite l'estensione fornita dal progetto Composite WPF Contrib).

Abbiamo un file xaml simile a questo pseudo-codice:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/
xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Presentation="clr-namespace:XXX.Modules.MyForm.Presentation"
xmlns:WinForms="clr-namespace:XXX.Modules.Common.WinForms"
xmlns:Converters="clr-namespace:XXX.Modules.Common.Converters"

<converters:booleanenumconverter key="YYYConverter">
[snipped other converters]
<DataTemplate DataType="{x:Type
Presentation:MyFormPresentationModel}">
[snipped template xaml]
</datatemplate>
</resourcedictionary>
Ho scritto un paio di intercettori (in pratica usando un componente chiamato Castle Dynamic Proxy, questi generano delle classi che ereditano i componenti registrati con Windsor e che poi si possono usare per intercettare i metodi prima e dopo la loro esecuzione, ad esempio per scrivere dei log o per fare altre cose), ma quando tento di usarli risolvendo i vari componenti intercettati, i DataTemplate definiti nei file xaml dei componenti non risolvono l'oggetto generato (che e' stato istanziato correttamente da Windsor, come posso ad esempio vedere mentre sono in debug), ma ritornano una stringa, che poi altro non e' che il nome del proxy generato (una cosa tipo IMyFormPresentationModelProxy1de831fc74a341249b67...).

Questo e' un comportamento molto simile a quello che incontro quando tento di usare un'interfaccia come DataType del DataTemplate (ad esempio impostando il DataType ad una cosa come "{x:Type Presentation:IMyFormPresentationModel}"), per cui immagino che il DataType non supporti molto bene l'ereditarieta' (o comunque sia piuttosto conservativo nella risoluzione dei tipi).

Dato che non penso che il problema sia nell'IOC o nell'estensione tramite la quale lo integriamo con WPF, immagino che il problema sia quindi che lo "xaml engine" non sia capace di far corrispondere il tipo descritto nel file xaml con quello generato dall'intercettore.

Ho fatto un po di ricerche, ed ho trovato che c'e' gente che per fare cose probabilmente simili (perlopiu' collegate al fatto che il DataType non supporta pienamente i tipi generici, vedi ad esempio "How To Get ParserContext" oppure "Limited generics support in Xaml") usa classi come TypeExtension o MarkupExtension e possibilmente qualche implementazione dell'interfaccia IXamlTypeResolver. Ho anche trovato qualche accenno al possibile uso di un DataTemplateSelector.

Da un punto di vista puramente teorico, l'idea di dover modificare i file xaml per poter intercettare i DataTemplate non mi attrae particolarmente, quindi mi sto chiedendo se per caso non mi sono perso qualcosa.

Prima di investire altro tempo per risolvere il problema (ad esempio scrivendo una mia TypeExtension), sto cercando di chiedere in vari gruppi o mailing list se c'e' qualcuno che abbia esperienza di questo tipo scenario (o qualcuno simile, magari qualcosa che abbia a che fare con l'ereditarieta' ed i tipi definiti in DataType per DataTemplate).

Anche soltanto qualche suggerimento o qualche referenza sarebbe molto gradita :)

Ho gia' scritto un messaggio molto simile sulla mailing list di Castle, ma immagino che questo non sia un bug di Windsor, ma il risultato di una limitazione (o di una scelta progettuale) del DataType.