Working with Symphony Framework V1.3
Page 1
Working with Symphony Framework
Working with Symphony Framework V1.3
Page 2
Rev No
Date Name Details
1.0 18/11/16 GI Introduction, description of setup project and some initial theory on objects, classes and MVVM
1.1 22/11/16 GI Product and supplier view projects and printing
1.2 27/12/16 GI Supplier, Product and Product Group Maintenance
Working with Symphony Framework V1.3
Page 3
Contents Introduction .................................................................................................................................................. 6
About this Document ................................................................................................................................ 6
My Background ......................................................................................................................................... 6
Why Symphony Framework ...................................................................................................................... 7
Symphony Framework Example project ....................................................................................................... 8
Set up Solution and initial projects ............................................................................................................. 11
Files and Data Objects ............................................................................................................................. 12
Other actions with file objects. ............................................................................................................... 15
Referencing Methods and Properties ..................................................................................................... 16
A Little of the Theory .................................................................................................................................. 17
Classes ..................................................................................................................................................... 17
Symphony Framework Application Structure ......................................................................................... 19
First Steps in XAML – Product and Supplier Viewer ................................................................................... 22
Product Viewer ....................................................................................................................................... 22
Supplier Viewer ....................................................................................................................................... 24
XAML window ..................................................................................................................................... 25
SupplierViewer.XAML.DBL .................................................................................................................. 29
APP.XAML ............................................................................................................................................ 30
View Model ......................................................................................................................................... 30
SupplierViewViewModel.dbc .............................................................................................................. 31
Using Symphony Harmony in a Class .......................................................................................................... 37
Printing and Other Utilities ......................................................................................................................... 39
SFEUtilities.SFEPrinting Class .................................................................................................................. 40
Sample Output ........................................................................................................................................ 42
Other Utility Classes ................................................................................................................................ 44
SupplierReport Project ................................................................................................................................ 45
SupplierReportOptions.xaml ................................................................................................................... 45
SupplierReport.xaml.dbl ......................................................................................................................... 48
APP.XAML ................................................................................................................................................ 49
SupplierReportViewModel.dbc ............................................................................................................... 49
SFEBusinessLogic.SupplierReport Class .................................................................................................. 53
Working with Symphony Framework V1.3
Page 4
File Objects, Symphony Harmony and Record Locking .............................................................................. 57
Record Locking ........................................................................................................................................ 57
File Objects .............................................................................................................................................. 57
Symphony Harmony ................................................................................................................................ 57
Design Considerations ............................................................................................................................ 58
New Applications alongside Older Applications ..................................................................................... 58
SFEAppShell – Menu and File Maintenance Programs ............................................................................... 59
Visual States ............................................................................................................................................ 60
SFEAppShell Project ................................................................................................................................ 60
Project Structure ..................................................................................................................................... 61
SFEAppShell ............................................................................................................................................. 61
AppStyling.XAML ..................................................................................................................................... 62
MainWindow1.XAML .............................................................................................................................. 64
Moving to a visual state for the file maintenance program ................................................................... 67
Defining how the user controls are loaded ............................................................................................ 67
Menu Buttons ......................................................................................................................................... 69
Animations between visual states .......................................................................................................... 70
Supplier File Maintenance .......................................................................................................................... 71
Maintenance.XAML ................................................................................................................................. 72
Creating Styles from Repository ............................................................................................................. 75
OverviewList.XAML ................................................................................................................................. 76
FullInput.xaml ......................................................................................................................................... 78
SupplierMaintenanceViewModel ........................................................................................................... 80
Filtering the list ....................................................................................................................................... 82
Changes to View .................................................................................................................................. 82
Changes to ViewModel ....................................................................................................................... 83
Adding Print Options ............................................................................................................................... 86
Changes to OverviewList.xaml ............................................................................................................ 86
Changes to ViewModel ....................................................................................................................... 87
Changes to Model ............................................................................................................................... 88
Product File Maintenance ........................................................................................................................... 89
Adding Images ......................................................................................................................................... 91
Working with Symphony Framework V1.3
Page 5
Changes to View .................................................................................................................................. 91
Changes to View Model ...................................................................................................................... 93
Changes to Model ............................................................................................................................... 93
Changes to Report............................................................................................................................... 96
Displaying descriptions for coded fields ................................................................................................. 97
Changes to View .................................................................................................................................. 97
Changes to View Model ...................................................................................................................... 97
Changes to Model ............................................................................................................................... 98
Adding Pop-up Selection Lists ............................................................................................................... 102
Changes to Repository ...................................................................................................................... 102
SFE_UI\Common\SupplierCodeLookup.xaml ................................................................................... 104
SFE_UI\ViewModel\SupplierCodeLookupViewModel.dbc ............................................................... 105
Changes to Maintenance.xaml ......................................................................................................... 106
Changes to View ................................................................................................................................ 107
Changes to View Model .................................................................................................................... 107
Changes to Model ............................................................................................................................. 109
To do list .................................................................................................................................................... 110
Questions .................................................................................................................................................. 111
Working with Symphony Framework V1.3
Page 6
Introduction
About this Document
This document aims to do 2 things
1. Tell the story of my journey from toolkit and traditional synergy to Symphony framework and
synergy.net development
2. Act as a reference manual for other developers making the same journey.
It is a mix of narrative, theory and instruction.
It does not aim to explain every possible thing about OO design and development, .net, visual studio,
XAML etc, but hopefully it does cover enough of each of these points to allow you to use them to create
robust, production class applications which are easily supported.
This document is an ongoing work in progress which may never be complete. As new things are
learned or better explanations emerge, they will be added.
And as others get involved in the Community Project, their experiences will help shape this document.
My Background
My background was in traditional and toolkit synergy development. I was responsible for a toolkit based
ERP product, and we tried to stay abreast of new technology, and embed it as and when we could.
I had not done any significant coding for 10 years, but would still have reviewed and debugged code.
Even then, most of the low level coding relating to creating, opening, reading and updating files and
records, printing, displaying messages, compiling and linking etc, were all wrapped up in our in-house
utility subroutines and batch files, so my actual pure synergy knowledge was also limited when I moved
to different environments.
My only exposure to OO and .net development was via the Synergy conference sessions and workshops,
which gave me a high level (possibly flawed) idea of what it was all about, but I had no experience of
actually using it.
We had engaged Richard to help with prototyping a few small Symphony Framework projects, but they
were followed through by other developers, and I did not see any of the code involved.
When I set up my own company 18 months ago, my first engagement was taking over a PSG re-
engineering project, which had moved a traditional synergy DBL project from VMS to windows, running
under synergy.net. It used low level windows and programs had been converted to subroutines. The
Working with Symphony Framework V1.3
Page 7
printing and a few other areas had been written using classes. The client wanted me to make extensive
changes to printing to support print API printing alongside embedded escape sequence printing to dot
matrix printers which couldn’t be added as network printers, so I had to get to grips with how methods
and properties are defined and used in classes, and learning how to code, debug and deploy in a visual
studio environment.
Why Symphony Framework
I knew that Symphony Framework solutions using XAML for the UI were a quantum leap forward from
toolkit based solutions, and there was no point trying to set up a business only offering toolkit and
traditional based solutions. I wanted to offer services which allowed synergy clients to advance their
applications, and indeed, be able to offer modern solutions to companies not using synergy.
Hence I decided that I wanted my business to offer Symphony Framework based solutions and so that
meant learning SF (Symphony Framework) and synergy.net to the point of being able to deliver robust
applications with it, and being able to train developers from a similar background to my own.
As I have immersed myself in learning, a lot of what I have done has based on trust with little
understanding behind it initially, but gradually the murk cleared and little pieces became clear, and then
joined with other pieces to allow the overall picture to build up.
I still have gaps and don’t always understand why I have to do certain things, but I am still learning.
Also, as I master an area, it then sparks off other questions.
This document records my journey and documents the key points I have learned along the way.
Working with Symphony Framework V1.3
Page 8
Symphony Framework Example project
I decided the best way to learn this was to actually try to get some simple examples working. Just
walking through working code of a completed application would not teach me what I needed to know.
It wasn’t just syntax I needed to learn, but I needed to understand how all the bits of an application
come together.
So Richard and I came up with the idea of putting together a simple application which managed
suppliers, products, product types and purchase orders. The design was kept as simple as possible so
that this could become a template on which more complex, real world applications could be put
together.
This has developed in a number of phases, and each phase added new layers to my knowledge and
understanding.
The application has 3 master files :
Product
Product_group
Working with Symphony Framework V1.3
Page 9
Supplier
It has a relative parameter file, which is used to assign the next automatic purchase order number.
Parameter
2 files are used for purchase orders :
Order_header
Working with Symphony Framework V1.3
Page 10
Order_line
The repository defines the files as being held in SFEDATA:, which is defined as a common property in the
VS solution to be :
This allows anyone to install the solution in any folder and create the files without ever having to hard
code directory names or paths.
Working with Symphony Framework V1.3
Page 11
Set up Solution and initial projects
The solution “SymphonyExampleSolution” was set up as follows :
Solution Items folder contains repository and SF templates used by Orchestrator/codegen Templates are downloaded from the Symphony Framework web site
AppData_server class library project
Contains all the file and data objects created by Orchestrator. This has Symphony Framework and Symphony Harmony installed as Nuget packages The following items were created for each file :
- Data class - File IO class - Table mapper
When we started using styles then additional items had to be generated per file. More on this later
SystemSetup console app project
Contains program to create and populate data files This project needs a reference to the AddData_server project to pick up all the codegen’d file and data classes.
The solution includes a number of other projects, and these will be described in separate chapters as we
come to them.
Working with Symphony Framework V1.3
Page 12
Files and Data Objects
The starting point was to create the actual files and populate them with initial data.
Step 1. Set up repository, including file type, file and key information.
Step2. Use Orchestrator to codegen File and Data objects
The following entries were created for each file. Note that other entries per file will be required in later
chapters as we start working with styles, selection lists and caching.
Working with Symphony Framework V1.3
Page 13
In each case the repository needs to be defined on the second tab.
This will create the code generated classes in the AppData_server folder. These files need to be added
to the AppData_server project. These will already be added , but if you add any additional files and
classes they will need to be added.
(to install orchestrator and codegen ………..)
Working with Symphony Framework V1.3
Page 14
SystemSetup project
I initially wrote this to include records from the repository, used ISAMC to create the file, and then
opened the file on a channel with an open statement and did STORES to the channel to add the records.
This was then changed to use file objects, data objects and structures.
This meant the program does not open or close the file, does not use records or channels, and does not
know where the file is or what it is called.
This was a bit of a culture shock, but was very useful later on.
Take the supplier file as an example.
I created a file object to talk to the file, and a structure to allow me to populate the fields with values.
The structure is then converted to a product object, and passed to the file IO class to be added to the
file.
data supplierIO = new Supplier_FileIO(FileOpenMode.UpdateIndexed)
(this is an object to access the supplier file in update mode)
data supplier ,STRSupplier
(this is a structure defining the fields in the supplier record)
The definitions come from the codegen’d classes in AppData_server.
These are picked up via import statements :
;;imports required to use data objects and file IO classes. import AppData import Symphony.Conductor.DataIO
And by setting a reference from the SystemStartup project to the AppData_server project
I found this concept of defining something to be based on something else very strange. I thought data
statements were A, D or I. However, the data statements allow objects, structures and various
framework elements to be created, based on items defined elsewhere. I found “go to definition” useful
in Visual Studio, and setting debug breakpoints to see what these structures, objects, properties etc
actually contained.
Working with Symphony Framework V1.3
Page 15
To add a record to the file I do the following :
To
add this to the file, I do :
This creates a new SupplierData object from the structure, then passes this object to the CreateRecord
method of the supplierIO class, and returns a status which can be compared against a success property
of FileAccessResults
When I am finished, I close the file with :
supplierIO.CloseChannel()
Other actions with file objects.
The equivalent of opening the product file, reading the contents and displaying to screen using file
objects would be :
You can see a fairly common structure here, try to read first record, if successful, perform a while loop,
picking up all records on file sequentially by primary key.
Working with Symphony Framework V1.3
Page 16
Every operation you would normally carry out with read, reads, write and store commands are provided
by IO methods, but the main thing here is to get used to having your data in an object, and using an IO
class to talk to the file.
SystemSetup contains a number of examples of reading and updating files via file and data objects.
Note – to run SystemSetup you need to make it the startup project in VS then run it.
Referencing Methods and Properties
The full reference to a method is NameSpace.ClassName.MethodName(), and similar for properties –
NameSpace.ClassName.PropertyName
If the class is defined in a different project, then your project needs to add reference to that project in
VS.
If you import the namespace which contains the class, then you can omit the namespace.
Hence the SetupSystem project has a reference to the AppData_server project, and imports the
AppData namespace, and so can refer to the Supplier_Data class, without having to reference it as
AppData.Supplier_Data
(Check this is correct)
Working with Symphony Framework V1.3
Page 17
A Little of the Theory
Classes
Symphony Framework is based on Classes
You have probably heard all of this before, but hopefully the hands on approach will give a better
understanding of it.
Classes only expose properties and methods.
You call Methods and get or set properties.
Although you can pass in/out arguments to methods, generally you pass read only parameters to a
method. A method may or may not return a value. The method definition defines the return type, or
VOID. The return type could be an object or framework element, or a simple data flag or field.
The class may also contain a number of private properties and methods, which it uses for its own
purposes, but which are not exposed to other methods. So we have public methods and properties, and
private methods and properties.
You will find that a class can be an extension of a base class. For example, the SupplierIO class is an
extension of a base FileIO class.
So the extended class is everything in the base class, plus any methods or properties you add to it.
You can also override methods in the base class with your own version of it. I have used this in later
chapters to use my own version of a load method to only load a filtered set of records instead of loading
all records, but we will come to that later.
If a class is declared as static, you can call methods and get and set properties of the class without
having to instantiate it as an object in your code. This is useful for utility classes covering printing, PDF
creation, sending emails etc.
I have used the SFEPrinting class in this way. Methods in static classes can be called, for example to
open the printer, add a field to be printed, close the printer etc. The method has its own properties
such as printer handle, pages printed, position on current page, number of lines left on current page etc,
and these can be exposed as public properties for your method to use. My print methods use the
number of lines left on a page property to decide if it should take a new page.
Otherwise classes are instantiated as objects within your code, and you could have multiple instances of
the same class as different objects within your code. A typical example would be a supplier or a
product class being instantiated as an object in your code.
With the Supplier_Data class in the previous example, you create an instance of the class as an object in
your code, and then you reference the properties and methods of that class via its object reference.
Working with Symphony Framework V1.3
Page 18
That may sound a little weird at this stage, but it will become clearer, and you do need to understand it.
It is best to stop thinking about records, functions, subroutines, commons etc, and to stop trying to map
everything back to what it was in the olden days. This requires a new approach and a new way of
thinking, and it should click into place as you start using it.
Working with Symphony Framework V1.3
Page 19
Symphony Framework Application Structure
Symphony Framework is based on an MVVM design pattern, ie Model, View, View-Model.
Unlike traditional programs which will open the screen, display things on it and ask for input, these
applications start with a XAML screen definition. The framework loads, displays and processes this UI
and nothing else.
You could write XAML which displayed your name, showed a picture of you, allowed you to enter your
dog’s name, favourite treat and most recent walk, selecting the walk by clicking on pictures of the park,
the beach or the lake. But nothing would be updated or stored, despite the stunning UI.
So the framework needs to link the UI to the “model”, where the “model” is all the code to read and
update files, and all the business logic to process transactions and produce reports. The link between
the UI (the “view”) and the “model” is a thin class called a “view-model”.
The view-model is a class which inherits most of its functionality from base classes defined in the
framework or other projects in the solution. Thew View Model would typically relate to a specific record
or a collection of records, plus any additional fields you want to add. In this application, the product
maintenance screen shows the supplier name and product group description, which are not held on the
product file. These are added as an extension to the Product_data class, which you will see later.
The UI can only talk to the view-model, and it can only do so by “binding” what is on screen to
properties exposed by the view model.
The UI can be notified that the contents of a field have been changed by your code by the viewmodel,
and the UI can call the set method of a property if data is entered in the UI.
Similarly, button clicks are bound to properties to allow the desired action to be performed – running a
report, for example.
Nothing else happens between the UI and the viewmodel.
The model layer contains all your data and file IO classes, utility classes for printing, creating PDFs,
sending emails etc, and as much business logic as you can. Everything in the model needs to be defined
as a class.
The view model should be kept as small and thin as possible. Because it is just a class, it would be
possible to write a load of business logic methods within it which updated files etc, but that would be
just wrong. If you are going to do this type of development, you need to do it properly ☺
The UI is written in XAML, with a small piece of DBL code behind it which links the XAML to the view
model.
The viewmodel is written in Synergy.net.
Working with Symphony Framework V1.3
Page 20
The code in the model can be written in any .net language. In this application, all of our code will be
written in synergy.net, but the SynPDF project is a mix of synergy.net code and DLLs written in C#
(confirm)
Working with Symphony Framework V1.3
Page 21
ViewModel
Much of this is inherited from base classes. This defines local variables, say for
selection criteria. It can carry out validation and executes logic linked to button
commands defined the the XAML (view).
Complex commands, eg, print, email, post etc, will make calls into the model to run
methods define there.
There is no UI or file IO here at all
her
View
This is defined in XAML and defines all the UI, and nothing else
It does not update anything, and does not communicate with the Model.
Fields displayed by XAML need to be bound to a property (normally a field) which
is visible to the ViewModel
Button commands also need to be bound to definitions defined in the View
Model.
Relies on the ViewModel to tell it that a field has changed and needs to be
redisplayed
Ne
Model
This contains your data classes, File IO classes, and methods equivalent to print
programs, posting programs, functions and subroutine.
All file reads and writes are defined here
There is no UI here at all.
Working with Symphony Framework V1.3
Page 22
First Steps in XAML – Product and Supplier Viewer
By this stage I was keen to get into some UI. My memory of XAML code from conference workshops
was that it was verbose and the syntax was very difficult. I hoped there would be a drag and drop tool
to write it all for me, with checkboxes for colours and other settings.
However, once I started using it I realized it was better to write the XAML code directly, and use the
intellisense to list available options. One key advantage of XAML is that it is readable, and the more you
work with it, the easier it is to understand.
The screens in this application are built around grids and data grids, which is very common in this type of
development.
Instead of referring to screens by row and column, you divide the screen into a grid, or multiple grids.
Each cell can be defined with an absolute size, or a relative size, such as “as big as it needs to be” , and
“whatever space is left”. This means that as you change the size and shape of the application window,
the screen layout adapts to fit the new screen size.
The other key concept is the data grid, which is basically a list. The list can contain data fields, images,
buttons, and you can have rows which expand to show additional lines of information. The data grids fit
within rows or cells of the overall screen grid, so they too will adapt to fit whatever size screen you have.
Product Viewer
To get me started, Richard wrote a simple “Product Viewer” project. I have not changed any of that
code. You can run it by setting this to be startup Project.
It lists the products in a data grid. It allows a particle product code to be entered, for example, to list all
products with codes beginning with “COK”
It does not use any of the symphony styles. It is just out of the box XAML.
Working with Symphony Framework V1.3
Page 23
The view model exposes a list of Product_data objects, and exposes local “work fields” to accept the key
value and the tick boxes for “full key match” and “Read on group”.
I suggest you walk through the code and use debug to set breakpoints in the view model at various
points to track what happens.
Working with Symphony Framework V1.3
Page 24
Supplier Viewer
I did not want to simply copy the product viewer and replace “product” with “supplier”
I created a new WPF application, called “SupplierViewer” I wanted to add a key word search and show
details of the currently selected row at the bottom of the screen, and I wanted to add some colour.
This project needs to have Symphony framework and Symphony Harmony installed as Nuget packages.
Right click on the project name in VS and select “Manage Nuget Packages. Browse for Symphony
Framework and Symphony Harmony and install them. Symphony Framework will also install 3 other
packages to give :
Working with Symphony Framework V1.3
Page 25
Creating the project created a MainWindow.XAML” file, with a “MainWindow.XAML.dbl” file behind it.
I renamed the window to “SupplierViewWindow1.xaml, as I was pretty sure I didn’t want an application
with 100 screens all called “MainWindow.XAML”
XAML window
The first thing I had to change was the top block of the program :
I needed the ‘Loaded=Window_Loaded”’ to get anything to work at all.
X:Class defines my namespace and window name
Working with Symphony Framework V1.3
Page 26
Because I am not using styles, which would convert the A and D fields defined by the repository into .net
field types, I had to include the following to access the converters used to display the fields
As you can see, these converters are part of Symphony Conductor
Next I divided by screen into 4 grid rows :
Row 0 - search criteria
Row 1 - search button
Row 2 – the data grid
Row 3 – the expanded window to show the currently selected window
This means, set rows 0, 1 and 3 as big as they need to be, and give row 2 whatever space is left
I defined Row 0 as follows :
The key thing to note here is that the text fields requested on screen are bound to public properties
defined within the viewmodel, ie KeyValue and KeyWord.
Working with Symphony Framework V1.3
Page 27
Row 1 was defined as below. This is similar to row 0, except the fields are checkboxes instead of
textboxes, and we have a Button, which is bound to a “SearchCommand” property exposed by the
ViewModel.
Row 2 contains the data grid
Things to note here :
a) The contents of the data grid is bound to a list of supplier objects called “SupplierList”
b) Each data grid column defines a column heading and is bound to a property (ie, field) within the
supplier object.
c) I had to add SelectedItem="{Binding Path=SelectedSupplier}" so I could link the fields in the bottom section of the screen to the selected item. SelectedSupplier is a property defined in the ViewModel, which contains the supplier object corresponding with the current item in the list of supplier objects.
d) The column widths are fixed, but they could be set to auto or *
e) The fields are not displayed as .net field types and so cannot be sorted (see next section)
Working with Symphony Framework V1.3
Page 28
Row 3 – expanded field details
First of all I defined a grid within this grid cell/row as follows :
Column 0 is used to display the field prompts or labels
Column 1 is used to display the field contents
I have given the XAML to display supplier code below. All fields are displayed in a similar manner. You
can see the full code in the VS projec
Q – note the wavy blue line under the TextBox Text line. This is highlighted as a potential error, yet
works fine. Why is this ? Is it normal ?
You can see the label is just a text block. The data field is bound to a property of the SelectedSupplier,
which was defined with the DataGrid. You will also see a converter is required to convert the synergy
field type to a .net field type.
Working with Symphony Framework V1.3
Page 29
SupplierViewer.XAML.DBL
VS creates a DBL file behind the XAML file when it creates a project. This defines the name of the
namespace and links the XAML to the viewmodel.
Note that the specification of “Window_Loaded” in the XAML window is needed to call the
Window_Loaded method in the DBL file.
Working with Symphony Framework V1.3
Page 30
Points to note :
a) The name space is the project name
b) The class name is the XAML window name
c) The data context is the name of the view model
APP.XAML
When the project is created as a WPF application, VS creates a file called APP.XAML, as below. This
defines the name of the class, and the name of the XAML file to run when the project is started.
I also defined various properties for text boxes and stack panels here, which apply as defaults across the
project.
View Model
In this simple example, the view model does not need to call any methods in the model, apart from the
File and Data classes which were code generated from the repository.
The coding contains 2 alternative methods of reading the data from the Supplier file, controlled by an
IFDEF. The code is currently running using Symphony Harmony, but the same result can also be
achieved using File objects to read the file. Symphony Harmony is more efficient, as it returns only the
records and fields requested by the query, whereas the File Objects will return every field on every
record for you to manually filter, which is less efficient, particularly in an xfserver environment.
However, Symphony Harmony does not yet return the GRFA of the records read via xfserver so if this is
an issue, then File Objects can be used instead.
Working with Symphony Framework V1.3
Page 31
I would recommend using Symphony Harmony wherever possible. It is a much nicer syntax to work
with.
SupplierViewViewModel.dbc
You need to create a class in the SupplierViewer project.
First of all, you need to add extra import statements to the 3 which VS will add for you
Then you need to define the namespace and class
As you can see, this ViewModel extends a BaseViewModel class and so only things specific to this ViewModel need to be defined here.
Working with Symphony Framework V1.3
Page 32
Next we define a constructor, which is a method which gets called when the ViewModel object is created in our application. This loads the list with supplier details, using the LoadAllSuppliers method. This is a private method within the class, which cannot be called by other classes.
LoadAllSuppliers method contains code to load the list using Symphony Harmony. The list is contained
in mSupplierList as an observable collection, and then exposed as a public property as SupplierList
(without the ‘m’). You can see that the data grid is bound to “SupplierList” in the XAML code.
SupplierList and mSupplierList are defined as :
We define a private property for the connector to use with Symphony Harmony:
private mConnector ,@DBConnector
Working with Symphony Framework V1.3
Page 33
The loadAllSuppliers method is as below:
This method populates the list but does not return anything, so is declared with “,void”.
So next we come to the properties (work variables) which control the search. In each case we havea private property, prefixed with an ‘m’, which is used within the class, and a public property declared by the public property property name, property type statement. These should be defined with .net data types, eg string and boolean. The get method of each property simply returns the private property value. The set method sets the private property equal to the value passed, and raises a “property changed” event on that field. The XAML watches for any notifications of properties which clear and so will get and display the latest value of the property if a notification is raised. For example, if a method in the class cleared mKeyWord, nothing would change on the screen. However, if a method in the class cleared KeyWord (ie, the public property) then the set method of the public property would be called, and the property changed notification would be raised, and the field would be cleared on screen
Working with Symphony Framework V1.3
Page 34
That just leaves the search. This can be written to use Symphony Harmony or to use File Objects. I will give the code using Harmony first, and then give the file objects version. The actual code uses an IFDEF to switch between the 2 approaches, but it is easier to follow if I split this down into 2 versions. In both cases you will see that the command is defined as a property of type “GenericCommand” which returns and executes command. The XAML just binds to this property. It does not set up a command to be processed. It has no knowledge of what actions will be taken. The XAML calls the get method of the command property, and the command returned is then executed. The method defines the command to be executed as an in-line lamda. (Explain what a lamda is ?)
Working with Symphony Framework V1.3
Page 35
You should see that the code checks if mKeyValue is populated. If so, it executes a Symphony Harmony query. If not it calls the loadAllSuppliers method instead. The alternative version with file objects is :
Working with Symphony Framework V1.3
Page 36
I suggest you compile and run the code with both options and step though in debug. It is important that you understand the XAML, how it interacts with the ViewModel, and how the ViewModel interacts with the model to get its data. Things get a lot more complicated in later chapters, and it is important you have a clear understanding of this simple example to serve as a reference point.
Working with Symphony Framework V1.3
Page 37
Using Symphony Harmony in a Class
As you can see above, Symphony Harmony allows you to issue a SQL like statement to an isam file and
have a collection of data objects returned.
The steps involved in using it are :
a) Import the following in the class
import Symphony.Harmony
b) Create a private property to act as a connector to the data
private mConnector ,@DBConnector
mConnector = new DBConnector("SYMLOCAL:richard/morris!AppData.TableMapper.MapTableToFile")
c) If you want to include string comparisons in the query, then the following will switch off case sensivity
mConnector.SetCaseSensitivity(false)
d) Create an object to be populated by each object returned by the query
data item ,@DataObjectBase
The example given uses very generic code. This could alsbe be defined as
data supplierObj ,@Supplier_Data ,new Supplier_Data()
e) Create a Data select object which contains the results of the query data dataSearch ,@DataSelect
The example given names this as “typeOfSearch”
Working with Symphony Framework V1.3
Page 38
f) Execute the Symphony Query
dataSearch = DataSelect.RunDataSelect(mConnector, "select * from supplier", new Supplier_Data()).Result
g) Navigate through the result set foreach supplierObj in dataSearch
Check the Symphony Framework web site for a more detailed explanation
http://www.symphonyframework.net
Working with Symphony Framework V1.3
Page 39
Printing and Other Utilities I wanted the SFE project to include examples of all types of program which would occur in a typical application – file maintenance, transaction entry, enquiries and reports. Separately, Richard had suggested I should get to grips with the Synergy Print API, and I was keen to try the synPDF functionality. My experience of using the print API had been a wrapper (XCALL PRINT) that submitted “PLINE” as a complete line of fixed font text to the printer. I wanted to be able to write reports which used different fonts (including proportional), different font sizes and colours, boxes and shading and images. I decided to write a utility printing class which hid all the complexity of working with pixels etc from the calling method, and allowed the calling method to select either a print API report or a PDF, make the same calls to the printing class and achieve the same results. The issue I had with the synPDF row and column approach was that it assumes the same font size throughout, but I wanted to be able to use different font sizes for headings, and so a straight row and column calculation of print position would not work. So my printing utility keeps track of the pixel position (in print API pixels or in PDF DIP pixels) of the last line printed. The calling method “prints” to a line number and column position and leaves all the calculation of where that is on the page to the print utility class. Boxes and images are printed based on top right row and column, and bottom left row and column, relative to the current line number, based on current font size. The class exposes a “number of lines left on page” property based on current font size and the calling method uses this to decide when to take a new page.
Working with Symphony Framework V1.3
Page 40
SFEUtilities.SFEPrinting Class
This is a static class within the SFEUtilties project and namespace. SFEUtilties is defined as a Class Library, not as a WPF application, and references the synPDF Project. The methods available are :
Method name Parameters Description
PrinterOpen ReportType R / P Landscape t/f Top Margin Bottom Margin Left Margin Right Margin Print Header t/f Print Footer t/f Printer queue/PDF file name
Defines whether report is print API (R) or PDF (P) Creates PDF object or print handle and defines a number of default values Margins are defined in print API pixels and converted to DIP pixels Columns per line is used to work out the number of pixels per column, which is then used to work out the pixel position for each print column passed It prints a fixed header and footer if requested. This is intended to print company name and logo at top of page, and date, page number etc at bottom of page
PrinterClose None Closes the PDF or print meta file and previews contents
SetFont fontName fontSize fontWeight fontColor backColor
Each of these is optional. The fonts currently supported are :
• Consolas (fixed font)
• Cambri
• Calibi
• Arial
• Times New ROman Foreground colours supported are :
• Black
• Red
• Blue
• Green
• Grey Background colours supported are :
• Light grey
• Light blue
Working with Symphony Framework V1.3
Page 41
• Light yellow
• Light green Other fonts and colours can be added easily
PrintField Row Column Text to be printed
Prints text at the specified row and column.
Box topRow topCol bottomRow bottomCol margin fillColour
Prints a line or box Margin specifies a number of pixels to add as a margin around the rows and columns specified
PrintImage imageFileName topRow topCol bottomRow bottomCol
Scales and prints the image file between the row/col coordinates specified
FormFeed None
Takes a new page
SetLandScapeMode None Does not support PDFs yet
SetPortraitMode None
Does not support PDF yet
It has the following properties
ColumnsPerLine Used to work out the number of pixels per column, allowing for left and right margins.
LinesLeft Gives number of lines left to print to end of page absed on current font size, allowing for top and bottom margins, headers and footers
Any projects which need to use the print utility needs to define a reference to the SFEUtilities project and import SFEUtilities.
Note : Some work required to complete this : - Standardise on fill colours between PDFs and print API - Methods for setting landscape or portrait mode mid- print – cater for PDFs
Working with Symphony Framework V1.3
Page 42
- Check functionality for bold and italics – does PDF allow these with same font, or does it need to change to a different font which has these qualities ?
Sample Output SupplierReport as report
SupplierReport as PDF
Working with Symphony Framework V1.3
Page 43
Product Listing as Report (see later chapters)
Product Listing as PDF
Working with Symphony Framework V1.3
Page 44
Other Utility Classes
The plan is to add other utilities to handle tasks such as exporting data grids to Excel, sending emails and
sending texts (SMS messages).
These do not exist yet.
Working with Symphony Framework V1.3
Page 45
SupplierReport Project
The SupplierReport project is a WPF application which accepts report type and range of supplier codes
and contains a button which will request a report.
The view model responds to the button press by calling a static class called SupplierReport in a project
called SFEBusinessLogic. This in turn makes calls to the SFEPrinting class in the SFEUtilities namespace.
In later chapters, we will cover better ways to structure projects, but this example uses 3 projects, the
SupplierReport project, the SFEBusinessLogic project, and the SFEUtilities project.
This chapter will explain how each of these elements are put together.
SupplierReportOptions.xaml
I renamed the MainWindow.xaml file created by VS to SupplierReportOptions.xaml
The class name was changed to SupplierReport.SupplierReportOptions
The ‘Loaded=”Window_Loaded”’ clause was added.
Working with Symphony Framework V1.3
Page 46
Then a grid was defined to :
- Accept starting supplier code on row 0
- Accept ending supplier code on row 1
- Accept report type on row 2
- Leave row 3 blank to space the form out
- Accept buttons to run report and exit
The field prompts are in column 0 and the data fields are in column 1
I tried to make the report type field a selection list. This could have been hand crafted, but the better
option would have been to have defined a repository structure and used styles. However, styles come
in a later chapter.
The “Back to Menu” button is a dummy button which does nothing since this is not called from
anywhere, and so has nowhere to return to.
The ViewModel defines the following public properties, and the XAML binds the fields on screen to
these :
- StartSupp
- EndSupp
- ReportType
- DoReportCommand
Working with Symphony Framework V1.3
Page 47
The following XAML populates the data grid with the prompts, fields and buttons :
Working with Symphony Framework V1.3
Page 48
SupplierReport.xaml.dbl
The DBL code behind the XAML was modified as below to define namespace, class name and viewmodel
name :
Note that the “Window_Loaded” clause at the top of the XAML links to the Window_Loaded method
here which defines the name of the ViewModel.
Working with Symphony Framework V1.3
Page 49
APP.XAML
This is what actually runs the application, and you see it defines the name of the XAML file to run
(StartupUri). This needs to define the class name and the StartupUri.
You will also see that I have defined the foreground colour and font size for text boxes, and the
background colour for stack panels.
SupplierReportViewModel.dbc
This needs to add the following import statements to the 3 which are provided as standard when a class
is created. It needs to import SFEBusinessLogic to allow the Supplier report method defined within it to
be called
Working with Symphony Framework V1.3
Page 50
This view model is linked to a data object in the model, based on the SELECTIONS structure defined in
the repository, however these fields are not used. See suggestion at end of this section re using styles
derived from the repository structure.
We now define the namespace and the class name for the ViewModel, which extends a BaseViewModelClass. You can right click on this in VS and “go to definition” to see where this is defined and what it contains if you are curious. We define a constructor which creates the object used by the ViewModel. The viewmodel needs an object, even though it is not referenced by this particular application. The constructor sets an initial default value for Report Type. It also adds a handler which checks if the data is valid if it is changed by calling dataChanged_event, which sets a property for the command button which says it can only be executed if the range of supplier codes is valid.
What exactly is the above doing - ? Doesn’t validate the range to decide if button is called ???
Working with Symphony Framework V1.3
Page 51
Then create an object from the Selections_Data class.
private mSelections ,@Selections_Data
We now define the properties referenced by the XAML. (Note that the fields in the selections object
could have been used instead of defining new fields).
Working with Symphony Framework V1.3
Page 52
In each case. If the public property is changed, the set method is called, which raises a Property Changed
Event on the field. When the XAML receives this notification it calls the get method for the property,
which returns the private property associated with the public property.
Now for the button command.
The command is set up as a Lamda which sets the range to ALL if both fields are left blank, and sets end
value equal to start value if end value left blank.
It then makes a call to the Print Method of the SupplierReport method in the SFEBusinessLogic
namespace, passing the starting supplier, ending supplier and report type.
Suggestion : Create an alternative version of this application to use styles code generated from a repository structure defining the work fields. Report type should be defined with a selection list of “Report” and “PDF” The Selections structure is defined in the repository to support this
Working with Symphony Framework V1.3
Page 53
SFEBusinessLogic.SupplierReport Class
This class belongs to the model. In later chapters you will see how this would normally be included
within the “supplier” project. This project takes a different approach of holding all the business logic
classes in a separate class library project called SFEBusinessLogic.
This class has no UI. The view accepts the range and report type, passes this to the ViewModel, and the
ViewModel calls this class.
This is quite a simple class which uses the SFEPrinting class within the SFEUtilities project.
The class accepts starting and ending values as parameters, uses Symphony Harmony to select the
records to be printed, and then makes calls to methods within the SFEPrinting class to open the
printer/PDF, print headings, format records etc.
It would also be possible to do this with file objects, but that would mean reading all records across the
network and filtering out the ones not required in the class. Symphony Harmony is like the select class,
and only returns the required records to the class.
The project has references defined to the SFEUtilities and App_Data_server projects
The supplier report class includes the following imports , loading the standard windows imports,
symphony conductor, symphony harmony, plus the 2 projects we need within our solution – AppData
and SFEUtilities.
Working with Symphony Framework V1.3
Page 54
The class declares a namespace for the class, the class name, and the methods within it
Because this is a static class is does not have a constructor method
You can see the 3 parameter values being passed in – starting and ending supplier code, and type of report.
Next we set up the connector for Symphony Harmony.
The second line of code makes all string matching case insensitive, which is
useful when carryout out keyword searching.
The commands to retrieve and process a set of records via Symphony Harmony are as follows :
This returns a list of supplier objects and we can then access the properties (ie, fields) within each
supplier object for printing :
Working with Symphony Framework V1.3
Page 55
In this case we are passing a number of properties to the PrintField method within the SFEPrinting Class,
together with the line number and column position to print the field at.
We defined dataSearch and SuppObj before making the call to Symphony Framework :
Now look at how the methods in the printing class are used alongside Symphony Harmony to extract a
range of suppliers and produce a printed report or PDF :
Working with Symphony Framework V1.3
Page 56
This produces:
Note that “END OF SUPPLIER” is just to show an example of a different sized font, and hence different
line height, in the middle of the report.
Working with Symphony Framework V1.3
Page 57
File Objects, Symphony Harmony and Record Locking
Record Locking
In any synergy application, there are two approaches to record locking – optimistic and pessimistic.
Pessimistic record locking was the default approach in older systems, and could result in applications
freezing for long periods of time, causing considerable operational difficulties. This method read and
locked records while users decided whether or not they wanted to update them. Other users were
made to wait until the first user completed their task before records were released to them. The only
way to mitigate against this is to build in some form of logging which can report which users are locking
which records on which files.
Optimistic record locking aims to leave records unlocked until a user has decided what they want to do
with the record. If they want to update it the application will check if the record was changed by
another user since they called it up to vie wor edit, and if not, will then make the change to the file. This
can be coded within the program to store a copy of the original record to be compared against the
latest copy at time of making the update, but the recommended approach would be to update via GRFA,
where the GRFA is compared at time of update, and removes the need for a lot of hand crafted code.
The drawback with optimistic locking is that you have no guarantee your update will be successful, and
you need to trap and report failures to the user.
The Symphony Framework, File Objects and Symphony Harmony are intended to be used with an
optimistic locking approach. For a file maintenance type program it is straightforward to display a
message “Update failed – please try again”, but if you are updating a summary file in a class within the
model (eg, updating the total quantity ordered for a given product code when a purchase order is
saved), you have to take possible failures into account in your design. Note that the failures should
relate to another user updating the same record rather than record locking.
File Objects
The File IO classes used by this application use “update by GRFA” when updating files.
Symphony Harmony
Symphony Harmony is intended to work more like a database, processing commands to select, update,
insert and delete sets of records. Select and update commands are based on columns rather than rows.
The select does not store the GRFA of the record, and so update by GRFA is not possible. Hence you
cannot select via Symphony Harmony and update via File IO classes. The update command will update
Working with Symphony Framework V1.3
Page 58
the field (ie, column) values specified, for the specified rows (ie, records), regardless of whether oir not
anyone else has updated them in the meantime.
Design Considerations
It is important that your application has a clear design approach to record locking, and how File objects
and/or Symphony Harmony are used.
In this application we are using File Objects with update by GRFA for maintenance programs, and
Symphony Harmony for read only reports and enquiries.
New Applications alongside Older Applications
It is likely that new applications such as this solution will by working alongside existing synergy
applications, and those older applications are likely to use a pessimistic approach to records locking.
File Objects and Symphony Harmony will both fail if they try to update a locked record. File Objects
work with single records and so trapping such failures is more straightforward than a trapping a failure
in a Symphony Harmony command which operates on multiple records, and could fail on any one of
them.
In this application, we will be creating, modifying and deleting purchase orders. We could potentially be
updating the value of orders placed on the supplier record and the number of items orders per product
on the product record.
The existing application may also update the same fields and files as it, say, receives goods against our
purchase orders, and archives the purchase orders when they are invoiced, matched and paid.
There are no right or wrong answers. You need to weigh up the options available and aim for the best
(or least worst) combination of robustness, performance and clean, readable code.
The last thing anyone wants is a cool UI which is unusable in a production environment.
Working with Symphony Framework V1.3
Page 59
SFEAppShell – Menu and File Maintenance Programs
By this stage we have used Orchestrator to generate our file objects, and worked with file objects to
populate, update and display the contents of our files in a WPF, MVVM environment.
We have written our UI in XAML, and used view models to link this to the file objects and business logic
classes of the model to display and print lists of records.
It would be possible to extend what we have done to date to buttons to cover the basic file maintenance
options of add, change, delete and print, and so write simple applications.
However, all of our screens and reports are separate projects, and we have to set these as the startup
project in Visual Studio to run them.
We have also not used any styles, which are a major part of the Symphony Framework.
Nor have we used Visual States or animations, which are a key part of WPF applications
The next section looks at how a number of file maintenance programs can be written and called from a
“menu”. These programs use styles and a template file maintenance program (or, more accurately, a
base file maintenance class), which is then adapted for each file. They use selection boxes, date picker,
tick boxes, popup selection lists, and images and show additional description fields from other files. This
is intended to cover the majority of normal file maintenance functionality.
We will also see how standard methods in the base class can be overridden with custom methods for
searching and filtering.
Working with Symphony Framework V1.3
Page 60
Visual States It is worth a few a few comments on visual states at this point to paint a broad picture. Visual states allow a user to move through different parts of a WPF application. In simple terms, a visual state is a ‘screen’ which can appear on top of any other ‘screen’. In our application the user moves from the menu, say to supplier file maintenance, back to the menu, then into product file Maintenance, where they drill on the Product Group field. Each of the items mentioned is a separate visual state. Each is defined as a user control with its own XAML file and view model. Each visual state has a visual state name, and the application uses commands to navigate to the visual state, and to indicate the visual state is completed or cancelled. The application then reverts back to the previous visual state. Examples of this are included in the SFE_Supplier and SFE_Product projects. Moving to and returning from a visual state is similar to entering and exiting from a new environment in a toolkit application (E_ENTER and E_EXIT)
SFEAppShell Project
The SFEAppShell project displays the menu and manages the visual states for each of the 3 file
maintenance ‘programs’ offered for selection.
Each of the maintenance ‘programs’ are defined as separate class library projects :
SFE_Product
SFE_Supplier
SFE_Group
Two other class library projects are used :
SFE_Base this holds the base classes for the file maintenance template program
SFE_UI this holds styles and other UI elements, including pop-up selection lists
Working with Symphony Framework V1.3
Page 61
Project Structure
Each of the projects in this group is structured with three sub folders :
View XAML screens
ViewModel View Models
Model Classes called by ViewModel
This will be our recommended approach.
SFEAppShell
SFEAppShell is defined as a “”Windows Application”, and references the 5 class libraries listed above. It
does not deal with any of the data files and so does not need a reference to the AppData_Server project.
The menu shows an icon for each file maintenance “program”. This is animated so that it expands as
you hover over each icon, and a 0.5 second delay is built into moving from the menu the maintenance
screen.
Lets start with app.xaml, as below. This defines our XAML window name – MainWindow1.xaml’, which
is the default for a WPF windows application. If we wanted to change the name of the XAML file, we
Working with Symphony Framework V1.3
Page 62
would need to change it here as well. You will also see that it defines a “Resource Dictionary”, which is
where our application colours and font sizes are defined.
AppStyling.XAML
This is located within the SFE_UI project, in the resources folder.
This was originally set up with a specific colour scheme in mind, which used black, white, blue and
orange.
The XAML is defined as a “resource” within VS, which means it is not executed, just referenced as per
the coding above. (confirm?)
It consists of a number of colour definition lines, which are then applied to each element of the user
interface
Working with Symphony Framework V1.3
Page 63
It was originally created with the colours listed, but I changed this to the following scheme :
I simply changed the hex colour codes for the colours defined. It would be better to define the colours
by more generic terms, such as “dark background” “light background” “light foreground”.
A few points to note, which will hopefully be addressed.
1. The date picker always shows black on your selected background, so is hard to read with dark
backgrounds
2. Tick box prompts are always shown in black, which is also hard to read
3. Drop down selection lists are shown with a white background, which means you can’t use white
or very light colours as the foreground colour for data fields.
Working with Symphony Framework V1.3
Page 64
MainWindow1.XAML
This window manages the display of 4 different “windows” as “visual states”.
These are :
Menu buttons
Supplier Maintenance
Product Maintenance
Product Group Maintenance
Each of these is defined as a “user control”, and each has its own XAML file.
These are held as follows :
Menu buttons SFEAppShell\View\MenuSelection.xaml
Supplier Maintenance SFE_Supplier\View\Maintenance.xaml
Product Maintenance SFE_Product\View\Maintenance.xaml
Product Group Maintenance SFE_Group\View\Maintenance.xaml
First of all, it defines :
Consider the following, which is defined for each of the 3 file maintenance projects. Assembly is the
project name, and namespace SFE_Product.View’ is defined within the SFE_Product project.
Working with Symphony Framework V1.3
Page 65
xmlns:sfeuiProduct="clr-namespace:SFE_Product.View;assembly=SFE_Product"
The main window defines the window size, placement and window title.
The main thing this window does is control the various user controls processed within it as “Visual
States”. The syntax of managing visual states is quite verbose, but it is what it is.
Every Visual State is identified by a name, ie “MenuViewState” and “SupplierMaintState” in the
examples below.
Take the following, which disables the three maintenance views, and enables the launcherview, which is
the menu.
This MenuViewState is the default visual state as it is the first visual state defined (Is this correct?)
Note that in the MenuViewState, an item named “launcherView” is enabled and three other items
relating to the 3 file maintenance visual states are disabled. You will see that these do not refer to the
names of the visual states, but to the following items loaded within a grid :
Working with Symphony Framework V1.3
Page 66
The border Name needs to correspond with the entry in the visual state definition as highlighted.
The entry for each visual state loads the user control specified by the XAML file indicated in the relevant
project. Ie. In the highlighted section, the user control specified in the Maintenance.XAML file within
sfeuiSupplier: is loaded. sfeuiSupplier is defined at the top of this MainWindow1.XAML file as :
The visual state for Supplier File Maintenance is defined as follows, disabling the launcherView user
control and enabling the supplierMaintView user control :
Working with Symphony Framework V1.3
Page 67
Moving to a visual state for the file maintenance program
MainWIndow1.xaml defines WHAT happens when we move between visual states, but not HOW we
move between them.
The MenuSelection.XAML user control displays the menu icons and contains the following, which
causes a “Navigate State” to be executed :
Clicking the exit button on the common toolbar exits from the visual state and returns to the
previous visual state :
Defining how the user controls are loaded
MainWIndow1.xaml defines where and how the user controls are loaded in the window, as follows :
<Grid> <Grid.RowDefinitions> <!-- main item --> <RowDefinition Height="*"/> <!-- status bar --> <RowDefinition Height="auto"/> </Grid.RowDefinitions>
The “main item” will be the user control. The status bar at the bottom is used to load a standard
message as below, which is a licensing requirement when using Icons8 icons for free.
Working with Symphony Framework V1.3
Page 68
The XAML then includes an entry for each of the visual states :
The border name must match the name specified in the visual state definition as mentioned previously.
The localUI defines the user control to load, and this was defined at the top of MainWindow1.xaml :
ie, localUI defines the namespace and the “:MenuSelection” defines the name of the class for the user
control to load. The menu Selection user control is declared as in MenuSelection.xaml.
See next section on Menu Buttons
The file maintenance user controls have slightly more defined for them:
This creates 2 rows within the user control. The first row loads a standard toolbar, which allows the user
controls to exit and return back to the menu. The second row loads the user control.
The details of the user controls for the toolbar and the Supplier Maintenance user control are specified
at the start of MainWindow1.xaml
Working with Symphony Framework V1.3
Page 69
Menu Buttons
This displays the icons, which are held in SFEAppShell\Icons as menu buttons. The menu buttons are
bound to “Navigate State”, passing the name of the required maintenance option as SupplierMaintState,
ProductMaintState and GroupMaintState.
The menu button style is applied to each button. This causes the menu button to increase in size when
the mouse hovers over it.
Working with Symphony Framework V1.3
Page 70
Animations between visual states
The Duration setting is the time allowed to move from one visual state to the next, and a variety of
animation effects are available. Try googling “WPF Visual State transition”. Basically, if you can
imagine it, you can probably do it. We have kept thing simple.
Note all XAML is extremely case sensitive, and differences in case or spelling WILL give you problems.
Working with Symphony Framework V1.3
Page 71
Supplier File Maintenance
The SFE_UI project contains a base user control class, which is used by the file maintenance projects for
suppliers, products and product groups. This is held in SFE_EUI\Common\BaseUserControl.dbc.
You should not modify this, just extend it as required.
The file maintenance programs are structured in 3 parts :
1. A list of records held on the file, which can be sorted by any column
2. A window beneath the list which shows the current record highlighted in the list. The key field is
read only unless adding records. Invalid fields have a red background and a validation failure
message will be displayed if you hover the mouse above the field(s) in question.
3. A set of context sensitive buttons covering add, delete, save and cancel. Save and cancel are
only visible when fields in the input window have been edited, and you have tabbed off the field
or clicked on another one. Save is only visible if all fields are valid.
Three XAML windows are used for this screen, and these are defined within SFE_Supplier\View
Working with Symphony Framework V1.3
Page 72
Maintenance.XAML
The DBL file behind maintenance.xaml links this XAML to the SupplierMaintenanceViewModel, held in
SFE_Supplier\ViewModel.
The code in Maintenance .xaml manages visual states within the “program”. The two states are
mainView and ErrorState. These are separate from the visual states managed by MainWIndow1.xaml.
ie, we are using visual states within visual states.
The mainView state loads 2 rows within the user control. The top row shows the data grid as defined in
OverViewList.XAML, and the bottom row shows the data entry window, defined within FullInput.XAML.
ErrorState is a standard user control window defined within SFE_UI\Common\ErrorDialogue.XAML
Let’s step through the XAML code.
This defines where the XAML files are found for common elements (ie, the Error Dialogue) and the
overviewlist and full input window.
Next we define some resource dictionaries to be used within the user control :
I seem to have an issue with the SFE_Supplier prtoject. I can’t add a refernce to it from SFEAppSHel;l,
yet the ap[plication works anyway ? Happened since I changed SEF_Supplier to SFE_Supplier
This defines dictionaries for :
Working with Symphony Framework V1.3
Page 73
Converters - converts between synergy data types and windows data types
AppStyling - general windows stylings – colours and fonts
Supplier_Styles - code generated form repository. Defines styles for each field and field prompt
based on repository entries.
Next we define the visual states :
Working with Symphony Framework V1.3
Page 74
And we define the display details for each visual state :
The two lines which actually load the OverviewList and FullInput windows are highlighted.
Working with Symphony Framework V1.3
Page 75
Creating Styles from Repository
The other two XAML files use styles to display the required fields on the screen, and these styles need to
be code generated using Orchestrator.
For each file/record you wish to use styles for, create the following :
This creates SFE_UI\Resources\Supplier_Style.CodeGen.xaml.
Note that everything is created from the repository, including field prompt. The repository defines
whether a field is numeric, character, date, required, and if applicable, whether it should be treated as a
selection list, radio buttons or tick box.
The code generated files should NEVER be manually edited under any circumstances, as manual changes
will be lost the next time the entries are regenerated.
Working with Symphony Framework V1.3
Page 76
This creates SFE_UI\Resources\Supplier_Content.CodeGen.xaml. This is used to provide drop down
selection lists for styles which require this.
This creates SFE_UI\Content\Supplier_Collection.CodeGen.dbc. Note this is class, and not a XAML file.
All of these code generated items are created in the SFE_UI project so they can be shared across
multiple projects.
OverviewList.XAML
This defines the data grid which allows the user to select records for editing.
The XAML defines a grid with 2 rowes. Row 0 is reserved for the toolbar with the exit button. Row 1 is
used to display the data grid. Ths size of the data grid is defined in maintenance.xaml, as the space
remaining between the full input window at the bottom of the screen, and the menu bar at the top.
This space will change in size if the window is resized.
Working with Symphony Framework V1.3
Page 77
Question – should these columns be bound to styles rather than field names ?
The data grid is bound to a collection of supplier objects, and the selected item is bound to
SelectedCollectionItem.
Working with Symphony Framework V1.3
Page 78
FullInput.xaml
This window handles the display and editing of the selected record from the list displayed by
OverviewList.xaml.
We have our standard stuff at the start of the xaml file :
We then define a grid to display the prompts and fields. Note – display prompts in separate grid cells
than data fields. This makes it a lot easier to line things up. The grid is actually placed within a single
row grid. Q – why was it done this way ?
Working with Symphony Framework V1.3
Page 79
And now we place the fields and prompts on the screen :
As you can see, when using styles, we only need one line for each prompt and one line for each field as
everything else is defined in by the styles. Field placement is by grid row and column number, not by
screen row and column.
Finally we add the buttons. In this case we are using text, but we could easily use icons instead.
The menu button styling will animate each button so that it grows bigger as you hover over it with the
mouse.
Working with Symphony Framework V1.3
Page 80
SupplierMaintenanceViewModel
Everything so far in this chapter has dealt with the XAML view. As mentioned already, the DBL file
behind the maintenance.xaml window links the view to the view model, which is held in
SFE_Supplier\ViewModel\SupplierMaintenanceViewModel.dbc
This extends a base view model defined in the SFE_Base project, called FileMaintenanceViewModel
First the imports and namespace :
Now the class definition and constructor method :
Working with Symphony Framework V1.3
Page 81
This creates a private version of the object we are dealing with, and then defines a constructor which is
called when the viewmodel class is instantiated.
The parent line connects the view model to supplier file objects, and gives the name of the window (ie,
visual state) to display if errors are encountered.
This uses two event handlers to call methods as below. The events are defined in the base
FileMaintViewModel.
Event Method Action
ProgramModeChanged doProgramModeChanged() Enables or disables key fields on screen. This is defined in our view model
IsDataModifiedChanged DoIsDataModified This is defined in the base view model
It then loads the collection with supplier data records, using the LoadDetailList method defined in the
base class.
DoProgramModeChanged enables and disables the key fields in the full input window, as shown.
That is all that is required. Everything else is handled by the base classes.
Working with Symphony Framework V1.3
Page 82
Filtering the list
To filter the list we need to add local fields to the overviewList.xaml file, and write our own override
version of the standard LoadDetailList method.
In this example we are reloading the list when the search button is pressed, but we could also do it by
calling the LoadDetailList method from the set method of the local search criteria fields.
Another approach in LoadDetailList would be to make the records in the list (data objects in the data
collection) visible or invisible according to the search criteria. It depends on what the overhead is in
going back to the data file each time, and whether or not the initial load loaded all records.
(Confirm the above)
Changes to View
OverviewList.xaml was modified to create an extra row in the grid to place the search criteria fields, and
the other elements were all moved down into the next row, ie, row 1 was changed to row 2.
The XAML was changed to display the following :
The line highlighted below was added to add the extra row
This row definition block was added to handle the local variables KeyValue and KeyWord, which are defined within the view model. It also defines a button, which is bound to a search command defined within the view model. Note that this is exactly the same approach as was used in the Supplier Viewer and Product Viewer projects already covered in earlier chapters.
Working with Symphony Framework V1.3
Page 83
Changes to ViewModel
SupplierMaintenanceViewModel was modified to add 2 new properties for KeyValue and KeyWord
The search command was added as a property :
Working with Symphony Framework V1.3
Page 84
Note that the lamda (ie, command) calls a private method called LoadBaseItemCollection, which is
defined within the view model as an override method, overriding the standard method defined in the
base class which loads the collection with all records on file. This is so that the same code can be called
when loading the list initially with no filters, and when reloading it with filters.
Working with Symphony Framework V1.3
Page 85
This uses File Objects to read the file. Initially Symphony Harmony was used, which loaded the list and
displayed the contents, but the application failed trying to update records as Symphony Harmony does
not return a GRFA, so update by GRFA is not possible.
Working with Symphony Framework V1.3
Page 86
Adding Print Options
Buttons were added to allow the filtered set of records shown in the list to be printed, either previewed
via the synergy Print API, or as a PDF. A version of the Supplier Report class was used for this, with the
print option, KeyValue and KeyWord passed in as parameters. This class is held in the Model folder of
SFE_Supplier.
These print options do not require any further user interface, and hence do not require a new Visual
State. If the print options required selection of printer, number of copies, page range etc, then a new
Visual State would be required.
Changes to OverviewList.xaml
The following was added to the definition for row :
The StaticResource MenuButtonStyle means the image grows in size when the mouse is hovered over it.
This displays as :
Working with Symphony Framework V1.3
Page 87
Changes to ViewModel
Command properties were added to SupplierMaintenanceViewModel for ‘print’ and ‘PDF’. These call a
print method defined in the SupplierReport class, held in SFE_Supplier\Model, passing different
parameters.
Working with Symphony Framework V1.3
Page 88
Changes to Model
As mentioned above, the static Print method of the SupplierReport class was based on the
SupplierReport project described in an earlier chapter.
Working with Symphony Framework V1.3
Page 89
Product File Maintenance
Product File Maintenance is based on the same approach as Supplier File Maintenance, including the
filtering, print and PDF options.
It adds some additional functionality as follows :
- Supplier code and product group code
o Display descriptions of codes in the list
o Display descriptions in the full input window
o Display the new description if the code is changed
o Validate the new codes to check they exist on the supplier code and product group files
o Provide pop-up selection lists
- Product Images
o Display product image in the list
o Display product image in the full input window
o Display a “sale” icon/image if the “on promotion” tick box is checked
o Include images in the printed report and PDF
Working with Symphony Framework V1.3
Page 90
The Product Data object in AppData_server was extended to hold additional fields in addition to those
generated from the repository entry. These are :
• name of the product image file
• name of the “sale” icon, which is blank if not on promotion
• supplier name
• Product group description
Working with Symphony Framework V1.3
Page 91
Adding Images
The product images are held as JPG files in the ProductImages folder, where the image name need to be
productcode.jpg. This folder does not need to be part of the VS application. When this is ran as an
application rather than from within VS, the logical SFEImages: should be assigned to the location of the
product images folder.
This folder also contains an image files named sale.jpg which is used to display as a highlight on screen
and product list report.
Changes to View
This ‘worked’ by displaying the image file name on the window, but this generated exceptions each time
the application tried to display a missing file or null file name. A ‘Null Image Converter’ was written to
avoid this problem.
The images appear in the list and on the input window, so both XAML files needed to be changed for
this.
OvervewList.xaml
A reference/link was added at the top of the XAML file to define the null image converter, which is
found in SFE_UI\Converters\NullConverter.dbc, which contains a class called NulImageConverter,
Working with Symphony Framework V1.3
Page 92
The data grid column definitions were defined as follows for the 2 image fields :
FullInput.xaml
Similar changes were made to this. The same reference to the null image converter was added to the
start of the XAML file.
The grid rows and columns were defined to create a cell to display the product image in. The product
description field was defined to span a number of columns as it would not fit within a cell. It would also
be possible to define the display grid in separate sections with different number of columns for different
rows.
Working with Symphony Framework V1.3
Page 93
Q – why am I getting a wavy blue line under this ?
The product image was placed in a grid cell and set to span 6 rows :
Changes to View Model
No changes were needed to the ViewModel. Everything relating to the images was defined at the model
level.
Changes to Model
The code generated Product class in AppData_Server was extended to add 2 new properties for the
product image file name and the product on promotion image file name.
The code generated file was not changed – AppData_Server\Product_Data.CodeGen.dbc
A new class called Product_Data was written which expands the code generated Product_Data class
generated from the repository by Orchestrator. This is defined as a partial class with the same name as
Working with Symphony Framework V1.3
Page 94
the code generated class, so that the properties and methods of this class are added to the code
generated class.
This was also created in AppData_Server as Product_Data.dbc
The constructor defines an event handler for the event ‘SynergyRercordChanged’ – synergychanged()
which are needed to ensure the additional image fields added to the class are populated and updated
correctly. In this case the image file names are set to Null initially and the get method of the public
property then determines the actual name.
Each image has 2 properties, of different types. ProductImage and PromotionImage are of type
ImageSource, and are used in the XAML. ProductImageFile and PromotionImageFile return strings
Working with Symphony Framework V1.3
Page 95
containing the file name of the image, and these are used in the SupplierReport class to print reports
and PDFs.
public property ProductImageFile, string
method get proc
mreturn AppData.DataLogic.GetImageFileName(product_main.str_prod_code, ImageFileType.JPGFileType) endmethod endproperty public property PromotionImageFile, string method get proc
if (product_main.str_promotion == 1) then mreturn AppData.DataLogic.GetImageFileName("sale", ImageFileType.PNGFileType) else mreturn ^null endmethod endproperty
Note that the above properties do not need a private backing field as they never refer to
mPromotionImageFile or mProductImageFile. These call a method in AppData_server\Data_logic class
to return the image file name as a string.
The next 2 properties provide image sources for the XAML code :
Working with Symphony Framework V1.3
Page 96
These properties provide the image file names for the report :
These do not require private backing fields, ie fields with an ‘m’ prefix.
Changes to Report
The ProductReport Class defined in SFE_Product\Model\SupplierReport.dbc includes the following to
print the product image and promotion image :
if (productObj.ProductImageFile != ^null) SFEUtilities.SFEPrinting.PrintImage(productObj.ProductImageFile,lineCount+1,20,lineCount +6,40) if (productObj.PromotionImageFile != ^null) SFEUtilities.SFEPrinting.PrintImage(productObj.PromotionImageFile,lineCount+2,50,lineCount +4,60)
This prints the image file based on top left and bottom right row and column co-ordinates, based on
current position on page and current font size.
Working with Symphony Framework V1.3
Page 97
Displaying descriptions for coded fields
The supplier name and product group description fields were added as additional properties to the
Product_Data class, along with the Product and Promotion image file names.
The challenge with these fields was to make sure the descriptions were displayed correctly on the full
input window and on the OverviewList if the Supplier Code or Product Group Code fields were changed.
Changes to View
Changes to the view are simple. The additional fields are just placed on screen, and all the logic behind
populating and refreshing them is handled by the model.
The styling is controlled by the settings in AppStyling.xaml.
OverviewList.xaml
FullInput.xaml
Note that the foreground coilour needs to be defined as these additional fields do not have code gen’d
styles.
Changes to View Model
No changes are required to the View Model.
Working with Symphony Framework V1.3
Page 98
Changes to Model
The Product_data class was modified as follows :-
- Define public and private properties for supplier name and group name
- Add private methods to find descriptions and populate the fields
- Calling the find methods when the object is created, and when the supplier code or product
group code is changed
This section will give the coding relating to supplier name. The product group description is handled
in exactly the same manner.
Defining the supplier name property
Note that any time the public property ‘SupplierName’ is set by code in the model, a property changed
event is raised which tells the xaml to display the new value.
Populating the supplier name field
The private method findSupplier populates the SupplierName property and returns a success or failure
status, which is used to set validation properties.
Working with Symphony Framework V1.3
Page 99
This uses a cached search routine to populate a temporary data object with a supplier object. This is
coded generated and checks a cache of records already found before using file objects to search the file.
Question : What is the template called for the cache so I can add this to my Orchestrator definitions ?
Calling the findSupplier method in the model
The view model uses event handlers to populate and validate the additional fields whenever the
contents of the synergy record changes. These are defined in the constructor method :
Working with Symphony Framework V1.3
Page 100
Synergychanged()
This is called when the synergy record is populated initially. It calls the findSupplier method to find and
populate the supplier name.
doDataChanged()
This is called each time a field in the view changes. It checks the name of the field which was changed,
and then performs field specific coding to read the new supplier name, and perform validation.
The return result from findSupplier is used to set the validation status and message on the Supplier Code
field. The style on the Supplier Code field causes the xaml to render the supplier code field with a red
background and to display a validation method set in the model when the user hovers the mouse over
the field.
doDataChanged is as follows :
Working with Symphony Framework V1.3
Page 101
Refreshdata()
This is called when the synergy record changes
Is this needed ? If so, what does it do ?
Working with Symphony Framework V1.3
Page 102
Adding Pop-up Selection Lists
Pop up selection lists were created for supplier code and for product group code. These were written in
the SFE_UI project so they could be included in any screen, and not just within Product File
Maintenance.
The approach is to define a xaml window for the selection list, with its own view model, and then handle
that within a separate visual state.
This section will describe how the selection list for the Supplier Code field was handled. The selection
list for Product Group is very similar.
The starting point is the repository, which defines the ‘name’ to be used. The code generated style for
the data class uses this ‘name’ and it is recommend that the various elements required to adhere to a
very strict, case sensitive, naming convention.
In this case, the repository defines the ‘name’ as SupplierCode.
The various elements are named as follows :
SupplierCodeLookup.xaml The xaml for the pop-up selection list window
SupplierCodeLookupViewModel.dbc The view model for the selection list window, which must contain a method named LoadList
SupplierCodeDrillState The name of the visual state used to display the selection list This is code generated by Orchestrator Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.NavigateState}" CommandParameter="SupplierCodeDrillState"
Changes to Repository
The repository was changed to indicate that a drill method called supplierCode was required for the
field.
Working with Symphony Framework V1.3
Page 103
The long description was set to :
Q – what is the long description used for ?
If the repository is changed then the code generated entries for the file in question need to be
regenerated via Orchestrator.
Working with Symphony Framework V1.3
Page 104
SFE_UI\Common\SupplierCodeLookup.xaml
Working with Symphony Framework V1.3
Page 105
Points to note are :
- This is a user control, which is displayed as part of the application’s main window
- The fields displayed per record are defined as data grid columns, bould to properties of the
supplier data object
- The user can sort the columns
- The user can only select a single item from the list
- The double click event selects the current item by binding it to a“selectItem” command
- The selected item is bound to the “selectedItem” property
- The user can move the window by holding the left mouse button down
SFE_UI\ViewModel\SupplierCodeLookupViewModel.dbc
This is a very simple view model which defines a single method to load the selection list with records
from the Supplier file, using Symphony Harmony. This extends the base class SerachViewModel.
Working with Symphony Framework V1.3
Page 106
Changes to Maintenance.xaml
The visual state for the supplier code lookup is managed within the maintenance.xaml file within the
SFE_Product\View Project.
The main visual state for the maintenance program contains the following to switch the lookup’s visual
state off :
Note that all pop-up drill windows need to be disabled in this main visual state.
A visual state for the lookup was then defined :
The name of the XAML window to load for the visual state is then defined (ie, SupplierCodeLookup) :
The binding path to SuppCodeLookupVM is a property of the ProductMaintenanceView Model, which is
an instance of the SupplierCodeLookupViewModel
Working with Symphony Framework V1.3
Page 107
Changes to View
No changes were needed for FullInput.xaml as the code generated style for the supplier code field adds
a lookup icon to the screen.
Changes to View Model
Code was added to the constructor method in ProductMaintenanceViewModel.dbc to create an
instance of the supplierCodeLookupViewModel .
A private and public property were created for the Supplier Lookup View Model :
The instance is created by the private method buildSupplierLookup, which is called from the
constructor:
Working with Symphony Framework V1.3
Page 108
This creates the instance and sets up 2 event handlers to cater for the user either selecting something
from the list, or cancelling out.
These call doSuppCodeItemSelected and doSuppCodeItemCanceled, depending on the action of the
user.
Finally, we have a method to load the contents of the supplier selection list just prior to navigating to
the lookup visual state.
Working with Symphony Framework V1.3
Page 109
This is called by an event handler defined within the constructor :
Changes to Model
No changes were required at the model level, apart from regenerating the Product_data class via
Orchestrator.
Working with Symphony Framework V1.3
Page 110
To do list
1. Redo SupplierReport using styles based on fields on the SELECTIONS data structure rather than
additional properties defined in the VM
2. Explain .net types versus synergy data types
Working with Symphony Framework V1.3
Page 111
Questions
1. How do you set it to respond to each key click rather than waiting to move off a field ?
2. How would you make the full input window a tab set ?
3. How would you add additional windows to dock/slide in/out, or place on the screen ?
4. How would you add a third party control to a data grid ?