In my previous post I have shown how we can use a C# function in the XSLT. Now I want to go one step further and use in the transformation the ASP.NET controls along with their events.
Let's start from the sample xml data:
<files>
<file Id="F58C2962-AC0D-4C55-80A8-79A724669F53" Name="file 1" Path="D:\Temp\" Extension="iso"/>
<file Id="FDC1358E-D9C8-4A70-ABE0-E0EF5E742E08" Name="file 2" Path="D:\Temp\" Extension="jpg"/>
</files>
I want to create a table from it and for each row I want to have a link which opens the Windows Explorer with this file selected. I have an ASP.NET Development Server so it will work. XSL for this xml looks as follow:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:StringExtensions="urn:StringExtensions" xmlns:asp="remove"
>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<table>
<tr>
<th>File name</th>
<th>Path</th>
<th>Extension</th>
</tr>
<xsl:for-each select ="files/file">
<tr>
<td>
<xsl:value-of select ="@Name"/>
</td>
<td>
<xsl:value-of select ="@Path"/>
</td>
<td>
<xsl:value-of select ="@Extension"/>
</td>
<td>
<asp:LinkButton runat="server" ID="{StringExtensions:Replace(@Id,'-','')}">Open</asp:LinkButton>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
I have used here a custom function to replace some characters. How to create that function is explained in my previous post. Link is in the first line of this post.
We can't just put an ASP.NET control in the stylesheet, because we will get an exception: System.Xml.XmlException: „asp” is not a declared prefix. To workaround it we must put in the stylesheet declaration new attribute: xmlns:asp="remove".
When we transform the xml data with this styleshet, next step is to create an ASP.NET control from html we got:
private Control CreateControl(string html)
{
html.Replace("xmlns:asp=\"remove\"", "");
return Page.ParseControl(html);
}
Now we can add this control to the placeholder control on our page.
The last what we have to do is to bind the click event to ours LinkButton's controls:
private void BindEvents()
{
var r = PlaceHolder1.FlattenChildren().OfType<LinkButton>().ToList();
r.ForEach(x =>
{
x.Click += LinkButton1_Click;
});
}
The FlattenChildren is an extension method which I found somewhere. It returns all the child control:
public static IEnumerable<Control> FlattenChildren(this Control control)
{
var children = control.Controls.Cast<Control>();
return children.SelectMany(c => FlattenChildren(c)).Concat(children);
}
Sample event can look like this:
protected void LinkButton1_Click(object sender, EventArgs e)
{
var elem = ((LinkButton)sender).ID;
Guid fileId = Guid.Parse(elem);
File selectedFile = DBSearchService.GetFileWithPathAndExtension(fileId);
Process.Start(new ProcessStartInfo("explorer", String.Format("/select, {0}\\{1}.{2}",
selectedFile.Path.Path,
selectedFile.Name, selectedFile.Extension.Name)));
}