Welcome to WindowsClient.net | Sign in | Join

SilverLaw

Silverlight and WPF with VB.NET

Using XML with CSS inline style to generate a customized printable file with reusable data for Silverlight 3 applications

Printing support is yet a missing feature in Silverlight 3. This article won’t fix that. But it will give an example for a workaround that combines two tasks. First to generate an output file in a visually customized and printable format. Second the opportunity to save the data in a reusable format using XML. In the following example we are going to build the engine for an application that enables the user to manage different lawyers organized respective there branch of law. The snippets are creating an XML file that is styled inline using CSS and that can be opened in every browser. The XML file then can be printed by the user using the print dialog of the browser. The XML file itself will be saved in the file system of the user.

 

The logical XML structure

 

At first we need to create the logical structure of our XML data. Throughout this example I will use the following simple XML structure:

 

<?xml version="1.0" encoding="utf-8"?>

<lawyers>

    <lawyer>

        <id>

            <label></label>

            <value></value>

        </id>

        <name>

            <label></label>

            <value></value>

        </name>

        <branchoflaw>

            <label></label>

            <value></value>

        </branchoflaw>

    </lawyer>

</lawyers>

Every lawyer has an id, a name and a branch of law. The elements <id>, <name> and <branchoflaw> each have the two child elements <label> and <value>.  The values of the <label> elements are holding the display text for the visual representation of the XML data in the browser. The values of the <value> elements are holding the created and stored XML data respectively.

 

The Project

 

Start building a new Silverlight 3 project using Expression Blend 3 or Visual Studio 2008 SP1. Add a reference to the System.Xml and the System.Xml.Linq assemblies. Then insert the following imports statements:

 

Imports System.Xml.Linq

Imports System.IO

With the System.Xml.Linq namespace we build the logical xml data. The System.IO namespace we are going to use for the save file and open file actions.

In MainPage.xaml we need a Button and call it x:Name="btSave".

 

In MainPage.xaml.vb we declare a private member variable called xdoc that will hold the generated XML data.

 

  Private xdoc As XDocument

  Private Sub MainPage_Loaded( _

        ByVal sender As Object, _

        ByVal e As System.Windows.RoutedEventArgs) _

        Handles Me.Loaded

 

    xdoc = New XDocument

 

  End Sub

In the Click event handler of btSave we are calling two sub routines.

 

  Private Sub btSave_Click( _

    ByVal sender As Object, _

    ByVal e As System.Windows.RoutedEventArgs) _

  Handles btSave.Click

 

    BuildXml()

    SaveXMLFile()

 

  End Sub

Creating XDocument with XML literals

We build the Private Sub routine called BuildXml() where we are going to create the XML structure. In there we are using the technique to create XDocument with XML literals:

  Private Sub BuildXml()

 

    Dim xdoc As XDocument

    xdoc = <?xml version="1.0" encoding="utf-8"?>

           <lawyers>

             <lawyer>

               <id>

                 <label></label>

                 <value></value>

               </id>

               <name>

                 <label></label>

                 <value></value>

               </name>

               <branchoflaw>

                 <label></label>

                 <value></value>

               </branchoflaw>

             </lawyer>

           </lawyers>

 

  End Sub

If we create a XML file with the above logical structure and open it in the browser it looks like this:

 

If we would watch the XML file in the print preview of the browser it would exactly look the same. But we want that it (with sample data) looks like this in the browser and in the print preview of the browser respectively: 

To achieve this we have to add some code to the BuildXml() routine.

 

Creating the style for the XML in code behind

 

First we have to add a processing instruction into the XML code:

<?xml version="1.0" encoding="utf-8"?>

<?xml-stylesheet type="text/css" h ref="#DataViewStyle" ?>

<lawyers>

  ...

The href–attribute in the above processing instruction is pointing to the id –attribute of a XML element that we are creating in the next step to define the CSS layout style:

<?xml version="1.0" encoding="utf-8"?>

    <?xml-stylesheet type="text/css" h ref="#DataViewStyle" ?>

    <lawyers>

        <viewstyle id="DataViewStyle">

  ...

Within the XML element we called <viewstyle> we now simply write the CSS layout for our logical XML structure. Here you can create the CSS style of your choice to customize the look and feel of your visually desired XML output. For the above screenshot example the CSS in the <viewstyle> element is the following:

<viewstyle id="DataViewStyle">

    lawyer {

    display:block;

    margin-top:20px;

    margin-bottom:8px;

    margin-left:16px;

    font-size:14px;

    border-style:solid;

    border-color:#003366;

    border-width:1px;

    padding-left:20px;

    padding-top:8px;

    padding-bottom:8px

    }

    id {

    display:block;

    margin-top:8px;

    margin-bottom:8px;

    color:#3366CC;

    font-weight:bolder;

    }

    idlabel {

    display:inline-block;

    position:absolute;

    font-weight:bolder;

    min-width:220px;

    }

    idvalue {

    display:inline-block;

    position:relative;

    left:140px;

    }

    name, branchoflaw {

    display:block;

    margin-top:8px;

    margin-bottom:8px;

    }

    label {

    display:inline-block;

    position:absolute;

    font-weight:bolder;

    min-width:220px;

    }

    value {

    display:inline-block;

    position:relative;

    left:140px;

    }

    viewstyle {display:none}

</viewstyle>

Note the CSS layout instruction at the end of the CSS code for the <viewstyle> element itself:

<viewstyle id="DataViewStyle">

    ...

    viewstyle {display:none}

</viewstyle>

This is important to avoid displaying the <viewstyle> element itself in the visual and printable output. This line of CSS code has to be placed at the very end of your CSS code.

 

XML data input

 

There are many techniques to fill the XML file with your data objects. You can use e.g. the following to fill your XML file with values from your Data Objects.

 

We define a class for our Lawyer objects:

Public Class Lawyer

 

  Sub New()

    ' nix tun

  End Sub

 

  Public Sub New(ByVal id As Integer, _

                 ByVal name As String, _

                 ByVal branchoflaw As String)

    Me._id = id

    Me._name = name

    Me._branchoflaw = branchoflaw

  End Sub

 

  Private _id As Integer

  Private _name As String

  Private _branchoflaw As String

 

  Public ReadOnly Property ID() As Integer

    Get

      Return _id

    End Get

  End Property

 

  Public ReadOnly Property Name() As String

    Get

      Return _name

    End Get

  End Property

 

  Public ReadOnly Property BranchOfLaw() As String

    Get

      Return _branchoflaw

    End Get

  End Property

 

End Class

 

Using some of this Lawyer objects we build some data in code behind and as a result of our work the BuildXml() routine finally has the following code:

Private Sub BuildXml()

 

  Dim lawyerlist As List(Of Lawyer)

 

  lawyerlist = New List(Of Lawyer)

 

  With lawyerlist

    .Add(New Lawyer(1, _

        "Michael R.A. Miller", "patent law"))

    .Add(New Lawyer(2, _

        "Josefine Radcliff", "mercantile law"))

    .Add(New Lawyer(3, _

        "Jim Johnson", "law of torts"))

  End With

 

  For Each item As Lawyer In lawyerlist

    Select Case item.ID

      Case Is = 1

        xdoc = _

    <?xml version="1.0" encoding="utf-8"?>

    <?xml-stylesheet type="text/css"

                     h ref="#DataViewStyle" ?>

    <lawyers>

      <viewstyle id="DataViewStyle">

        lawyer {

        display:block;

        margin-top:20px;

        margin-bottom:8px;

        margin-left:16px;

        font-size:14px;

        border-style:solid;

        border-color:#003366;

        border-width:1px;

        padding-left:20px;

        padding-top:8px;

        padding-bottom:8px

        }

        id {

        display:block;

        margin-top:8px;

        margin-bottom:8px;

        color:#3366CC;

        font-weight:bolder;

        }

        idlabel {

        display:inline-block;

        position:absolute;

        font-weight:bolder;

        min-width:220px;

        }

        idvalue {

        display:inline-block;

        position:relative;

        left:140px;

        }

        name, branchoflaw {

        display:block;

        margin-top:8px;

        margin-bottom:8px;

        }

        label {

        display:inline-block;

        position:absolute;

        font-weight:bolder;

        min-width:220px;

        }

        value {

        display:inline-block;

        position:relative;

        left:140px;

        }

        viewstyle {display:none}

     </viewstyle>

      <lawyer>

        <id>

          <label>ID:</label>

          <value><%= item.ID.ToString %></value>

        </id>

        <name>

          <label>Name:</label>

          <value><%= item.Name %></value>

        </name>

        <branchoflaw>

          <label>Branch of Law:</label>

          <value><%= item.BranchOfLaw %></value>

        </branchoflaw>

      </lawyer>

    </lawyers>

      Case Else

        xdoc.<lawyers>(0).Add( _

      <lawyer>

        <id>

          <label>ID:</label>

          <value><%= item.ID.ToString %></value>

        </id>

        <name>

          <label>Name:</label>

          <value><%= item.Name %></value>

        </name>

        <branchoflaw>

          <label>Branch of Law:</label>

          <value><%= item.BranchOfLaw %></value>

        </branchoflaw>

      </lawyer>)

    End Select

  Next

 

End Sub

Save the XML file

 

Finally we need to save the XML file using the SaveFileDialog and StreamWriter. Here is the code:

Private Sub SaveXMLFile()

 

  Dim sDialog As New SaveFileDialog

  sDialog.Filter = "Xml files (*.xml)|*.xml"

  If sDialog.ShowDialog = True Then

    Using xstream As Stream = sDialog.OpenFile

      Using xwriter As New StreamWriter(xstream)

        xwriter.Write(xdoc)

      End Using

    End Using

  End If

 

End Sub

The resulting visual

 

And this is how the XML file looks in the browser. The look and feel in the print preview of the browser is exactly the same.

Last words

This workaround has several advantages.

 

1.       You are working with pure XML which enables you to use the entire power of LINQ to XML to create and manipulate your data including querying.

 

2.       Using CSS you have a powerful language to design customized solutions for the visual output.

 

3.       The created XML file has its style inline which means that you don’t need a separate file for the style. Maybe this is the biggest advantage of this workaround. If the style would be in a separate file one would never know at runtime where in the file system the user saved his XML file and the file for the style respectively. But one would need this knowledge to get/set a reference to the style.

 

Using the OpenFileDialog you are able to write code for runtime actions of users data manipulations.

 

That’s it. I hope this was useful to bridge the time until Silverlight 4 will be released with printing support.  Best regards,

 

M. (SilverLaw)

 

Comments

No Comments

Leave a Comment

(required) 

(required) 

(optional)

(required) 

Page view counter