wpfXmlBindingDemo

(Hide table-of-contents)

wpfXmlBindingDemo is a Dyalog APL namespace that shows examples of how to bind a XML representation of APL data to a WPF user interface.

Overview

When building a User Interface (UI) with WPF, the APLer can use Xaml or code directly with APL. Some examples of using Xaml can be found at wpfXamlDemo.

Either way the UI needs to be populated with the data and again this can be done either directly within the APL code or with DataBinding.

With APL code each element of the UI controls that display data will need to be written with the value of an APL variable. With DataBinding it is possible to bind the value of an APL variable directly with multiple controls of the UI.

If the DataBinding is made bidirectional then changes in the UI are immediately reflected by the associated APL variable. When using just APL code the data will need to be retrieved from each control and saved back to the APL variable.

For binding you can use the I-Beam 2015 (2015⌶) from Dyalog, a .Net DataTable, a .Net XmlDocument or even a database. In all cases the APL data will need to be converted to a .Net object so it can be used by the UI that resides on the .Net side of the fence.

Some utility functions for dealing with .Net DataTables are available at netDataTable.

Refer to the Dyalog tutorials on how to use the 2015⌶ I-Beam. For large tabular data, binding with a DataTable will be faster than binding with XML. When there is a multitude of single controls to bind from the same APL variable XML is the better choice. This page will demonstrate the use of a .Net XmlDocument representing the APL data for binding with WPF controls.

XML Representation of APL Data

The XML representation of the data needs to be made in such a way that the XPath used in the Binding will be able to find the data but also it needs to contain all the information to revert the XmlDocument back to APL data when used with two-way binding.

The functions AplToXml and XmlToApl in the attached namespace are doing just that for simple APL data that is not nested.

Here are some examples:

Vector:

    ⍝ Example for a vector
      {⎕XML ⎕XML ⍵.OuterXml} AplToXml 1 2 (⍳0) ('') 'some text'

<Data Rank="1" Shape="5" Type="array" xmlns="">     ⍝ 'Data' is the name of the root element by default.
  <n>1</n>
  <n>2</n>             ⍝ The Rank(⍴⍴), Shape(⍴) and the Type(array or namespace) are attributes in the root element
  <n></n>              ⍝ The name of the elements with the data is either <n>(for number) or <s>(for string)
  <s></s>              ⍝ The 'Elements' of the Xml are holding the data.
  <s>some text</s>     ⍝ Empty values are permitted and used for place holder. Use ⍳0 for numbers and '' for characters.
</Data>

The function AplToXml is returning a .Net XmlDocument. To see the characters the property .OuterXml is used. Typical binding for the third element would be: "{Binding XPath=/Data/*[3]}" or for the whole vector: "{Binding XPath=/Data/*}"

Matrix:

    ⍝ Example for a matrix
      {⎕XML ⎕XML ⍵.OuterXml} AplToXml 2 3 ⍴ 1 2 'three' 4 'five' 6

<Data Rank="2" Shape="2 3" Type="array" xmlns=""> ⍝ This is the 'Attribute' style representation of the matrix
  <nns C1="1" C2="2"    C3="three"></nns>         ⍝ The name of the elements are still 'n' for numbers and 's' for characters
  <nsn C1="4" C2="five" C3="6">    </nsn>         ⍝ The column names are 'C1', 'C2' etc. by default
</Data>                                           ⍝ The 'Attributes' of the Xml are holding the data. Elements are empty

    ⍝ The equivalent 'Element' style representation is shown below for information only:
<Data Rank="2" Shape="2 3" Type="array" xmlns="">
  <DataPoint>
    <C1 Type="n">1</C1>
    <C2 Type="n">2</C2>
    <C3 Type="s">three</C3>
  </DataPoint>
  <DataPoint>
    <C1 Type="n">4</C1>
    <C2 Type="s">five</C2>
    <C3 Type="n">6</C3>
  </DataPoint>
</Data>

The 'Attribute' style was retained because it is taking less characters to write. A matrix will typically be used for a DataGrid, ListView and ListBox. The names of the columns are prefix at 'C1', 'C2', 'C3', etc. Typical binding for the first column would be: "{Binding XPath=/Data/@C1}"

Simple Namespace

    ⍝ Example for a simple namespace:

      ns ← ⎕NS ''
      ns.firstName ← ⊂'Marco'
      ns.lastName  ← ⊂'Polo'
      ns.location  ← ⊂'Venezia'
      ns.interest  ← ⊂'Travelling'

      {⎕XML ⎕XML ⍵.OuterXml} AplToXml ns

<Data Type="ns" xmlns="">
  <firstName Rank="0" Shape="0" Type="array" xmlns="">
    <s>Marco</s>
  </firstName>
  <lastName Rank="0" Shape="0" Type="array" xmlns="">
    <s>Polo</s>
  </lastName>
  <location Rank="0" Shape="0" Type="array" xmlns="">
    <s>Venezia</s>
  </location>
  <interest Rank="0" Shape="0" Type="array" xmlns="">
    <s>Travelling</s>
  </interest>
</Data>

Each property name of the namespace will hold data. The binding will refer to that property name in the Xaml.

It is not necessary for the objects in the Xaml to have a Name or x:Name defined for the binding to work. Typical binding would be: "{Binding XPath=/Data/firstName/*}" or "{Binding XPath=//firstName/*}". This type of representation of the APL data can have a converter on the APL side; more information is provided below. The function demo1 in the attached namespace has a complete example for this type of binding.

Namespace within a Namespace

     ⍝ Example of namespace within a namespace

            ns ← ⎕NS ''
      ns.Books ← ⎕NS ''
      ns.Books.Author ← 'author1' 'author2' 'author3'
      ns.Books.Title  ← 'title1' 'title2' 'title3'
      ns.Books.ID     ← 100 101 103

      {⎕XML ⎕XML ⍵.OuterXml} AplToXml ns
<Data Type="ns" xmlns="">
  <Books Rank="2" Shape="3 3" Type="nsArray" xmlns="">
    <sns Author="author1" ID="100" Title="title1"></sns>
    <sns Author="author2" ID="101" Title="title2"></sns>
    <sns Author="author3" ID="103" Title="title3"></sns>
  </Books>
</Data>

Each property of the namespace Books must have the same number of items. This is typical for binding data that will be presented in a tabular form like a DataGrid or a ListView where each column will have a selected name (this will allow a converter on the APL side to function as well).

A typical binding would be: "{Binding XPath=/Data/Books/@Author}".

The function demo2 in the attached namespace is a comprehensive example for this type of binding.

The functions AplToXml and XmlToApl are used for two-way binding. The functions has to figure out the data type (numeric or character) of each value. The function MatToXml can be used for one-way binding of an APL matrix without checking if each item is numeric or character. It is perfect for displaying a large quantity of information on a DataGrid or ListView when there is no need to convert the data back to APL.

See the function demo3 for an example.

About XPath

If you are not sure of the syntax for XPath you can use the function XmlDocToFile included in the attached namespace to write the XmlDocument to disk, then create a DataSource from the file in Visual Studio and let Visual Studio write the XPath.

Data Conversion While Binding

If you bind using XML the characters 'Red' to the property 'Background' of a button, the button will be of the color red. This is because the XAML engine will convert the characters 'Red' to a .Net Brush object internally. Usually you can use the same characters that are used to define a property in XAML for binding in XML (the XAML engine will try to do the conversion).

When coding in APL, the conversion from a character to a .Net Brush will need to be made on the APL side (ex.: ⎕NEW SolidColorBrush (Colors.Red)). Here are some examples of properties and the characters that they are expecting while binding with XML:

Property

Characters

Comments

Color

Literal (like 'Red') or Hexadecimal (like #FFFF0000)

See the MSDN for the list of permitted literal color

DateTime

DateTime formatted as format 'G'

(⎕NEW DateTime ⎕TS).ToString(⊂,'G')

Boolean

'True', 'False' or 'Indeterminate'

Visibility

'Visible', 'Hidden' or 'Collapsed'

Number

Number as characters only

for .Net Double use StringToDoubleConverter

For controls that are expecting a .Net object (like a Double, DateTime or Image) and are not compatible with characters as input values a converter on the .Net side will be required.

Converters

As we can see while binding using XML it is always characters that are passed as an argument. There are no numbers, only the character representation of those numbers. The DateTime .Net object is represented as ⎕TS formatted as characters with format 'G' (for ⎕TS equal to (2015 3 30 16 40 10) the character representation in format 'G' will be '03/30/2015 16:40:10').

Also sometimes the characters expected for binding are not what an APLer would like to use. For example, an APLer is expecting a 1 or 0 as value for a Boolean but the XML binding is expecting the characters 'True' and 'False' instead.

A control receiving the character representation of numbers may also refuse to cooperate because it was expecting real numbers. This problem can be solved by using Converters.

A Converter can be used either on the APL side or on the .Net side. When used on the APL side it is a function that will convert for example the text vector 'True' to numeric 1 and the text vectors 'False' to numeric 0 and vice versa.

When used on the .Net side it will be declared in the Xaml and will require a special DLL with the converters functions written in a language like C#. Syncfusion has many controls that will accept characters as input value and will show a formatted output without the use of a converter:

Converters .Net Side

Included in the attached zip file is a file named XmlConverters.dll which contains the following basic converters useful when binding with XML:

Name

APL ↔ .Net

BooleanConverter

1 0 ¯1 ↔ 'True' | 'False' | 'Indeterminate'

VisibilityConverter

1 0 ¯1 ↔ 'Visible' | 'Hidden' | 'Collapsed'

StringToDoubleConverter

number ↔ .Net Double

StringToDateConverter

characters of a DateTime ↔ .Net DateTime

OADateToDateConverter

OADate ↔ .Net DateTime

Base64ImageConverter

Base64 characters of an image file --> .Net Image

The DLL XmlConverters.dll needs to be in the same directory as dyalog.exe. The declarations in the Xaml shall be like this (only the converter(s) used need to be declared) and ⎕USING does not need to be define because it is in the same directory as dyalog.exe:

<Window
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:xmlCvt="clr-namespace:XmlConverters;assembly=XmlConverters">
   <Window.Resources>
      <xmlCvt:BooleanConverter        x:Key="bCvt"/>
      <xmlCvt:VisibilityConverter     x:Key="vCvt"/>
      <xmlCvt:StringToDoubleConverter x:Key="s2dCvt"/>
      <xmlCvt:StringToDateConverter   x:Key="s2dtCvt"/>
      <xmlCvt:OADateToDateConverter   x:Key="oadt2dtCvt"/>
      <xmlCvt:Base64ImageConverter    x:Key="b642iCvt"/>
   </Window.Resources>
</Window>

The function demo4 can be used to experiment with XmlConverters.dll. There are also many converters included in the assemblies of Syncfusion that can be used.

Converters APL Side

A converter on the APL side will be easier to use for an APLer. A typical direct function for a Boolean converter will look like this:

 _b←{               ⍝ Boolean Converter
     ⍵≡1:'True'     ⍝  1 = 'True'
     ⍵≡0:'False'    ⍝  0 = 'False'
     ⍵≡¯1:''        ⍝ ¯1 = 'Indeterminate'
     ⍵≡'True':1     ⍝ 'True'  =  1
     ⍵≡'False':0    ⍝ 'False' =  0
     ⍵≡'':¯1        ⍝  Empty  = ¯1
     ' '=↑1↑0⍴⍵:0   ⍝ Any character = 0
     'False'        ⍝ Any number = 'False'
 }

The function AplToXml and XmlToApl will use automatically the converter if the name of the property of the namespace is terminating by the name of the converter. It cannot be used if there is no name (only when there is a namespace). For example for the Boolean converter ('_b'):

      ns ← ⎕NS''
      ns.check1_IsChecked_b ← 1
      ns.check2_IsChecked_b ← 0

      {⎕XML ⎕XML ⍵.OuterXml} AplToXml ns
<Data Type="namespace" xmlns="">
  <check1_IsChecked_b Rank="0" Shape="0" Type="array" xmlns="">
    <b>True</b>                  ⍝ The name of the element 'b' is the name of the converter.
  </check1_IsChecked_b>
  <check2_IsChecked_b Rank="0" Shape="0" Type="array" xmlns="">
    <b>False</b>
  </check2_IsChecked_b>
</Data>

The numeric 1 and 0 are converted to the text vectors 'True' and 'False' and vice versa for a two-way binding. Here is the list of APL converters included in the attached namespace:

Type

Name

APL ↔ .Net

Boolean

_b

1 0 ¯1 ↔ 'True' 'False' 'Indeterminate'

Visibility

_v

1 0 ¯1 ↔ 'Visible' 'Hidden' 'Collapsed'

Color

_c

numeric (R,G,B) or (256⊥R,G,B) ↔ Hexadecimal Color in characters

DateTime

_d

numeric OADate ↔ DateTime in format 'G' in characters

DateTime

_D

numeric ⎕TS ↔ DateTime in format 'G' in characters

The function demo5 is a fully-fledged example of XML Binding with WPF's basics controls while using the converters on the APL side. Here is a screenshot taken after executing the function:

demo5.png

Installation

  1. Download the file wpfXmlBindingDemo.1.1.zip. It contains the scripted namespace wpfXmlBindingDemo.txt and a DLL named XmlConverters.dll

  2. Do a "Select all" (Ctrl+A) and a "Copy" (Ctrl+C) of wpfXmlBindingDemo.txt.

  3. In your workspace execute )ed ⍟ wpfXmlBindingDemo.

  4. Paste (Ctrl+V) the text into the Dyalog editor.
  5. Press Escape and ')save' your workspace.
  6. Copy the file XmlConverters.dll into the Dyalog installation directory as shown by +2 ⎕NQ'.' 'GetEnvironment' 'Dyalog'. You may need administrator privileges for this.

Optionally to de-script the namespace you can do:

#.wpfXmlBindingDemo←{('n' ⎕NS ⍵)⊢n←⎕NS ''}#.wpfXmlBindingDemo

Version Information

Original author:

Pierre Gilbert

Responsible:

PierreGilbert

Email:

<apgil AT SPAMFREE videotron DOT ca>


CategoryDyalog - CategoryDyalogDotNet - CategoryDyalogWpfUtilities - CategoryDotNet

wpfXmlBindingDemo (last edited 2015-09-18 20:19:55 by PierreGilbert)