WPF XAML demo: Difference between revisions

Jump to navigation Jump to search
128 bytes removed ,  13:19, 7 May 2020
This is an essay, not an article, so it shouldn't use article subject styling
(This is an essay, not an article, so it shouldn't use article subject styling)
(7 intermediate revisions by one other user not shown)
Line 1: Line 1:
= wpfXamlDemo =
This page gives a [[Dyalog APL]] demonstratration of WPF XAMPL with some utility functions, delivered in the form of a [[namespace]].


'''wpfXamlDemo''' is a Dyalog APL namespace that demonstrates the use of WPF Xaml with some utility functions.
Please read the Dyalog tutorials for a more detailed explanation. Part of the code was taken from ''[http://www.codeproject.com/Articles/22980/WPF-A-Beginner-s-Guide-Part-of-n CodeProject: A Beginner's Guide]''.


Please read the Dyalog tutorials for a more detailed explanation. Part of the code was taken from <ref>[http://www.codeproject.com/Articles/22980/WPF-A-Beginner-s-Guide-Part-of-n CodeProject: A Beginner's Guide]</ref>
=== What is XAML? ===
 
[[wikipedia:XAML|XAML]] stands for Extensible Application Markup Language (and pronounced "Zammel"). It's a simple language based on [[wikipedia:XML]] to create and initialize [[.NET]] objects with hierarchical relations.
=== WHAT IS XAML ? ===
XAML stands for Extensible Application Markup Language (and pronounced "Zammel"). It's a simple language based on XML to create and initialize .NET objects with hierarchical relations.


All you can do in XAML can also be done in code. XAML is just another way to create and initialize objects.
All you can do in XAML can also be done in code. XAML is just another way to create and initialize objects.


You can use WPF without using XAML. It's up to you whether you want to declare it in XAML or write it as code.  There is a [https://msdn.microsoft.com/en-us/library/ms752059(v=vs.100).aspx Xaml Overview] from Microsoft.
You can use WPF without using XAML. It's up to you whether you want to declare it in XAML or write it as code.  There is a [https://msdn.microsoft.com/en-us/library/ms752059(v=vs.100).aspx XAML Overview] from Microsoft.


{{Collapse|Here is an example of Xaml found in the attached namespace called '''sample1''':|
{{Collapse|Here is an example of XAML found in the attached namespace called '''sample1''':|
<source lang=xml>
<source lang=xml>
<Window
<Window
Line 46: Line 44:
</source>
</source>
}}
}}
=== FixSimpleXaml ===
=== FixSimpleXaml ===
If you install the attached namespace and execute the following 2 lines in your workspace:
If you install the attached namespace and execute the following 2 lines in your workspace:
Line 56: Line 55:
{{attachment:Sample1.png || width=250}}
{{attachment:Sample1.png || width=250}}


<source lang=apl inline>FixSimpleXaml</source> is a function used to execute the Xaml and return the root element as a .Net object.  All the other elements that are named in the Xaml will be attached to their names to the root object automatically.
<source lang=apl inline>FixSimpleXaml</source> is a function used to execute the XAML and return the root element as a .Net object.  All the other elements that are named in the XAML will be attached to their names to the root object automatically.


For example, the element '''!TextBox''' that is named '''textBox1''' (line 15) and the element '''Button''' that is named '''button1''' (line 22) are attached automatically to the root element by the function <source lang=apl inline>FixSimpleXaml</source>:
For example, the element '''!TextBox''' that is named '''textBox1''' (line 15) and the element '''Button''' that is named '''button1''' (line 22) are attached automatically to the root element by the function <source lang=apl inline>FixSimpleXaml</source>:
Line 66: Line 65:
</source>
</source>


That way you don't need to define a separate variable for each named element. If you install the User Command [[sfPropGrid||]] you can see all the properties, methods and events of all the named objects by doing (click the combo of NOE to access all the named objects):
That way you don't need to define a separate variable for each named element. If you install the [[user command]] called <source lang=apl inline>sfPropGrid</source> you can see all the properties, methods and events of all the named objects by doing (click the combo of NOE to access all the named objects):
<source lang=apl>
<source lang=apl>
       ]noe win      ⍝ noe = .Net Object Explorer
       ]noe win      ⍝ noe = .Net Object Explorer
</source>
</source>
In conclusion <source lang=apl inline>FixSimpleXaml</source> is a simple function to use on simple Xaml that does not have events and is properly formed.  In production code you may want to do something like this:
In conclusion <source lang=apl inline>FixSimpleXaml</source> is a simple function to use on simple XAML that does not have events and is properly formed.  In production code you may want to do something like this:
<source lang=apl>
<source lang=apl>
  :If ⎕NULL≡myObject ← FixSimpleXaml myXaml
  :If ⎕NULL≡myObject ← FixSimpleXaml myXaml
     ⍝ Fixing the Xaml did not work. Show an error and exit.
     ⍝ Fixing the XAML did not work. Show an error and exit.
     ⎕ ← 'Error Fixing Xaml'
     ⎕ ← 'Error Fixing XAML'
     →0
     →0
  :Else
  :Else
Line 82: Line 81:


=== FixXaml ===
=== FixXaml ===
{{Collapse|For cases where there are events that need to be fixed and have better error handling the function <source lang=apl inline>FixXaml</source> is available.  It is useful when using Xaml taken directly from Visual Studio.  For example, with the Xaml code in '''sample2''' that has an event on the button (Click<nowiki>=</nowiki>"<source lang=apl inline>__Button_Click</source>") at line 24, if you do the following:|
{{Collapse|For cases where there are events that need to be fixed and have better error handling the function <source lang=apl inline>FixXaml</source> is available.  It is useful when using XAML taken directly from Visual Studio.  For example, with the XAML code in '''sample2''' that has an event on the button (Click<nowiki>=</nowiki>"<source lang=apl inline>__Button_Click</source>") at line 24, if you do the following:|
<source lang=xml>
<source lang=xml>
<Window
<Window
Line 131: Line 130:
The function <source lang=apl inline>__Button_Click</source> is handling the event.  The author has taken the convention of naming the callback functions with a double underscore prefix.
The function <source lang=apl inline>__Button_Click</source> is handling the event.  The author has taken the convention of naming the callback functions with a double underscore prefix.


The goal is to be able to take the Xaml directly from Visual Studio to APL.  The single underscore '_' is a valid first character in Visual Studio and APL but is in conflict with the menu object that will accept an underscore as the first character to define a keyboard shortcut.
The goal is to be able to take the XAML directly from Visual Studio to APL.  The single underscore '_' is a valid first character in Visual Studio and APL but is in conflict with the menu object that will accept an underscore as the first character to define a keyboard shortcut.


The line 5 of '''sample2''' (x:Class="!WpfApplication3.!MainWindow") that is required by Visual Studio is removed by <source lang=apl inline>FixXaml</source>.  See the comments in the function for more information.
The line 5 of '''sample2''' (x:Class="!WpfApplication3.!MainWindow") that is required by Visual Studio is removed by <source lang=apl inline>FixXaml</source>.  See the comments in the function for more information.
Line 138: Line 137:
<source lang=apl>
<source lang=apl>
  :If ⎕NULL≡↑myObject ← FixXaml myXaml
  :If ⎕NULL≡↑myObject ← FixXaml myXaml
     ⍝ Fixing the Xaml did not work. Show an error and exit.
     ⍝ Fixing the XAML did not work. Show an error and exit.
     ⎕ ← 2⊃myObject
     ⎕ ← 2⊃myObject
     →0
     →0
Line 147: Line 146:


=== About ⎕USING ===
=== About ⎕USING ===
In general, when using Xaml there is no need to define a <source lang=apl inline>⎕USING</source> before fixing it except when there is a 3rd party dll involved.  For example, the variable <source lang=apl inline>NewWindow</source> is defined as:
In general, when using XAML there is no need to define a <source lang=apl inline>⎕USING</source> before fixing it except when there is a 3rd party dll involved.  For example, the variable <source lang=apl inline>NewWindow</source> is defined as:
<source lang=apl>
<source lang=apl>
<Window
<Window
Line 165: Line 164:
       win.Show
       win.Show
</source>
</source>
The first element of Xaml must contain the '''xmlns=''' and the '''xmlns:x=''' declarations. This is instructing the parser (in our case '''System.Windows.Markup.!XamlReader''' in the function <source lang=apl inline>FixSimpleXaml</source> and <source lang=apl inline>FixXaml</source>) to load a series of .NET namespaces required to parse the Xaml.  This is just a convention, there is actually no such web site.
The first element of XAML must contain the '''xmlns=''' and the '''xmlns:x=''' declarations. This is instructing the parser (in our case '''System.Windows.Markup.!XamlReader''' in the function <source lang=apl inline>FixSimpleXaml</source> and <source lang=apl inline>FixXaml</source>) to load a series of .NET namespaces required to parse the XAML.  This is just a convention, there is actually no such web site.


=== 3rd Party Dll ===
=== 3rd Party Dll ===
When using 3rd party dll, they must be added to the declaration in the first element of Xaml.  There are 2 choices on how to do it:
When using 3rd party dll, they must be added to the declaration in the first element of XAML.  There are 2 choices on how to do it:


<source lang=apl>
<source lang=apl>
Line 179: Line 178:
   xmlns:sf="clr-namespace:Syncfusion.Windows.PropertyGrid;assembly=Syncfusion.PropertyGrid.Wpf"  ⍝ Notice no .dll at the end
   xmlns:sf="clr-namespace:Syncfusion.Windows.PropertyGrid;assembly=Syncfusion.PropertyGrid.Wpf"  ⍝ Notice no .dll at the end
</source>
</source>
and the Xaml will look like this:
and the XAML will look like this:
<source lang=apl>
<source lang=apl>
   <sf:PropertyGrid x:Name="PGrid"/>  ⍝ Notice the prefix 'sf' is the same on both lines (you choose the prefix).
   <sf:PropertyGrid x:Name="PGrid"/>  ⍝ Notice the prefix 'sf' is the same on both lines (you choose the prefix).
</source>
</source>
but this is not enough, <source lang=apl inline>⎕USING</source> must be set up correctly before fixing the Xaml for 3rd party dlls in order for the parser to find the assembly.  Here is an example for the Syncfusion !PropertyGrid ('''Syncfusion/4.5/''' is the Dyalog sub-directory where the assemblies live):
but this is not enough, <source lang=apl inline>⎕USING</source> must be set up correctly before fixing the XAML for 3rd party dlls in order for the parser to find the assembly.  Here is an example for the Syncfusion !PropertyGrid ('''Syncfusion/4.5/''' is the Dyalog sub-directory where the assemblies live):
<source lang=apl>
<source lang=apl>
     ⎕USING ← 'Syncfusion.Windows.PropertyGrid,Syncfusion/4.5/Syncfusion.PropertyGrid.Wpf.dll'    ⍝ The .dll is required
     ⎕USING ← 'Syncfusion.Windows.PropertyGrid,Syncfusion/4.5/Syncfusion.PropertyGrid.Wpf.dll'    ⍝ The .dll is required
Line 263: Line 262:
</source>
</source>
=== Fixing Images ===
=== Fixing Images ===
In Xaml you declare an Image object that is on disk the following way:
In XAML you declare an Image object that is on disk the following way:
<source lang=apl>
<source lang=apl>
<Image x:Name="MyImageName"
<Image x:Name="MyImageName"
Line 270: Line 269:
       Height="24"/>
       Height="24"/>
</source>
</source>
When you want to keep the Image definition in the APL workspace (because it is easier that way to distribute the workspace or the namespace) one way of doing it is by keeping a '''Base64''' definition of the Image. '''Base64''' encoding is using a set of 64 visible characters to encode binary data.
When you want to keep the Image definition in the APL workspace (because it is easier that way to distribute the workspace or the namespace) one way of doing it is by keeping a [[wikipedia:Base64|Base64]] definition of the Image. Base64 encoding is using a set of 64 visible characters to encode binary data.


It is widely used on the internet, for example in emails for images and binary attachments definition of Base64 on <ref>[http://en.wikipedia.org/wiki/Base64 Wikipedia: Base64]</ref>).
It is widely used on the internet, for example in emails for images and binary attachments.


Here are the steps to use this technique with APL:
Here are the steps to use this technique with APL:


==== Step 1: Save all the images in the workspace with the function FileToBase64String ====
==== Step 1: Save all the images in the workspace with the function FileToBase64String ====
At design time, save the images in the workspace.  The APL variable name of any image must be the original name of the image name in the Xaml with the added suffix '''_b64''' (naming convention only).
At design time, save the images in the workspace.  The APL variable name of any image must be the original name of the image name in the XAML with the added suffix '''_b64''' (naming convention only).
<source lang=apl>
<source lang=apl>
       Paste_b64 ← FileToBase64String 'D:\Paste.png'
       Paste_b64 ← FileToBase64String 'D:\Paste.png'
Line 299: Line 298:
       win.Cut_b64.Source  ← ImageFromBase64String Cut_b64
       win.Cut_b64.Source  ← ImageFromBase64String Cut_b64
</source>
</source>
If there are many images in the Xaml, the following lines of code can automate the process at run time:
If there are many images in the XAML, the following lines of code can automate the process at run time:
<source lang=apl>
<source lang=apl>
     ⍝ Get the names of all the 'Image' object that has been fixed in the root object
     ⍝ Get the names of all the 'Image' object that has been fixed in the root object
Line 316: Line 315:
     win.Cursor ← CursorFromBase64String HandCursor_b64
     win.Cursor ← CursorFromBase64String HandCursor_b64
</source>
</source>
=== Routed Events ===
=== Routed Events ===
In WPF it is possible to set a single function that will receive all the Click events on the window (in this example it is <source lang=apl inline>__EventHandler</source>) by doing:
In WPF it is possible to set a single function that will receive all the Click events on the window (in this example it is <source lang=apl inline>__EventHandler</source>) by doing:
Line 397: Line 397:
}}
}}


{{Collapse|The function <source lang=apl inline>ScrubAndFix</source> will remove all the events from the Xaml by looping on a <source lang=apl inline>XamlXmlReader</source> object. It is slower than <source lang=apl inline>FixXaml</source> but the events don't need to have a specific prefix.  Perfect for experimenting with the Xaml taken directly from the Web.  All the named objects are attached to the root object|
{{Collapse|The function <source lang=apl inline>ScrubAndFix</source> will remove all the events from the XAML by looping on a <source lang=apl inline>XamlXmlReader</source> object. It is slower than <source lang=apl inline>FixXaml</source> but the events don't need to have a specific prefix.  Perfect for experimenting with the XAML taken directly from the Web.  All the named objects are attached to the root object|
<source lang=apl>
<source lang=apl>
     ∇ rootObj←ScrubAndFix xamlString;err;names;nodeNumber;reader;stringReader;writer;⎕USING
     ∇ rootObj←ScrubAndFix xamlString;err;names;nodeNumber;reader;stringReader;writer;⎕USING
     ⍝ Function to remove the Class and Events elements of Xaml and fix the resulting Xaml.
     ⍝ Function to remove the Class and Events elements of XAML and fix the resulting XAML.
     ⍝ Each named element(s) object will be attached to rootObject.
     ⍝ Each named element(s) object will be attached to rootObject.
     ⍝ Root element name is removed in all cases. Use the rootObj directly to access its properties/methods.
     ⍝ Root element name is removed in all cases. Use the rootObj directly to access its properties/methods.
     ⍝ This function is most usefull when experimenting with Xaml taken directly from the Web but is slower than FixXaml.
     ⍝ This function is most usefull when experimenting with XAML taken directly from the Web but is slower than FixXaml.
     ⍝ Inspired from the code of XAMLPAD2009.
     ⍝ Inspired from the code of XAMLPAD2009.
     ⍝
     ⍝
Line 412: Line 412:
       :Trap 0
       :Trap 0


           ⎕USING,←'System.IO' 'System.Windows.Markup,WPF/PresentationFramework.dll' 'System.Xaml,System.Xaml.dll'
           ⎕USING,←'System.IO' 'System.Windows.Markup,WPF/PresentationFramework.dll' 'System.XAML,System.XAML.dll'
           stringReader←⎕NEW StringReader(⊂xamlString)
           stringReader←⎕NEW StringReader(⊂xamlString)
           reader←⎕NEW XamlXmlReader(stringReader XamlReader.GetWpfSchemaContext)
           reader←⎕NEW XamlXmlReader(stringReader XamlReader.GetWpfSchemaContext)
Line 497: Line 497:
}}
}}


The User Command [[wpfXamlEditor||]] is designed to edit the Xaml saved in the workspace and on disk.
The User Command [[wpfXamlEditor||]] is designed to edit the XAML saved in the workspace and on disk.


=== Inserting WPF Controls into Traditional Dyalog Windows ===
=== Inserting WPF Controls into Traditional Dyalog Windows ===
You can insert a WPF control into an already existing application developed with <source lang=apl inline>⎕WC</source> by using an [[https://msdn.microsoft.com/en-us/library/system.windows.forms.integration.elementhost(v=vs.110).aspx|ElementHost]] and a Dyalog's <source lang=apl inline>NetControl</source>. Here is an example of how to insert a WPF Button:
You can insert a WPF control into an already existing application developed with <source lang=apl inline>⎕WC</source> by using an [https://msdn.microsoft.com/en-us/library/system.windows.forms.integration.elementhost(v=vs.110).aspx ElementHost] and a Dyalog's <source lang=apl inline>NetControl</source>. Here is an example of how to insert a WPF Button:
<source lang=apl>
<source lang=apl>
       ⎕USING∪←⊂'System.Windows.Forms.Integration,WPF/WindowsFormsIntegration.dll'  ⍝ Location of 'ElementHost'
       ⎕USING∪←⊂'System.Windows.Forms.Integration,WPF/WindowsFormsIntegration.dll'  ⍝ Location of 'ElementHost'
Line 613: Line 613:
The author has taken the prefix '⍝∇' instead of '⍝' because in production code you will probably want to erase all the comments in your runtime WS because they are useless and it is helping to obfuscate the code while taking less space.
The author has taken the prefix '⍝∇' instead of '⍝' because in production code you will probably want to erase all the comments in your runtime WS because they are useless and it is helping to obfuscate the code while taking less space.
==== With a DispatcherTimer ====
==== With a DispatcherTimer ====
If you have a repetitive task to be executed on the UI thread then you can use a [[https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer(v=vs.110).aspx|DispatcherTimer]] like this:
If you have a repetitive task to be executed on the UI thread then you can use a [https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer(v=vs.110).aspx DispatcherTimer] like this:
<source lang=apl>
<source lang=apl>
     ⎕USING∪←'System.Windows,WPF/WindowsBase.dll' 'System,mscorlib.dll'
     ⎕USING∪←'System.Windows,WPF/WindowsBase.dll' 'System,mscorlib.dll'
Line 623: Line 623:
Note that since the <source lang=apl inline>DispatcherTimer</source> is executed on the UI thread you cannot have a long callback because it will freeze the UI during its execution.
Note that since the <source lang=apl inline>DispatcherTimer</source> is executed on the UI thread you cannot have a long callback because it will freeze the UI during its execution.
==== With a BackgroundWorker ====
==== With a BackgroundWorker ====
The .NET framework provides a simple way to get started in threading with the [[https://msdn.microsoft.com/fr-fr/library/cc221403(v=vs.95).aspx|BackgroundWorker]] component. This wraps much of the complexity and makes spawning a background thread relatively safe. It offers several features which include spawning a background thread, the ability to cancel the background process before it has completed, and the chance to report the progress back to your UI. The <source lang=apl inline>BackgroundWorker</source> is an excellent tool when you want multithreading in your application with access to the UI thread, mainly because it's so easy to use.
The .NET framework provides a simple way to get started in threading with the [https://msdn.microsoft.com/fr-fr/library/cc221403(v=vs.95).aspx BackgroundWorker] component. This wraps much of the complexity and makes spawning a background thread relatively safe. It offers several features which include spawning a background thread, the ability to cancel the background process before it has completed, and the chance to report the progress back to your UI. The <source lang=apl inline>BackgroundWorker</source> is an excellent tool when you want multithreading in your application with access to the UI thread, mainly because it's so easy to use.


An example is included in this namespace. It is inspired by this [[http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/|article]].  You start the example by doing:
An example is included in this namespace. It is inspired by [http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/ this article].  You start the example by doing:
<source lang=apl>
<source lang=apl>
       BackgroundWorkerSample& 1000
       BackgroundWorkerSample& 1000
Line 633: Line 633:
=== How to install wpfXamlDemo in your workspace ===
=== How to install wpfXamlDemo in your workspace ===


1. Download [[attachment:wpfXamlDemo.v1.6.txt]]
# Download [[attachment:wpfXamlDemo.v1.6.txt]]
1. Do a Select all (Ctrl+A) and a copy (Ctrl+C).
# Do a Select all (Ctrl+A) and a copy (Ctrl+C).
1. In your workspace execute <source lang=apl inline>)ed ⍟ wpfXamlDemo </source>
# In your workspace execute <source lang=apl inline>)ed ⍟ wpfXamlDemo </source>
1. Paste (Ctrl+V) the text into the Dyalog editor
# Paste (Ctrl+V) the text into the Dyalog editor
1. Press Escape and ')save' your workspace
# Press Escape and ')save' your workspace


Optionally to de-script the namespace you can do:
Optionally to de-script the namespace you can do:
Line 643: Line 643:
     #.wpfXamlDemo←{('n' ⎕NS ⍵)⊢n←⎕NS ''}#.wpfXamlDemo
     #.wpfXamlDemo←{('n' ⎕NS ⍵)⊢n←⎕NS ''}#.wpfXamlDemo
</source>
</source>
== Version Information ==
Original author: [[User:PierreGilbert|Pierre Gilbert]]
----
<references />
[[Category:Tutorials]][[Category:Dyalog APL examples]][[Category:.NET]]
[[Category:Tutorials]][[Category:Dyalog APL examples]][[Category:.NET]]

Navigation menu