Introduction

 Top Next

These eNotes have been written to accompany my Power Point Presentations prepared for

Vulcan.Live.15 in Cologne - April 21st/22nd.

It is best to find and read through the PPP slides for 2015 and also those re-issued which were

provided for VL 2014.

It is important that you gain an overall idea of what the "MVVM approach" actually means, before

you try and learn some of the many details required for successful development.

Because of the range of features, and functionality I will need in my apps, I am using Visual Studio only

and am not addressing the use of VIDE. Sorry some of you guys!

There is currently available a VS 2013 'Community' download which includes TFS (Team Foundation Server)

and is a fully functioning version of Visual Studio.

Vulcan.NET integrates fully with this version as long as you get VN .303k or later.

Good Luck with your learning, there is much fun ahead!

PHH - 8th. December 2014 & February 19th. 2015


How to use these eNotes

 Top Previous Next

These eNotes will provide you with useful reference material for many months and years to come.

However, as well as being reference material the notes also provide you with many sections which

you can follow through yourself, at your computer, using Visual Studio 2013 Update 4. Or the newly

available 'Community' release of VS 2013.

Try to acquire the above version of Visual Studio, and if you can't then drop back to the best version

you have previous to VS 2013. Note Vulcan .303k is the first Vulcan version to be compatible with

VS 2013.

Until you become experienced with XAML and data binding, I strongly suggest that you copy the

style of coding and scripting laid out carefully in and throughout these eNotes. If you try to cut corners

then some data binding will not work - I know, I have been there ;-0((

Enjoy !!!

PHH - 8th. December 2014. & February 19th. 2015


How to use the samples to develop your skills

Most or all samples have full working code and script included in a child sub-section of

the chapter in which it is developed and discussed in detail.

Here is an example of what I mean - checkout below :-

=======================================================================

In the above image both of the child folders have code and script which can be copied and pasted

into the the most appropriate files in the SE pane.

If the copying is done correctly then you should end up with a working WPF application.

However, and there is a BIG 'however', if you are inexperienced or a new guy, you are likely to

get things wrong, so be CAREFUL, and be warned. If you try to cut corners then you could end

up wasting time and effort, as well as getting frustrated ;-0((

There are plenty of simple sample sections where you can try to copy in your VS shell, what I am

doing and discussing in the body of the chapter.

Also I recommend you check-out in detail the subsection of this chapter relating

to the 'walk-through' style of learning.

Although I try to show readers how to do in VS, exactly what I am talking about, and doing myself,

there is a limit to how many times (and how many sample apps) this can be done in full detail.

After a few simple samples of 'walk-through' I change to a similar style but without all the full details.

In later sample discussions it is assumed that you know how to carry out many of the basic IDE or

'shell' operations - like starting a new Project for example.

Since I wrote the chapter contents as I was creating the samples myself, and made suitable screen shots,

there is a HIGH chance that all this stuff should work for you, as long as you remember NOT to cut corners.

If all else fails :

If things were to go all wrong for you then there are quite a number of the samples provided in full with the

conference material.

A lesser way to use the material is to just load and run the sample solutions within VS. However, you then

don't know what I did things as I did and also why!

So keep this in mind as you read, learn and work at the IDE.

See you in the next sub-section .................

PHH - 9th. December 2014. & February 19th. 2015


Software required - One

A copy of Visual Studio (Professional) :

[ .. get the very latest in which the Vulcan compiler will run .. at present that is VS 2013 .. ]

{ I wrote this before 'Community' was released .......

I strongly suggest you get a copy of at least VS 2013 Update 4 - Professional.

Even though the conference is about Vulcan.NET we as .NET developers need to be able to

switch easily, and happily, between VN and CS (C#). I use both together, quite regularly.

Vulcan.NET is a good .NET citizen ! It is very compliant.

Try to get the very latest Vulcan.NET version, I am currently using '303k'.

Also try to acquire Redgate's Reflector 8.2 or later and integrate it into the VS environment.

Get SQL Server from Microsoft (MSSS), however the 'Express' version is quite sufficient for our needs.

We need SQL Server for 'Entity Framework', and we are using version 6 of 'EF'. This is the latest from

Microsoft to date (Feb. 2015)

} ..............

*** And now, the Latest News ***

https://www.visualstudio.com/products/free-developer-offers-vs

Microsoft have released a "good deal" version for developers - completely FREE :-

===========================================================================================================

It even includes TFS (Team Foundation Server) and the whole application is very easy to download and install.

Study some more information on this offer from Microsoft :-

====================================================================================================

http://channel9.msdn.com/Events/Visual-Studio/Connect-event-2014/040

=====================================================================================

Please also note that the VS IDE provided by this FREE offer is also quite rich in SQL Server support.

We can open SQL Servers and look into databases, both for data values and to examine the table structures.

https://www.visualstudio.com/products/free-developer-offers-vs

Lets continue with our learning and finding out :-

===================================================================================================

https://www.visualstudio.com/products/free-developer-offers-vs

If you get a chance to have a FREE account for Azure I suggest you jump at the chance - I have one, and it is

a great way to learn.

Check out the following :-

================================================================================================================================

Below is an image of my IDE showing the presence of two connections to Azure SQL server with selected (chosen) database :-

===================================================================================================

Notice below the icons used to show an Azure connection - these are the bottom two from the five shown :-

==========================================================================================

One thing I have not as yet done, and that is to create a database using CodeFirst EF6 in my Azure SQL

Server. I will try this out soon ..............

PHH - 8th. December 2014. & February 19th. 2015 & March 29th 2015.


Software required - Two

· Latest version of Vulcan (currently 303k) - this is required to us to be able to use VS 2013 'Community'.

· Microsoft SQL Server, the latest free 'Express' version will do just fine - I used 2014.

· The 'Viewer' tool from Microsoft for "PowerPoint" slide shows, and presentations. Both still images and

video clips can be displayed and shown.

· 'QuickTime' to allow and facilitate video clips shown on an slide.

Firstly, SQL Server - there is enough detail below, including web links and URLs :-

====================================================================================================================

Below is the web link to use :-

http://www.microsoft.com/en-gb/download/details.aspx?id=42299

============================================================================

The installation process for the above '2014 Express' is easy enough to get right - just follow your nose ;-0)

And now to be able to display, see and view 'PowerPoint' slides ...........................

Microsoft PowerPoint viewer - download :

https://www.microsoft.com/en-gb/download/details.aspx?id=13

If we do not have a suitable version of Microsoft Office installed on our target PC platform then we need a 'Viewer'.

Here is how to find and download such a software tool :-

==========================================================================================================

https://www.microsoft.com/en-gb/download/details.aspx?id=13

=============================================================================================================

https://www.microsoft.com/en-gb/download/details.aspx?id=13

And now we move on to the software support needed to show video clips in the slides .........................

"QuickTime" - from Apple :

https://www.apple.com/uk/quicktime/download/

====================================================================================================================================

Without the above installation the slides which include a video clip will not display as required.

It is important to make this available to yourself as the video clip is a away of showing sample running, without the

need for software to be installed on the viewing PC platform.

PHH - 29th. March 2015.


Why focus on WPF - XAML for desktop ?

With Windows 8 and 10 on the desktop, we are most likely to see code and development

along the lines of what can be done today with WPF and XAML - it will form a central part of

all common 'core' coding on most (or all) of MS's hardware platforms in years to come.

Other similar code, previously developed for Tablet and Windows Phone will be changing a little from

what I discussed in my Power Point Presentations at Vulcan.Live.14 last year. However, a lot will

be common to both.

Microsoft may change names a lot, but the underlying technologies don't change as much as you may

think - they do not waste investment efforts ;-)

Although the general basic stuff will be similar, the closest to what will be seen in the future is

will be the WPF stuff I have been coding and developing for the past few years.

However, be careful, as there is still the likelihood that we have slightly different class UI elements

in Tablet, Phone, Desktop, XBox and Web stuff.

In the future we should be able to transfer much of our knowledge, experience and skill set from

WPF desktop to each of the others - and the new "Windows Apps".

In the past I found it relatively easy to move to app design and development on the Tablet and Phone

because I had experience with WPF, so in some ways this proves what I suggest above.

Until this 'One Core' approach of MS settles down, and is more 'fixed' I suggest you gain knowledge

and experience with WPF for desktop - it won't let you down.

Much of what you do will be useful in the 'new world' of programming.

PHH - 9th. December 2014. & February 19th. 2015


'Walk-Through' style of learning material

RULE ONE : Do not be worried about sections which have so far been left empty !

There is a huge amount of detail in these eNotes - most of which you will find VERY helpful -

so focus on the filled sections and what they have to say ;-0)

Do not assume that because some earlier sections are yet to be filled (are empty) that

ones following will also be empty - that is just NOT the case.

There is a HUGE amount of stuff in chapters 9, 14, and 15.

So you will find 'walk-through' parts in quite a few sections, even in later chapters.

When you find a walk-through sub-section, try to follow along with your own VS application.

Overall, I have tried to make the chapters flow from 0 to 27, and ideally they should be read and

studied in that order. However, the more experience you have, the more likely that you are to be

able to use what I present to you in your own way - you know, 'do your own thing! '.

The whole reason I tried to use 'walk-through' as a style of writing, is to help readers learn VS and

its parts and tools, without realising that they are learning VS.

Chapter '0' is dedicated to Don Caton - who put the zero into 'Chapters' and who taught me my

first two conference sessions on VS (version 2005 at the time).

Good Learning ;-0))

PHH - 8th. December 2014. & February 19th. 2015


No quick way to learn all this !

I will not tell you lies, I will be honest and up-front with you, to learn and be good at WPF

and data binding with XAML script, takes a HUGE amount of effort and a load of your time.

There is no easy way - BUT - the good news is that you can save yourself a LOT of time

by not wasting time ;-0) Follow these eNotes to save yourself time.

I have given you most of the secrets in these eNotes, so you don't have to experiment and

do zillions of things wrong while finding out the right way ! I have done that for you.

If you are serious about learning WPF / XAML / and the MVVM style approach, then find time

to work your way through these eNotes.

Time spent with Visual Studio open, and you entering script and code as shown in my 'walk-through'

sections, is time well spent by you - VS becomes easy to use if you spend time exploring what it

has to offer us as developers.

For your information and interest, I myself have learned a great deal by researching and writing

the notes - this is because I had to examine most things in fine detail, and that is when we find

out more facts and build more skills etc..

Spend some BIG time with VS and you will not regret it.

PHH - 8th. December 2014. & February 19th. 2015


The Future - One

VERY latest News (well it was yesterday!) :

Microsoft has announced that henceforth, all Windows 10 Universal applications will be

known as “Windows apps.” Windows desktop applications will be called “Windows desktop applications.”

So then, a better mapping for us is that WPF apps will be called 'Windows Desktop' apps, and the old Metro style

apps will run on Windows 10 on all platforms (devices) and be called 'Windows apps'.

'Applications' are for desktops, and 'apps' are for Windows 10.

So Dick, in my understanding, Metro style apps are to be everywhere, whether we like it or not - a few name

changes may hide the fact ;-0)

One benefit in going "Universal" (can't say going Windows!) is that we are likely to see a common set of UI classes

and therefore UI tools. That will be a BIG and good step forward I feel, as WPF UI classes feel dated in my opinion.

To my mind, my WPF and XAML skills will take me a long way in the new world to come - some call the future, but

is already somewhere in Redmond today.

=============================================================================

Looks like we will need to get familiar with what "OneCore" means.

Since we are not talking about the future of everything in this subsection, and just the future of the

programming and software development code used for MS's range of platforms, then 'OneCore' is

what we should be following (or was).

=============================================================================================

http://www.windowscentral.com/windows-onecore-shows-some-microsoft-linkedin-pages

=================================================================================================================

The above information is probably NOT a surprise to many of you guys out there, it is not to me either.

I suspect that any of us with existing WPF / XAML / data binding skills will find it easy enough to go the

'OneCore' route in future.

However, I suspect that there will be some changes, modernisation, and updates on the UI element classes

available in 'OneCore', and some older controls will be dropped.

My guess is that we may see the Radio Button disappear for good, it already seems the oddball in the Toolbox.

And there may be many others too.

The good news is that there will be newer classes, like some of the nice ones in Tablet and Phone for items display.

Short Summary :

Get into XAML, and well enough to do the MVVM style 'pattern' approach.

Get VERY good at Data Binding.

Get excellent at designing effective ViewModels.

Keep your Views simple and in 100% correspondence with the designed VM.

PHH - 8th. December 2014. & February 19th. 2015


The Future - Two

'Azure' and the 'Cloud' :

Okay guys, I was as sceptical about this 'cloud' stuff as any of you were.

However, after a good introductory two sessions with Paul Piko from Australia at DevShare, I

have now given 'Azure' a go to see what it offers me - and I enjoyed the experience.

Having looked at virtual machines, and then SQL servers and databases, I am becoming a convert. It's nice.

There are some very nice features and facilities to 'Azure', and it is really quite easy to access and use.

On top of all the above, we only get to pay for what we actually use, or 'consume'. Since Azure is really

a bunch of services, we should talk about 'consuming Azure services', rather than using them.

Machines (virtual) or Services (software) :

Let's think in 'real' terms, if we need a certain specification of computer architecture we can think of renting (or hiring)

a computer.

If we wish to use certain applications and database packages, we can think of software 'services'.

When we request a SQL server for our use we get the software provided to us, we do not need to purchase it, even

though we can specify "multi use" by many, many users (unlike locally used Express versions).

PHH - 29th. March 2015.


Terminology & Acronyms

'ClickStart' - one or more web sites maintained and owned by Phil Hepburn. Named by John Parker these

web sites provide an easy way to accessing the many eVolumes of eNotes (almost eBooks) in which PHH

maintains his own working development notes and working code samples and snippets.

'DevShare' - a meeting of like minded developer guys who usually meet about one a year in the UK.

Paul Piko gave the name as the very low cost get-together is more like a user group meeting than a conference.

IDE - Interactive Development Environment, so we talk of the VS IDE

MVVM - "Model, View, ViewModel" - a development 'pattern' or approach

MVVMLight - a 'light' or cut-down framework from 'Laurent Bugnion' (Galasoft) in Switzerland (a one man band effort).

http://blog.galasoft.ch/posts/category/mvvm/

https://mvvmlight.codeplex.com/

==============================================

Prism4 - Microsoft's MVVM full framework, all classes needed to support the MVVM approach

Development 'Pattern' -

LINQ - Language Integrated Query

EF - Entity Framework

Azure - Microsoft's 'cloud' solutions to everything ICT and not local - the PC becomes a 'dumb terminal'.

XAML - Extensible Application Markup Language, or XAML (pronounced "zammel"), is an XML-based

mark-up language developed by Microsoft. XAML should more correctly be called a 'Script' than a language.

I will talk of .NET code )CS and VN) and XAML script.

VS - Visual Studio

MS - Management Studio, the stand alone tool which provides a management platform for SQL Server.

This is a Microsoft product.

'Top Down' - application design approach - sketch out the solution by 'named' modules, and which module

then calls another. Details are the last things to be added - details of code that is. Classes can be named

in a similar fashion. The modern way of doing things !?

'Bottom Up' - application design approach - details of classes and modules are filled out in detail, when other

parts of the solution have not even be thought out. This is the unprofessional approach, and one which any

guy can fall into, simply because programmers like to write code more than they like designing a solution

'pattern'. MVVM is certainly NOT 'bottom up'.

The old fashioned way of doing things !?

PHH - 12th. December 2014. & February 19th. 2015


Chapter 0 - How to use Visual Studio

Some earlier eNotes to checkout :

http://www.clickstartvulcan.net/WebNotes/VisualStudio/ClickStartVS.html

However, do be aware that these are date October 2008, and so are almost 7 years old !!!

=============================================================================

Here are some of my heart felt thoughts on guys using Visual Studio - learned by myself "the hard way" !

The SE pane is not used enough - guys do NOT structure their solution in enough detail, they also do not

split up their code and script into small enough and organised parts.

Keep your classes as small as possible - do NOT make any large classes.

If a class is of a reasonable size, then think of trying to split it across files, using the 'partial class' structure.

Create and use more Namespaces than you may have previously been used to.

Using various Namespace is one way to structure and split up our code into meaningful 'chunks'.

On the other hand be careful that you do not end up with too many different Namespaces. Do not have a

new Namespace just for the sake of it, it has to reflect the structure or functionality of the project.

As your solutions and projects get larger, then you are more likely to need more Namespaces.

=============================================================================

Get the very latest of Visual Studio (full version) that you can.

You may have to have one version for all .NET things as well as C#, and another slightly earlier version

which is supported by the latest version of Vulcan.NET.

I would suggest you keep away from any form of 'cut-down' VS version out there. And now that VS 2013

'Community' is a free download I would also suggest keeping away from the version supplied by Brian and

Grafxsoft.

There are so many useful and helpful features in the Professional version of VS that we would be silly and

stupid to pass them by, or do without them.

Be in control of your VS environment - do not feel 'overwhelmed' by it:

Being 'scared' (frightened) of all the panes and screens etc. !? :

Personalising the IDE, or NOT !? :

Using C# :

Making and Using 'Class Libraries' - C# and VN :

SQL Server support in the Visual Studio IDE :

SQL Server support instead of 'Management Studio' :

Code and Script Safety - 'TFS' - (Team Foundation Server) :

The XAML 'Designer / Editor' - or Blend ? :

Using Templates for Everything :

PHH - 8th. December 2014. & February 19th. 2015


Prevoius eNotes - still useful

There will be some stuff in the earlier eNotes that is not repeated in my offerings later in this chapter.

So check them put, particularly to get started with Debug.

http://www.clickstartvulcan.net/WebNotes/VisualStudio/ClickStartVS.html

However, do be aware that these are date October 2008, and so are almost 7 years old !!!

The early notes are helpful for WinForms, but since I gave them up many years ago then these current

2015 eNotes are firmly based on WPF and XAML technologies.

==========================================

PHH - 2nd. April 2015.


There's no such thing as a 'Typical' IDE layout

Its all about space (or screen real estate) and room to work easily on screen and monitor.

Many of the configurable features are about using screen space wisely, and having only those required

elements available to the user / developer, at design time.

As far as VS goes, Customisation and Configuration are the words of the day :-0))

======================================================================================

Lets us take the opportunity to look at two screen shots of my own VS 2013 'shell'.

The Visual Studio 'IDE' shown below, is similar to that which I use on a 'day-to-day' basis - it just happened that way.

Look for panes 'Properties', 'Solution Explorer', 'Toolbox', 'Server Explorer' and 'Output' - note their positions

relative to one another :-

===========================================================================================================================================

[ .. note I do adjust the edges of the panes so that I have more central area available for code/script editing .. ]

Now then guys, after a few seconds I have changed a few things around, and now my IDE looks like the following.

Re-check the relative positions of the Panes and Window(s) :-

===========================================================================================================================================

Yes, we seem to have a completely different layout, panes have been moved from left to right and top to bottom and vice versa as well.

It would appear that the file editors and XAML designer/editor always appear in the middle somewhere - a central feature.

But even that can change - as we hide the side panes - see this 'new look' to the exact same screen layout :-

=================================================================================================================================

In the above image notice the information about the hidden panes - those closed with auto-hide or similar.

Look at the dark blue edges to the left and right, as well as the LHS (left hand side) of the bottom.

Below is a larger view of these, one which is easier to read :-

===================

=======================================

And when we run the mouse over the collapsed 'tab' we get high-lighting as seen below :-

=========================================

Clicking on the highlighted tab will bring up the pane on the VS shell viewing surface.

Moving on .......................

Now then guys, just when we think we know all about what is going on, we find something else ;-0)

That seems to be the story of Visual Studio !

If we focus on the central code / script editing section (or area) we find that we can change display settings there

too, within the area we are displaying.

One important thing we can do for designer editors is share the screen by splitting - check this screen detail :-

===============================================

On the 'Design' line above we can use the double arrow icon to swap around the top / bottom screen sections.

Below is the opposite way to how I normally set and use my IDE - note the Designer at the bottom :-

=============================================================================================================

And we can change the 'split mode' from horizontal to vertical - or top/bottom to left/right - check this icon below :-

=====================

Which when chosen results in the following screen :-

==============================================================================================================

Or in fact we can select toggle to collapse and expand the two panes - you need to try this out for yourselves.

==========================

By placing in focus either the script or the designer we can toggle to full and shared mode, the two separately.

Below we have the script editor expanded :-

========================================================================================================================

And below we have the Designer for WPF expanded to make things easier for us guys :-

Lets move on a step or two .................

Exploding everything !? - floating some tabs onto other screen areas :

When we think we have just about seen everything, we find that we can actually use all of our available monitors,

if we so wish. By choice I have four, MANY folks have two, even with laptops.

Tabs can be picked up with a mouse click and then floated onto screens and display areas outside of the Visual Studio

visible IDE (or shell area) - so they appear external to the 'shell'. In fact they are still under 'shell' control, they are

just floating freely.

Here is a conservative 'explosion' in which only my main screen (monitor) is used - but I could use all four if I wished, and

quite often use a second screen for displaying code files with classes on display - as I work on new code using the

classes in view.

Checkout the following fun image :-

==================================================================================================================================

If you close the 'shell' (exit VS) then the next time you open up VS with this same solution, the screen positions

Are retained, exactly as they were when you closed things down - which is as it should be. So give it a go.

Let move on to see another way to get more editing screen room / space ...................

"Full Screen Mode", ('Shift+Alt+Enter') - 'FSM' :

Under the View menu you will find a menu item named 'Full Screen'.

When activated, the only window displayed will be the active document - that 'tab' selected in the central editing region.

This is especially helpful for those working on low resolution monitors, given that the size of your code window can shrink

dramatically if you have too many windows docked within the IDE (normal view).

To escape from full screen, just click the 'Full Screen' icon-button floating over your code window - or toggle with the same

special keys - Shift+Alt+Enter.

Luckily, these days large monitors and high resolution screens help ease this issue as well as 'FSM'.

===================================================

Seen below is part of an image in Full Screen mode - check the extra entry in the Menu bar :-

===============================================================================================================================

And to get a flavour of what is provided in this mode, see below for the LARGE area provided :-

==============================================================================================

Enough for one sub-section, lets move on to see how we can take more control of the Visual Studio IDE.

See you there .......................

PHH - 31st. March 2015.


Some basics - taking control of the IDE !

Lets start from the bottom and work up ;-0)

Look at the following image and see if you think that it represents the Visual Studio you remember ?

==================================================================================================

Okay then guys, if you think the above is strange and/or crazy, then study the following image :-

===========================================================================================================

The 'Menu Bar' (MB) :

It would appear that the 'Menu Bar' belongs to Microsoft and not our user 'customisations' - the MB is always

present (there), and can't be changed. Its always visible in the IDE. So the image above is the 'bare bones' display

of Visual Studio.

Take a look below at the Menu bar for VS 2013 - there are twelve menus from which to select :-

=============================================================================================================

Customizing the IDE :

We can choose to 'customize' out Visual Studio environment, to make our development work

easier for us - by only having easily available the tools which we regularly use.

Go to the 'TOOLS' menu option and open the drop list of further options - see below :-

=========================================================

Okay then folks, we can see that 'customization' is all about selecting and displaying strips of icon tools under the Menu Bar area.

The lines (linear areas) under the main Menu bar can be provided with one or more of the built-in Toolbars belonging to VS.

As well as the Toolbars provided (see below) we can build and name our own, as well as removing chosen icons from existing Toolbars.

The whole thing is VERY flexible, and totally customisable. But you guys beware - don't do much at all, if you don't have to.

Checkout these details :-

===================================================================================================================================================

What is this ?

Below we see an entry for Vulcan.NET and also a couple of Controls, but I can seem to get it up

and running (displayed) in my VS 2013 shell.

===========================================================================================================================

The 'Toolbar's :

PHH - 9th. December 2014. & February 19th. 2015


The main (or common) windows / panes

As you may have realised by now, Visual Studio is a very complex bit / piece of software.

It is not rocket science, complicated, or calculus - BUT - it does have many sides to it, it has

lots of parts - that is what complex means!

In that case, if VS is complex and NOT complicated, then if we work steadily through the various parts,

getting to know what is there and what each part does, we will be well on our way to feeling comfortable

with VS, even though we may never 'master' it ;-0)

One simple way to get to know VS more thoroughly, is to work our way through the various 'Panes'.

These 'Panes' are often given names including that of 'Explorer' and 'Browser', but can simply be thought of

as windows - I like the word 'Pane' as it suggests a small window.

History - Legacy : How to understand a few things :

As we look at all the parts of Visual Studio today, April of 2015, it is easy to forget that menu options have been

in place and heavily used by the general public of developers for well over ten years - yes '10' that is.

I started by buying VS 2005 after a 'DevFest' where Ginny gave us guys some good advice - thanks Ginny.

Although I took her advice (partly) I did not get into using VS as much as I should, simply because I did not know

where to start, and all of the on-screen details seemed to confuse me and 'scare' me ! Yes, I was scared and

thought that it was too complicated for me to understand.

Now I like it, use it to good effect, but do not consider myself as any kind of expert !!

The other side of this 'legacy' thing is that names were chosen for certain features which looking today ten years

on may have been better named, so as to fit in with the new stuff. For example, should the 'Toolbox' be named

'Tool Explorer' ?

Personally, I think we can live with things as they are, it is quite 'human' as well as interesting.

So windows, panes, browsers and named features like Toolbox and 'Document Outline', will just have to stay

as they are.

Newer additions to VS seem to have less quirky names, which is what maturity does for us ;-0)

In the child sub-sections to this we will look at many of the most useful and commonly used feature windows.

Yes, a pane, explorer, browser are all "feature panes" to my mind.

Lets start with the 'Explorers' ...............

See you in the next sub-section, ready to learn more 'stuff'

PHH - 30th. March & 1st April 2015.


The 'Explorers'

Although we don't really need to explain what 'Explorer' means in general, it may be nice if we

make our own speculation.

It would appear that any feature 'Pane' which has the word (or term) explorer associated with it,

seems to have to do with it being related to information outside of the VS shell itself.

So 'Solution' explorer finds, maintains, and displays code and resource type of files, somewhere

else on disk.

'Team' explorer relates to the SQL data stored elsewhere for various versions of our solution and projects.

Server and SQL Server related explorer panes are to do with all things SQL which are also external

to the VS shell.

Explorers tend to be one-off find and display, but Browsers are there to be regular 'look see' tools.

Enough of this generalised rambling, lets go and learn some new 'stuff' for VS familiarisation.

PHH - 30th. March & 1st. April 2015.


Solution Explorer

This is probably the most important of the VS feature 'Panes'.

Many folks have the SE pane always showing in their IDE, it also seems to be commonly

at top right of screen, even though as you will soon see it can be anywhere really.

Here is my SE pane as I have used it to develop the Vulcan.Live.15 demo application :-

===================================================

The structure of the SE pane relates in folders and files to be much like what we see in File Explorer - see below :-

====================================================================================================================================================

However, we can see more detail by being able to look into multiple folders at any one time.

Below we can see two separate PRG files (Vulcan code files) one in a folder and the other in

a separated sub-folder. Check below for details :-

=================================================

I suggest that you create organised structure in your SE pane right from the word 'go', as you

develop your application.

It would appear from News Group postings (Grafxsoft) that many guys do not take good (or full)

advantage of being able to deeply structure the SE pane, I think this is a mistake.

Anyway, before we go any further, check out the more limited File Explorer view of some ViewModels :-

==============================================================================================================================================

Lets move on ......................

Grouping Code / Script files :

Getting our heads around the difference between SE pane 'structure' and how the code files are separated

and / or grouped.

In many ways the SE pane structure is just a convenience to us, and possibly a way in which we can

more easily apply 'top down design'.

Below is a simple example in which we separate into two file parts, code from the same class, in the

same namespace, obviously ;-0)

Check the two blue highlights :-

======================================================

In the above image the two highlighted PRG files are actually parts of the same class, they could

quite happily be in one file.

In this case I have separated out the Vulcan.NET code so to leave as little as possible in the bottom most

of the two files, as this is what is called "the code behind" and gets written to by the Vulcan code editing

system when an event handler is automatically created.

Look at what is in this simple file, the first of the two we are discussing :-

======================================================================================

I get quite used to splitting my PRG files like this for a WPF form, it works quite nicely ;-0)

Here is the second part, even if there are no event handler stubs or methods :-

=========================================================================================

Image above shows same Namespace and same Class.

If we wished, we could hold any event handler methods in a third file, with a SE pane entry which

was named something related to Events etc., see my trial entry shown below :-

=================================================

Yes, I know, a shorter name may be better / easier.

And here is the new code file - just a stub and no event handler methods as yet :-

===========================================================================================

The sharper eyed of you reading this would have noticed a PRG file in the SE pane with a name

already relating to Events :- check this out :-

================================================

So in effect we have already split off the handler methods, in a previous attempt to tidy our code.

Shown below is a partly collapsed image of the real live and working handlers :-

================================================================================================

We are probably best to move on now that we have some fundamental knowledge of the SE pane.

Make sure you get some good and useful practise in with adding and moving folders and files, as well

as renaming them too.

Remember, Vulcan related SE pane stuff will not generally be as robust and flexible as the C# stuff.

After all it is one man versus Microsoft ;-0)

Having said that I have no real issues that I can't easily work around.

When dealing with entries into the SE pane remember to use the context menu (right click) a lot

to get specific and helpful menu options. Here are a few examples :-

From the 'Solution' entry :

Take time to study the possible options, and try to look to one of your own sample to explore stuff.

=================================================================================================

From the 'Project' entry :

====================================================================================

From a 'Code File' entry :

======================================================

Lets move on ..............

PHH - 30th. March & 1st. April 2015.


Using Templates - a MUST !

This section is easy in many ways - if we are going to add parts to our solution / application by placing

new items in the SE pane and its folders, then we MUST use 'Templates'.

Templates are required for new projects as well as items based on code and script, like forms as well as code

and class files. We need to become VERY familiar with Templates and what they can do for us.

We have a lot of Templates for Vulcan.NET items, but even more at the moment for C# ones.

Yes, this is correct, the above sentence implies that Templates are language based - TRUE !!

When we select and employ a Template the system uses it to add the necessary stub files and also stub

code and script to those files.

Usually, the stub and default stuff allows the solution / project to compile and run, even if it does not do a lot, or

much at all.

Vulcan.NET - Templates :

Okay then folks, the message is "Templates for everything ! ", so lets start with VS open and nothing else - no solution.

Check out the image below where we have selected to start a New >> Project ............. :-

========================================================================================

And then when we click to select the above we getting the following shown on screen :-

========================================================================================================================

Generally, as seen above, I choose a WPF app., now to be known as a "Windows Desktop Application" or what was as

'Universal' application.

I wonder if the large Hollywood studio "Universal (pictures)" had anything to do with the drop of the terminology !?

Lets move on ..............

Adding a New Project :

This is as easy as the solution was previously.

This time select and highlight the open solution entry in the SE pane, and right click for the Context menu.

Here is my example :-

==========================================================================================

And once again we get the 'Add New Project' dialog screen - see below :-

===============================================================================================================

Obviously, there is not a lot of difference between adding a new solution / project to adding an extra project to an

existing solution pane - it indeed any !

Here are the few that I regularly choose and use :-

============================================================

Lets now move forward a few paces to see how to select Templates for individual items in the SE pane.

Selecting 'New Item' Templates :

We first need to place in focus an existing Project entry, within the SE pane structure.

Once we do that we can then right click to get the Context Menus - check below :-

==========================================================================================

And all we now need do is checkout the options for 'New Items' - see below :-

=============================================================================================================

The above short list avails us of the WPF related items of 'Form' and 'UserControl'.

Often we need a code related file not a 'Window' based form.

Here are some options - check out these :-

=============================================================================================================

I have to admit that I don't like using 'Class' items in either VN or CS, but I do use the 'Code' file a lot.

In fact neither of these does a lot except add a new file entry to the SE pane, with the name supplied above

at the bottom of the screen.

Lets look at a default / stub solution/project which has a range of new items added - check this out below :-

==============================================

Obviously, the template has been used to add the SE pane entries, but there are other things going on.

We need to go through and see what the Template does for VN - to provide contents within the items.

Interface :

===================================================

Class :

=======================================================

CodeFile :

============================================================================

Window (WPF form) :

===================================

==========================================================================

=====================================================

UserControl (WPF) :

========================================

==============================================================================================

================================================================

==============================================

C# - Templates :

Advanced - writing your own Templates !? :

PHH - 1st. April 2015.


References

What are they ? :

Every 'Project' in your solution has a References section.

Part of what you do in the SE pane is maintain the correct list of References.

References are effectively pointers to assemblies in which the required Classes are to be found.

The help notes in VS always show for a class the assembly and the Namespace for a selected class.

Let us search on a ListBox UI class for WPF ................ see below :-

========================================================================

What shows up alongside this entry (seen above) is the following - check it carefully :-

================================================================================

It would seem that we need a References entry for the assembly - PresentationFramework.dll

So here we have my SE pane details :-

=======================================

And now we need to see the directives above some code using this class - check this out below :-

======================================================================================

The whole point of restricting references to assemblies is to make things both simpler and faster.

If we only reference required assemblies than time is not wasted searching and hunting through others.

By correct use of Namespaces and References, then only required classes are in our list for use, and

the underlying system will not spend time hunting through list of what we do not need or want to use.

A list of Namespace directives needs to be at the head of each code and script file.

So here is an example of some working C# in the Conference demo sample :-

[ .. check out the directives section in particular .. ]

=======================================================================================

In line 14 above we see that a Class Library is being referred to.

Lets find out more about Class Libraries ..................

Class Libraries (CLs) :

In our demo application of the 'Conference' sample we see in the SE pane below,

that we have three 'Class Library' (CL) projects, two in C# and one in VN, these are basically

classes which can be used elsewhere, in other projects.

Mixing .NET languages is quite acceptable, and easy to do, however we need to take care

and get our references set correctly, as even our own libraries need to be referred to in the

correct manner.

Check out the working SE pane shown below :-

========================================================

Above we have mixed VN and CS libraries of classes.

We can actually refer from one CL to another but we need to be careful in our code design -

more on cyclic referencing in a short while, below.

To keep things simple, here is what we have in the working application.

One CL written in Vulcan an the project is seen below in the SE pane :-

===============================================

Notice above that this CL project does not reference any of the other CLs.

In the code we write to create the Entity Classes we do not have in the directives list any of the

Namespaces within the other C# libraries. Check below :-

=============================================================================================

However, when we look at one of the other C# Class Libraries (that for Entity Framework) we see the following :-

================================================

Yes, now the EF CL is referring to the VN basic classes for use with EF.

This is confirmed by checking the head of the code - see details below :-

===============================================================

Yes, that seems okay to me, but what about our third and last CL, how does this reference

the other two ?

Well, guys, the CL for all the LINQ work written with C# code, needs to have references set to

both of the other two CLs, as you can see below :-

=====================================================

And so when it comes to the code file we need directives to two of our own Namespaces,

check this out below :-

=======================================================

Okay then folks, so far so good, as they say !

But what about the 'WIndow1' class code files (or any other in the main project), they will most likely need to

reference all three CLs (but that may not always be the case for other applications) and so we need to check

out one or more 'Window1' / full project files - try this below :-

========================================

Yes, above we see all three references, one to each CL.

Now checkout the code for the full project, this is class 'SpeakerRead' for the VMs :-

====================================================================================

Okay, that is just fine, but what is the possible catch as this stuff seems to work well enough,

and it should be easy to copy into other similar types of solutions and applications.

Well, to put it simply, it is easy to get ones "knickers in a twist" and set up a 'cyclic' reference situation.

I actually did it myself while designing this demo Conference application.

Simply, we MUST keep away from having one project reference another, which in turn references back to

the first one. We must also stop similar cyclic referencing through three or more projects.

Suitable error messages and warnings will be given I can assure you of that ;-0)

And believe me, it is not as difficult as you may think to create a 'cyclic' situation, so take great CARE !!!

Avoiding the Cyclic Referencing Situation !? :

Oh! guys, this sounds easy to write as a topic title / subtitle - BUT - the reality is different.

You see it is not the referencing entries and directives alone which need to be gotten just right, but

in fact the way you write you code as to expect classes to be used from other libraries.

One thing you can't do is in the first library use a class from the second library, and then have a class in

the second library use a class in the first - that way we would have to create a cyclic pair (set) of references.

One thing is for sure, try to keep your libraries as simple and as short as possible, as that will help.

However, some CLs may be quite long and also 'safe', say like my original 'Print' library years back. Although

the library was quite long(ish) it was also self contained. So no problems there for cyclic behaviour.

In the end, with the Conference application, I decided to make and name my CLs by simple functionality,

so one was to handle the LINQ and another to handle the Entity stuff, while the third and simplest (linear)

was to define my business classes, for use with the EF6 stuff. I still need to take care however.

I can only encourage you to have a go, and try to think things out clearly, before you start coding like mad.

Good Luck !

How to Remove an Existing Reference :

This is easy - open the References folder in the SE pane and right click on the chosen reference entry to

bing up the Context Menu as seen below :-

===================================================

Select 'Remove' with a mouse click, and watch what happens - always do a visual check afterwards.

Multiple selection seems to work - BUT - be careful as it is more work to replace an entry than it is

to remove it. Also we can get to a point where we did not remember what was in the References list

originally.

I strongly suggest that you set up a practice solution and projects and try adding and removing various

references - yes, get some practise in ;-0)

How to Find and Select New References :

Okay then guys, lets get to grips with the process of adding new or extra reference entries to our folder.

The actual process of adding a reference is NOT difficult but finding the correct one to select for adding

is a bit more tricky - we need to know what we are doing, as well as getting the correct version.

Lets start simple, highlight the References folder entry in the SE pane and right click to bring up the

context menu - see below :-

=======================================================

The above is what we get for Vulcan projects, now we see what we get for C# ones :-

=================================================

Just a little different, but we do need to keep in mind that VN and CS will be different in most parts

of this process for dealing with References.

Okay then, so far its easy enough, but what do we get when we select 'Add ...' ?

First Vulcan.NET :

Be aware that VN's dialog box is different entirely to that for C#. We get the older style 'Add.....' dialog

when we are coding with VN - C# has a nice new one which allows multiple selection, as well as better

general tracking of used References.

However, the dialog shown below works, and does the job OK, even if a little slower ;-0)

On opening the dialog we see something like that seen below :-

====================================================================================================

Make sure you are viewing the tab entitled '.NET' and not one of the other four.

Now lets imagine we wish to find 'PresentationFramework' in order to support the ListBox class for WPF.

Click the first entry to highlight it :-

=============================================================================================

All we do is type 'P' and the display immediately looks like this below :-

======================================================================================================

Note that the top highlighted (and selected) row is a consequence of the 'P' typed, and the second lighter

coloured highlight is because of my mouse hovering.

*** Be Aware *** The search is started from the existing highlighted row, and searches on down from there.

When the bottom of the list is reached the search goes automatically back to the top of the list of rows.

The search as such, is only on the first character typed.

The list of assemblies is NOT in alphabetical order.

My initial order is as seen below :-

===============================================================

However, the column headers allow clicking to sort A-Z and Z-A as can bee seen in the

following image :-

==================================================================

Lets move on ...............

Multiple selection is possible - BUT - be most carefully you do not get into a mess by trying

to do too much at once.

Check this multiple selection :-

=========================================================================================================

It seems to me that quite often we are after only one or two new Reference entries at a time, so

take care and 'slowly does it' !

The Recent 'tab' :

Move from the .NET tab to that entitled 'Recent'. This can be very helpful as it shortens the very

long list of possible rows from which to choose.

Here is what mine looks like for the Conference demo application which is open in my IDE :-

==============================================================================================================================================================

Above you can see the 'PresentationFramework' we selected previously in this section of the eNotes.

Also notice above that our own 'dll' assemblies are listed too (with version 1.0) and that Entity Framework

is version 6.1 which is what we should expect.

Okay folks lets move on to the C# flavour of doing stuff with References ....................

Secondly C# - and the Reference folder :

Okay guys, this should be easier simply because we have knowledge about the older way we used to

go about finding and selecting References - as we studied above.

The new dialog screen is entitled 'Reference Manager' and also displays in the header the actual Project

we have currently in focus.

Checkout the following details :-

===================================================================================================================================

Yes, we now see via check-boxes which of the assemblies are already chosen, or set for selection at the press of the 'OK' button.

Before we go and study the other sections (tabs as was) we need to see just what references are already in the folder

within the SE pane - check this out :-

==============================================

So lets try and find and checkout some 'System' entries - see below :-

============================================================================================================================

The 'System.Xml' rows are out of sight (below).

Now then, once again the 'Recent' section is helpful - see below :-

===========================================================================================================================

And finally, a look at my entries in the Browse / Recent section table :-

=================================================================================================================================================================================================================================

Notice that 'AutoMapper' is present in the table, but that it is not being used in the project in focus.

In fact it is actually not being used in any of the four projects VN or CS, in the "VN_FullConf_VL15_Linq_EF6_3"

solution.

Okay folks, enough of all that, its up to you to go play with this stuff and gain some experience by messing

about with the options and dialogs etc., etc..

See you in the next sub-section ......................

PHH - 1st. & 2nd. April 2015.


Images in the SE pane

=====================================================

=======================================

========================================

========================================

PHH - 1st. April & 8th. 2015.


Team Explorer

I use this a lot, and reasonably frequently as well. I strongly encourage others to do the same.

Ever since Team Foundation Server (TFS) was made freely available to MSDN members, and now

the general public, I have been using TFS to keep my code and script safe.

Generally I use the TFS option and not 'Git' - just my personal choice.

My preferred position / location is behind the SE pane at top right of screen. Below is my current setting :-

============================================================

However, as part of the 'moving around' exercise we are doing for the Cologne conference material,

here is an alternative position and the 'Home' view as well :-

==============================================

If you are not using TFS or Git in any of your solutions / projects then you can close this

pane down by checking the top right hand 'cross'.

Personally, I would recommend that each and every one of us uses TFS or Git - all of the time.

Yes, for each and every project we start.

Note that 'Source Control' can be set to 'ON' for existing projects, as well as new ones.

Below is a good example as VL_VM01 has not as yet been added to Source Control, the icons

indicate that as well as there being a suitable option in the context menu - check below :-

=====================================================================

Once TFS is used to activate 'Source Control' for a project we get different icons appearing

in the SE pane - this helps us know just what is going on.

Study the fine details shown below :-

===============================================================

=================================

===========================================================

========================================================================================================================================================

PHH - 30th. March & 8th. April 2015.


Server Explorer

======================================================

=====================================================

PHH - 30th. March & 8th. April 2015.


SQL Server Object Explorer

Once again, it seems to do what it says on the can ....... explores objects which act as SQL servers.

However, it also handles objects which are related to the servers, databases and Tables are objects, as

too the Columns in the Tables.

Have a look below at my development desktop situation, just to see what we get :-

=====================================================================================================

Yes, above we see details of local SQL servers, both free and purchased, as well as a local 'file' format,

and then VERY importantly two Azure servers in the 'Cloud'.

Lets explore further by opening some of the nodes available in the tree structure.

First we will try the the FREE 'Express' download and install I used with EF6 and Code First - check this :-

===========================================================================================

Above we see lots to do with the Vulcan.Live.15 conference material.

Now lets see if the Azure servers are active and still working - I have not visited them for a few weeks.

Check these details :-

==========================================================================================

Okay the folks, lets really Push the boat out (go for it), let us as the Server in the Azure cloud for

some genuine data of mine.

Below we are asking the remote Server to send us back all of the Athlete records / rows:-

==========================================================================================

And although the test Database is not well populated, here is the results set - it is automatically place in a results 'pane' :-

==============================================================================================================================================================================================

And now lets go for a few more records by querying the Sport data table :-

======================================================

Note that in both of the above tables we are storing small images as binary data - all done by CodeFirst

once the .NET classes were suitably defined.

PHH - 30th. March & 8th./ 9th. April 2015.


Source Control Explorer

Well guys, it does what it says on the can ;-0)

This window pane explores 'Source Control' stuff and things !

============================================

========================================================================================

========================================================================================================================================

=================================================================================================================================

===========================================================================================================================================================================================

=====================================================

=========================================================================================================================================

PHH - 31st. March & 9th. April 2015.


Browsers

PHH - 30th. March 2015.


Windows

PHH - 31st. March 2015.


Toolbox

If your Toolbox pane is missing from your shell then find it again in the 'View' tab from the Menu Bar.

Even if it is lurking somewhere that you don't suspect - or know about - the selecting from the menu

options or pressing 'Ctrl+Alt+X' will make it visible on screen.

Here is the VIEW menu - study the details :-

===================================================

===========================================================

======================================

===============================================

============================================================================================

===============================================

========================================================

=============================================================================

PHH - 31st. March & 8th. April 2015.


Adding 'UserControl's - a bit of a drag !?

Okay guys, an important short topic and one we need to know about.

As you go through the eNotes in later chapters you will see that for 'View's we have two classes

in WPF, 'Window' and 'UserControl', both of which have prominent place in MVVM pattern application.

We need to take a few minutes to examine UserControls as they appear in our SE pane and also

how they can be included in the Toolbox as user defined tools.

Check out below the SE pane I have here in a demo development solution / project :-

=====================================================

Yes, UCs (UserControls) are in the 'View' folder - or in the case above the 'ucView' folder.

At the moment, as I write this, the collapsed Toolbox pane looks like the following image :-

======================================================================

Notice in the above image detail, that we have two entries in a specialized section in the

Toolbox pane - basically the section has been given the name of the Project.

It would also look as if we can drag and drop (and use) each of these entries as a complex tool,

or indeed control.

Before we go any further, first lets look at how the last section looks, that of the 'General' heading :-

====================================================

Yes, we can indeed drag a copy of any UC in the SE pane, from our solution and into the Toolbox.

Note we need to drop the 'copy drag' onto the text showing in the General section - see above.

*** WARNING *** although I have gotten this DnD to work for me, it does seem a bit sticky and even

behave as if it does not work properly. C# is what I show here, and VN seems to not function at all for

the current version - no doubt this will change.

Lets start be looking at the template required to add a C# UserControl to our project. We highlight the

project node in the SE pane and right click for the Context Menu - from which we choose the option for

'User Control (WPF)' - see below for details :-

=======================================================================================================

Okay folks, lets leave the default name as it is and check the results in the SE pane itself :-

The results are two files, one for .NET code and the other a XAML designer/editor.

Lets now check out the XAML file after I have added a few standard controls to the design surface :-

==================================================================================================

Okay, nothing too fancy there, but what if we create a new and second User Control and then slide

with a mouse DnD the first UC onto part of the surface of this second one, as well as a few different

standard controls - study the following carefully :-

===========================================================================================================================

As you can see above, the second UC has not as yet been added to the Toolbox, by a drag and drop.

Here is what we get (after some 'un-sticking') when I do a DnD from the SE pane :-

======================================================

Okay then we have UC two which is a nested UC one with some other UI elements.

So having seen that we can nest UCs lets take a look at things from the other way about - lets see a final

working main Window in a working application.

Check below to see a 'ContentControl' (CC) element on the main window :-

=========================================================================================================

The XAML script for the extra UI element is seen in the image above - lines 23 - 25.

Running the application we see the following screen display - check the details :-

=============================================================================

Note that I have now coloured the background of the UC (3) element bound to the CC so that we can much more

easily identify what is what in our window when we build and run the application.

In the image below check out line 10 and 11 :-

============================================================================================================

And how do we make the association of UC with CC ? This too is seen in detail below (line 37) :-

===============================================================================================

Seems quite easy, doesn't it ?

And now I can show you the final Toolbox details, after some difficult dragging and dropping, often

without apparent success.

I am not sure what it is which forces the refreshing of the Toolbox pane, but here are positive results :-

============================================================================

As a bonus you may wish to see the DO (Document Outline) pane for the main Window :-

===================================================================================

Notice that the UserControl3 item does NOT expand at all, whatever we do.

It is seen as a single and closed control.

Enough success for one afternoon, lets move on.

See you in the next sub-section .........................

PHH - 10th. April 2015.


Document Outline

PHH - 31st. March 2015.


Moving and arranging the various 'panes'

This is very much a 'life skill', just as riding a bicycle is, or even driving a car around town.

It is much easier to do once some time has been put in to 'giving it a go' than it is to express in

words, or even from visual images ;-0)

I strongly suggest that you put aside some time to do extensive trials and experimentation.

Eventually, you will feel much more in control of your VS environment, 'Shell', and what it can do

for you.

======================================================================

Let us remind ourselves of the 'bare bones' look of the VS 'shell' IDE :-

================================================================================================================

Yes, as we all know by now, we do not often see the VS 'shell' looking to naked, and yet this is how it is.

It is easy to close down all of the window panes by checking the top right hand side red and black 'X' icon, one

after another in quick succession. This leaves the Toolbars as seen in the following image :-

===================================================================================================

In the above image I have placed (dragged) the separate Toolbar strips onto separate lines for clarity of viewing.

However, we can easily remove those by going into Customisation ...... Tools >> Customize >> Toolbars ...

and un-checking all selected (*** tip - make a note of what you had selected before you save your changes ;-0)

Now then folks, what about us controlling, and placing, some window panes so we can do whatever it is

we have in mind for our coding and application development.

We have two simple questions to answer, "What do we need (by way of 'panes'), and how do we place them?"

It can seem a bit of a put-off if we say that in some way it all depends ! But that is the truth.

So in that case (it all depending) let us look at some common scenarios.

Scenario One - a new Solution/Project :

Let us start with an empty shell, but the Toolbars that I would normally use - like the image shown above.

Now we go to the File menu and create a new project, of Vulcan type WPF. I called mine 'WpfApplication06'.

Juts by doing that the system places a couple of panes as seen in the next image - check it out :-

===========================================================================================================================================

Not a lot - BUT - we do have the 'Properties' pane and the two two code editing panes.

However, once we click on the tab for the XAML editing pane we see a change and the following on our screens :-

==========================================================================================================================================

Notice that the action of clicking the '.xaml' tab in the editing section of the IDE, places a few extra panes in the 'shell'.

We now have :-

o Toolbox
o Properties
o Document Outline
o Data Sources
o ... code ....
o ... script ...

However, if we build and run the application (with Ctrl + F5) we see yet another pane open and attached,

as we can clearly see in the following image :-

==========================================================================================================================================

Yes, because the VS system needs the Output pane to display details, it loads and places it.

Note above where it is placed, this is what we would call the normal (or common) place for it.

If we click outside the 'Output' pane it auto hides, or goes away, leaving a tab and tab header in the status (type) line

towards bottom of screen.

Lets now click the tab for 'Data Sources' just to see what we have - check this out :-

===========================================

Yes, not a lot, as I suspected.

Lets move on ....................

'Usually' - different sorts of window 'pane' means different positions on screen that they can be 'placed'.

Actually, I like my Toolbox on the RHS of the IDE - to the right of the editing panes for XAML.

We can now experiment ..............

Moving the Toolbox pane :

Go to the collapsed Toolbox pane indicated by the tab as seen below :-

=========================================

Open the pane by a click, and then pick up the top of the Toolbox pane and drag with the mouse pointer.

In the following image we see the drag move in operation :-

====================================================================

Okay then guys, the pane is on the move, so what does the possible target sight look like ?

===================================================================================

This is where (and when) we need to use the 'doohickeys' discussed and described in the child

sub-section from here.

Notice in the above image that the yellow pane header of the Toolbox pane is being dragged to the

top button icon area of the cross shaped 'doohickey'.

So with luck we get the Toolbox pane at the top of screen when we release the mouse button. Lets

see just what we get by examining the next image :-

===================================================

Yes, good, but not exactly what I was after, ideally I would like the two panes to be tabs in the

same screen pane area - so that we have three panes of equal size.

Lets try again ................

Adjusting a Pane Position and/or Arrangement :

Let us pick up once more the yellow header at the top of the Toolbox pane and drag it to another

and alternative place in the 'doohickey' active icon shapes.

=================================================================================

This time, as seen above, we will drop the pane onto the left most active icon.

Here is what we then get as a result :-

=======================================================

Arhh yes, that is more like what I wanted. Notice the two other de-selected tabs.

Moving on and Making Further Improvements :

Turning our attention back to the RHS of the 'shell' we can see that VS does not have an SE pane

showing as yet (at the moment).

Lets see how we can add a new SE pane at the left, and above the 'Properties' pane.

Here is what we have at the moment :-

======================================================

So where is the Solution Explorer pane, and how do we place it in the correct spot (a personal

choice) ?

First we need to realise that since we do not have any part of the SE pane on screen, we must first

find it in the menus in the Menu Bar.

'VIEW' >> will do the job quite nicely, see below :-

=============================================================================================

Note above that SE is the first of four 'Explorer' type panes.

Lets see what happens when we select from the menu - where will the pane go? where will it be placed ?

This is what I got, check it out in the following image :-

========================================================================================================================

Well, not exactly what I was wanting, so lets put my wishes right by moving the SE pane - we need to pick it up with the

mouse and drag and place it above the Properties pane.

Here is what I see when I start the move :-

======================================================

Note above that the mouse pointer is actually in the yellow pane header, and only gets into the

'doohickey' up-arrow button icon area when the mouse is moved and hence the pane dragged.

If the mouse button is released where it is shown above then the following image shows what

you are most likely to get, and see on your screen :-

===============================================================

Note that I usually work with the SE pane directly above the Properties pane.

Since a lot of my development work is NOT for huge projects I can manage to have SE and

Properties panes showing at the same time.

So below is a slightly large part of the VS shell after the SE pane placement :-

========================================================================================

==================================================

==============================================================

========================================================================================

============================================================================================================

=====================================================

========================================================

==================================================

=========================================================

===========================================================

===================================================================================================

==============================================================

===============================================================

Time to move on ..............

Let us now go to the child sub-section from here and see just how many other 'strange' ? places

we can dock, or locate' our panes, lets have some fun ;-0)

See you there .........................

PHH - 31st. March & 6th. & 7th. April 2015.


Studying the "doohickey"s

=======================================================================================================

Well then guys, what is all this 'doohickey' stuff ? Answer is quite simple, it was Don Caton who used the

term during a VS double presentation at DevFest (London) many years ago - when VS 2005 was around.

Don used the American slang word (or term) to describe what you see below - check the images :-

Centre of screen :

============================

Right of screen :

==================================================================================

Left of screen :

====================================================================

PHH - 31st. March 2015.


Places not to go !? : Odd but interesting

Let me say right from the beginning that this sub-section is all about personal choice.

For any Visual Studio 'shell' layout of the IDE, it all depends on what we as individuals prefer as a working environment.

What I think of as 'odd', as to the window pane layout, others may like (or even love) to work with.

Take care however, as you can easily change to have a different layout which then applies to all solution/projects yo then

open, even the existing ones.

As yet I do not know how to have different pane layouts associated and attached to different (separate) solutions. And in

some ways I am not that bothered about finding out - SIMPLY - because we get used to being productive with our own

favoured layout, no mater how we came about it - goo luck, fine fortune, or just "higgledy-piggledy" !

For my normal way of working, here is a strange pane layout - check the details thoroughly :-

============================================================================================================================

Also a point to consider is that we may have different devices on which we need to have different layouts.

Some of us have large monitors 24" and more, as well as HD Tablets (like my Surface Pro 3) which have 10 to 12 inch screens.

If we have plenty of screen real estate then we tend to leave the commonly used window panes open - as I

do with my Properties and Solution Explorer ones.

I only move to and open the Team Explorer pane when I need to save the latest version (now and again).

Similarly, my Output, Error and Command windows can be hidden most of the time I develop.

Here below is a very different layout, which some may find useful - but not for me :-

========================================================================================================================================

Note that we have a lot of tabs in the bottom left quadrant, and that the Command, Error, and Output are now at top left

of screen.

Since some panes require long lined display, it makes better sense to place those on Auto Hide' at the bottom of the screen.

However, for now have a look at the following, where we have MANY tabs on the left of screen, as well as the

XAML script area on top of the Designer surface (I usually have things the other way up) :-

===========================================================================================

========================================================================================

Pinning and Auto Hide :

========================================================

==========================================================================================

What we can't do, and where we can't leave panes :

There are not that many exclusions to this 'stuff' - BUT - the ones that are in place do make good sense.

Window panes for editing code and script can only be placed in the central or editing area, not at the sides

of the 'shell' or towards the bottom.

They can be left floating, or free-standing however.

===================================================================================================================

====================================================================================================================================

=========================================================================================================================================

PHH - 7th. April 2015.


Enlarging the work area

Yet another helpful feature to get our heads around ;-0)

It would appear that any .NET code or XAML script that we can add (to) or edit, can have its size changed to

suit our needs - the needs of the developer.

Often the text editing panes have a drop down box somewhere for selection, as well as being able to use

the mouse feature of "Ctrl + mouse wheel" here is one example :-

=========================================================================================================

And here is the other extreme, 400% to 20% - not a lot of use perhaps ;-0) ............ :-

=================================================================

Almost as good as the 'Map Mode' of the scrollbar discussed in the next sub-section ;-0))

Here below is something more useful - setting the XAML design surface to 67% or 50%, which I often do.

[ .. Note the script text size has been left a bit on the LARGE size !? .. ]

=======================================================================================================================

============================================================================================================

======================================================================================================

PHH - 7th. April 2015.


Some survival skills

Closing, Losing, and Re-opening "Panes" of all types :

Make sure you know how to locate in the top menu bar any of the many useful 'panes', like the 'DO' or

"Document Outline" window.

The term (word) window and pane are often used interchangeably - we can use one or the other, or indeed both.

It is quite common for us to lose a window pane from being available - you know, " ... it is not where it was when I last

used it ..." this is often because it has been closed down inadvertently (or by accident).

So we all need to know how to re-open any available pane, from the menu bar options and sub-options.

Once we have re-opened a pane we can move it from its default position, that position chosen by the VS system.

Using the Scroll Bar features for navigation :

The feature we are about to explore was originally called 'Metal Scroll', and used to be an add-in

from a third party.

Now the following is a fully integrated feature of the VS environment, and we can easily change its settings.

First of all we need to checkout below what the detailed scrollbar can look like - as when we called it "Metal Scroll".

Study the following image thoroughly :-

[ .. right click in the scrollbar area to bring up the context menu .. ]

==============================================================

Above we see that hovering with the mouse pointer gives us an enlarged portion of the text, and

that over which the mouse pointer is currently placed.

Below we see the context menu brought up from the expanded scrollbar :-

==================================================

And the dialog screen launched from the context menu is as seen below :-

========================================================================================================

Note that we get the same dialog screen from the 'Bar mode' as the 'Map mode'.

Examine the above image details and then have a try yourself to change and test the behaviour section.

Here is the Bar Mode, and the blue line indicates the current cursor position :-

===========

A fuller image show (below) how the length of the 'Thumb' indicates the portion

of the existing text shown (visible) in the editing window.

The blue line shows the cursor position :-

=================

I have to add a personal note here, to say that I have used the 'Map Mode' feature to

good effect from when it was third party and introduced to us as a user group by Mike Bertenshaw.

I thoroughly recommend you give it a try for yourself.

See you in the next sub-section .........

PHH - 9th. December 2014. & February 19th. 2015

Addendum :

If your code, in the code file in focus, seems too long for the 'Map Mode' to be of real use, then quite

simply your code needs to be split up - and your design and coding technique needs to be revised !


A few useful tips and tricks

Ctrl + M +L : Collapses the open editor content - this is a toggle and often needs two presses before anything

obviously visible is seen on-screen.

Ctrl - (said "control with minus") : Goes back one step at a time in the editor tab, to the previous cursor position - this

works within all file types XAML, C# and also Vulcan. It also works across tabs, which is most helpful.

Ctrl + L : Remove the whole line (text editor)

When entering XAML and designing a WPF form :

'Document Outline' (or 'DO')

When using the VN & C# text editor :

When using the SQL Server 'support panes' :

When using the TFS (Team Foundation Server) 'support panes' :

Outlining :

Finding a pane which you think you can't see :

PHH - 9th. December 2014. & February 19th. & 8th. April 2015


The Debugger and debugging

Well folks, there is no real point in writing anything new on this, as I made some useful eNotes back in October

of 2008 - these will still get you going in the Debugger today.

Here is the ClickStart link :-

http://www.clickstartvulcan.net/WebNotes/VisualStudio/ClickStartVS.html

Then go to Chapter 6 to checkout the 'stuff' on debugging :-

===============================================

Here are some copied screen shots to get you in the mood :-

================================================================================================================

And finally a bit more 'Visual' stimulus :-

======================================================================================================================================

Good Luck - with starting a learning the debugging process.

When you get reasonably OK as a starter guy, lookout the piles of stuff available on using the VS

debugger in a more ambitious, or advanced way.

Even purchase an eBook ;-0)

PHH - 1st. April 2015.


Intellisense XAML, C# and Vulcan.NET

My own quote to myself :-

"In this current coding world of the 'Framework', intellisense is king."

=========================================================================

This is sometimes seen as a topic for hot debate and often argument !?

The truth is that any "intellisense" is better than none.

The appearance of a drop down list at any point in the editor where we are typing is regarded as Intellisense.

The drop list suggestions can be a variety of things from language commands to class members.

It is when we begin to totally rely on intellisense that we can often get frustrated that it does NOT

do exactly as we may expect.

'Not working properly' is a term open to individual interpretation. Also the intellisense can seem to be 'sticky' !

Meaning it does not work as smoothly as we would wish, or hope ;-0)

What sometimes happens to me is that I don't get any intellisense drop down options when I would

expect to see some - then I have to resort to other measures (find another way).

At this point we need to realise that Intellisense is language dependent, in that it is the duty (or job) of

the person integrating a .NET language into VS to see that the Intellisense is set-up correctly for that

particular language - hence currently, Fabrice does the Intellisense work for Vulcan.NET.

Microsoft does Intellisense for C# and the XAML script editor.

In a mixed project, like my 'Conference' application, we may need all three types somewhere across

the files included in the SE pane. It seems to me that it is this situation which may cause issues with

the full and correct working of Intellisense - but things will improve as time goes by.

Here is an image of the mixed application folder/file structure in the SE pane :-

=================================================

Above we have files with .NET code for VN and C#, as well as XAML script.

Since we are discussing Visual Studio and its features in this chapter, we will not linger on any possible

shortcomings in the Vulcan intellisense system in the current VN release 303k.

Vulcan.NET :

=======================================================================

C Sharp - C# :

========================================================================================

===================================================================================================================

===============================================================================

=================================================================================

Cross-Referencing to and from VN to CS and vice versa :

=============================================================================================================

===============================================================================================================

Issues for VN project to CS classes :

=====================================================================================

I can't get anything to show ! - no drop list appears.

=============================================================================

XAML script :

I find the intellisense in the XAML editor very good indeed - its been very helpful to me over the years.

Let us together explore some of the various aspects of what the XAML intellisense has to offer us.

Below we are starting to add a tag and 'te' characters have been supplied by typing - check this :-

=======================================================

After selecting the TextBox from the context aware intellisense drop list, we see below

how it then offers up a list of attributes and events for the chosen class :-

==================================================================

Yes, there are a LOT - see above, the size of the 'thumb' compared to the vertical scroll bar.

==================================================================

As seen above, lets now select the 'Name' property / attribute :-

[ .. type an 'n' to provide a quick location .. ]

======================================

The intellisense system then provides the double quotes for a string input.

Lets now type a space to bring up the drop list once more :-

============================================================================

Yes, above we see lots of attributes for Fonts.

Lets try one ............... see below :-

=========================================================================

And now lets change to a 'bindable' Text attribute - notice the curly brace triggers a different

set of options in the drop list provided by intellisense :-

=======================================================================================

I tend to use (in order of priority) 'Binding', 'StaticResource' and 'DynamicResource'.

Lets see what is offered in the list when we type a single space after the word 'binding' - below

Path and Mode are seen and these are commonly required.

============================================================================================================

The above information and details are just part of what is on offer in the XAML editor.

I suggest you set up a trial application and just give things a go - play around a little, try

out all the stuff shown above, and more if you have the courage ;-0)

Time to move on .................................

See you in the next sub-section.

PHH - 1st. April 2015.


Chapter 1 - Sample(s) one - starting WPF and Data Binding

Okay then guys, lets start with a genuine DataBinding sample, but one which is NOT the way we

will be doing it by the time we get further into the eNotes.

Our simple sample will not be 'WRONG' as such, just a poorer way of going about DataBinding,

if we are to develop a 'good' way of doing things, and one which can be expanded or sized to a much

larger degree at a later stage.

So all the recognised 'WRONG' ways will NOT be shown here, we will start with a way which can be

tidied and improved !

PHH - 8th. December 2014. & February 19th. 2015


Basic first sample

Describing our Basic Start :

We will create a few Public Properties within a suitable class.

Only Public Properties can be bound to DP (dependency properties) on UI elements (controls).

A few standard UI elements will be tried out to see if Data Binding can be achieved.

For this subsection I have started a new Window in my test / trial / demo application.

Lets start by looking at this WPF form before the data binding is set-up - check below :-

======================================================

And we need to look at the XAML script which produces the above runtime output.

Check this out below :-

========================================================================================================

The code behind is just the 'stub' default as seen in the next image :-

=========================================================

Lets tidy this up before we add to it - see the following image details :-

=====================================================

And now lets look at some code after I have tried a couple of things and failed, and then got

something to work for us. Check the following - study carefully :-

================================================================================================

As we can see above, I have tried a couple of simple things first.

One on line 28 works but is NOT data binding. The other on line 20 is not providing an object with

Public properties to the 'DataContext' assignment / association.

The working line 30 provides an object with a public property (called 'TestString') and the binding can

be seen to work.

Unfortunately for some (possibly new guys) the object is also 'SELF' which can be confusing at first.

Until we move on to the next best sample ('Second'), we will need to stick with this approach

Lets do some Tidying :

We can move the existing code such that we have a useful way forward - lets start with the following :-

==============================================================

And the XAML script which has the data binding can be seen in the XAML editor to be this below :-

================================================================================================

Line 13 shown above is where the binding is specified - note the syntax is one of two possible ones,

the 'Path=' may also be left out altogether.

==================================================================================

We can if we so wish, define a new class called 'MyString' with a public property with a name of

'TestString' as seen below :-

===========================================================

We could then use this new class and property as follows :-

============================================================================================

This is probably easier to follow than 'self' applied to 'self' !

However, when we soon get to 'ViewModels' the issue will be over, and nicely solved as well ;-0)

Lets return to using 'SELF' as we can code the rest easily.

Here is a further step in the right direction - check below :-

====================================================================================

And the binding to support this is as follows :-

===============================================================================================================

And taking another step forward we can see this working code :-

=========================================================================================

Okay, yes, it works - BUT - lines 32, 35, and 38 seem a bit 'odd' in one way or another. What can we do

to improve things ?

Well, its quite easy really. Instead of coupling a data object to each of the UI controls, lets couple this

data object with the form itself, so we can replace the three lines with one - study the next image VERY

carefully :-

=====================================================================================

And as well as working okay, it tidies quite nicely to this shown below :-

=====================================================================================

Remember the line 37 is taking the data object 'SELF' and supplying it in the loose coupling

to the 'DataContext' of the Window object. This will change with VMs (ViewModels).

So lets complete the other bindings and data assignments - study the following very thoroughly :-

======================================================================================================================================================

All six bindings have been completed as seen above. These bindings are to Public Properties on the

data object 'SELF'.

Now we need to see the simplicity of the code in the data object - study carefully :-

=======================================================================================================================

Yep! - Success !! - with six public properties and six XAML script bindings.

The ListBox is bound to a typed list or List<Product> and the extra method has been added as seen

in the next small image :-

================================================================

So far so good, we have some working data bindings - BUT - we have too much code in the 'code behind' file.

Also we may really need to have some of these data public properties (PP) bound to other UI elements in other Views,

or Windows.

Remember, we can have a PP bound to many UI elements, and also across multiple Windows and UserControls. So

we need to have a different design 'pattern' and strategy.

We need to move on to creating and using a separate data object, and obviously define a suitable data object

class to do the job for us.

See you in the next subsection ...............

PHH - 20th. February 2015.


working script and code

============================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE WpfUCsVulcanTest

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

============================================================================

<Application x:Class="WpfUCsVulcanTest.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window2.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace WpfUCsVulcanTest

partial class Window2 inherit Window

    property TestString as string Auto

    property TestDT as DateTime Auto

    property TestLogic as Boolean Auto

    property BlockString2 as string Auto

    property LabelTest3 as string Auto

    property aList as List<Product> Auto

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

    return

    method Initialize() as void

        //-----------------------------------

        self:TestString := "Vulcan Victory!"

        self:TestDT := DateTime.Now

        self:TestLogic := true

        self:BlockString2 := "my Block Test .."

        self:LabelTest3 := "my Label Test .."

        self:aList := Product.GetProductsList()

        //-----------------------------------

        self:DataContext := self

    return

end class

class MyString

    property TestString as string Auto

    constructor()

        super()

        self:TestString := "Vulcan Victory!"

    return

end class

end namespace

============================================================================

<Window x:Class="WpfUCsVulcanTest.Window2"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window 2 - first sample :" Height="400" Width="400" Background="LemonChiffon">

    <Grid>

        <DatePicker HorizontalAlignment="Left" Margin="26,10,0,0"

                    VerticalAlignment="Top"

                    Name="dtpkSam1" SelectedDate="{Binding TestDT}" Width="120"/>

        <ListBox HorizontalAlignment="Left" Height="191"

                 Name="lbxSam1" ItemsSource="{Binding aList}" Width="202"

                 VerticalAlignment="Top" Margin="180,10,0,0"/>

        <TextBox HorizontalAlignment="Left" Height="23" Margin="26,241,0,0"

                 TextWrapping="Wrap" Text="{Binding Path=TestString}"

                 Name="tbxSam1" VerticalAlignment="Top" Width="120"/>

        <TextBlock HorizontalAlignment="Left" Margin="180,241,0,0"

                   TextWrapping="Wrap" Height="23" Width="125"

                   Text="{Binding BlockString2}" VerticalAlignment="Top"

                   Name="tblkSam1" />

        <CheckBox Content="CheckBox" HorizontalAlignment="Left"

                  Margin="29,295,0,0" VerticalAlignment="Top" Width="117"

                  Height="21"

                  Name="chbxSam1" IsChecked="{Binding TestLogic}"/>

        <Label Content="{Binding LabelTest3}" HorizontalAlignment="Left"

               Height="27" Width="125" Margin="180,289,0,0"

               Name="lbSam1" VerticalAlignment="Top" />

    </Grid>

</Window>

============================================================================

//----- Product.prg -----

#using System

#using System.Collections.Generic

//----- added for LINQ -----

//#using System.Data.Linq.Mapping  //----- needed for Table & Column .....

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

BEGIN NAMESPACE WpfUCsVulcanTest

    //[Table(Name:="Products")];

    class Product

        //----- Fields -----

        private _cost as real8

        private _dateAdded as System.Nullable<System.DateTime>

        private _description as string

        private _name as string

        private _price as real8

        private _productId as Long

        private _type as string

        //----- Events -----

        Event PropertyChanged AS System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

         constructor();super()

            //

            self:ProductId := -1

         constructor(cN as string, cD as string, cT as string, nC as real8, nP as real8, dtA as System.Nullable<System.DateTime>)

            super()

            self:ProductId := -1

            self:Name := cN

            self:Description := cD

            self:@@Type := cT

            self:Cost := nC

            self:Price := nP

            self:DateAdded := dtA

        return

        //----- Methods -----

        static method GetProductCollection() as System.Collections.ObjectModel.ObservableCollection<Product>

            return System.Collections.ObjectModel.ObservableCollection<Product>{Product.GetProductsList()}

        static method GetProductsList() as System.Collections.Generic.List<Product>

            local aList as List<Product>

            aList := List<Product>{}

            aList:Add(Product{"Long stand 19", "Holder for long pouch 19", "stand", 17.03, 19.73, System.DateTime{2001, 1, 1}})

            aList:Add(Product{"Short stand 19", "Holder for long pouch 19", "stand", 15.23, 17.52, System.DateTime{2003, 3, 3}})

            aList:Add(Product{"Extra long stand 19", "Holder for long pouch 19", "stand", 21.27, 24.09, System.DateTime{2002, 2, 2}})

            aList:Add(Product{"Narrow pouch 19", "Pouch 19", "bag", 1.35, 2.45, System.DateTime{2004, 4, 4}})

            aList:Add(Product{"Standard pouch 19", "Pouch 19", "bag", 1.45, 2.19, System.DateTime{2006, 6, 6}})

            aList:Add(Product{"Wide pouch 19", "Pouch 19", "bag", 1.55, 2.56, System.DateTime{2008, 8, 8}})

            aList:Add(Product{"Extra wide pouch 19", "Pouch 19", "bag", 1.65, 2.81, System.DateTime{2010, 10, 10}})

            aList:Add(Product{"Dry Storage", "Small", "box", 1.05, 1.9, System.DateTime{2005, 5, 5}})

            aList:Add(Product{"Dry Storage", "Medium", "box", 1.35, 2.08, System.DateTime{2007, 7, 7}})

            aList:Add(Product{"xxxDry Storage", "xxMedium", "xbox", 1.35, 2.08, DateTime{2003, 4, 5}} )

        return aList

        static method GetNewProductCollection() as System.Collections.ObjectModel.ObservableCollection<Product>

            return System.Collections.ObjectModel.ObservableCollection<Product>{Product.GetNewProductsList()}

        static method GetNewProductsList() as System.Collections.Generic.List<Product>

            local aList as List<Product>

            aList := List<Product>{}

            aList:Add(Product{})

            aList:Add(Product{})

            aList:Add(Product{})

            aList:Add(Product{})

        return aList

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return Name+" : "+ProductId:ToString()

        //----- Properties -----

        property Cost as real8

            get

                return self:_cost

            end get

            set

                self:_cost := value

                self:NotifyPropertyChanged("Cost")

            end set

        end property

        property DateAdded as System.Nullable<System.DateTime>

            get

                return self:_dateAdded

            end get

            set

                self:_dateAdded := value

                self:NotifyPropertyChanged("DateAdded")

            end set

        end property

        property Description as string

            get

                return self:_description

            end get

            set

                self:_description := value

                self:NotifyPropertyChanged("Description")

            end set

        end property

        property Name as string

            get

                return self:_name

            end get

            set

                self:_name := value

                self:NotifyPropertyChanged("Name")

            end set

        end property

        property Price as real8

            get

                return self:_price

            end get

            set

                self:_price := value

                self:NotifyPropertyChanged("Price")

            end set

        end property

        property ProductId as long

            get

                return self:_productId

            end get

            set

                self:_productId := value

                self:NotifyPropertyChanged("ProductId")

            end set

        end property

        property @@Type as string

            get

                return self:_type

            end get

            set

                self:_type := value

                self:NotifyPropertyChanged("Type")

            end set

        end property

    end class //----- Product -----

end namespace //----- WpfMVLstartVN -----

============================================================================

============================================================================

PHH - 20th. February 2015.


Conference - first sample

PHH - 9th. December 2014.


working script and code

===============================================

===============================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

BEGIN NAMESPACE VL15_VM01

PARTIAL CLASS Window1 INHERIT Window

    Public oReg AS Registration

    CONSTRUCTOR()

        SUPER()

        InitializeComponent()

        SELF:Initialize()

    RETURN

    METHOD Initialize() AS VOID

        SELF:My_Main_Win:Width := 360

        SELF:My_Main_Win:Title := "Vulcan.Live.15 demo One :"

        //---------------------------------------------------

        oReg := Registration{}

        oReg:FirstName := "Dan"

        oReg:LastName := "Logan"

        oReg:Country := "Romania"

        oReg:Company := "Super Fly"

        oReg:HasPaid := true

        oReg:IsAlone := true

        oReg:Newbie := false

        oReg:RegistrationDate := DateTime.Now

        oReg:RegistrationId := 22

        oReg:SessionA := false

        oReg:SessionB := true

        oReg:SessionC := true

    RETURN

    //----- Event Handler -----

    PRIVATE METHOD pbViewConfReg_Click( sender AS System.Object, ;

                                e AS System.Windows.RoutedEventArgs ) AS System.Void

        LOCAL oVCR AS ViewConfReg

        oVCR := ViewConfReg{oReg}

        oVCR:Show()

    RETURN

END CLASS

END NAMESPACE

===============================================================================================

<Window x:Class="VL15_VM01.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300"

    Name="My_Main_Win" Background="Bisque">

    <Grid>

        <Button Name="pbViewConfReg"

                Content="View Conf. Reg." HorizontalAlignment="Left"

                Margin="10,19,0,0" VerticalAlignment="Top"

                Width="118" Background="LightBlue"

                Click="pbViewConfReg_Click"/>

    </Grid>

</Window>

===============================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE VL15_VM01

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

<Application x:Class="VL15_VM01.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

===============================================================================================

//----- Registration.prg -----

//----- Monday December 7th. 2014. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

BEGIN NAMESPACE VL15_VM01

    CLASS Registration implements INotifyPropertyChanged

        //----- Fields -----

        PRIVATE _registrationId AS LONG

        PRIVATE _firstName AS STRING

        PRIVATE _lastName AS STRING

        PRIVATE _country AS STRING

        PRIVATE _company AS STRING

        PRIVATE _registrationDate AS System.Nullable<System.DateTime>

        PRIVATE _hasPaid AS System.Nullable<LOGIC>

        PRIVATE _isAlone AS System.Nullable<LOGIC>

        PRIVATE _newbie AS System.Nullable<LOGIC>

        PRIVATE _sessionA AS LOGIC

        PRIVATE _sessionB AS LOGIC

        PRIVATE _sessionC AS LOGIC

        //----- Events -----

        EVENT PropertyChanged AS System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        CONSTRUCTOR()

            SUPER()

            SELF:RegistrationId := -1

        RETURN

        //----- Methods -----

        METHOD NotifyPropertyChanged(propertyName AS STRING) AS VOID

            IF (SELF:PropertyChanged != NULL)

                SELF:PropertyChanged:Invoke(SELF, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            ENDIF

        RETURN

        //----- Properties -----

        PROPERTY RegistrationId AS LONG

            GET

                RETURN SELF:_registrationId

            END GET

            SET

                SELF:_registrationId := value

                SELF:NotifyPropertyChanged("RegistrationId")

            END SET

        END PROPERTY

        PROPERTY FirstName AS STRING

            GET

                RETURN SELF:_firstName

            END GET

            SET

                SELF:_firstName := value

                SELF:NotifyPropertyChanged("FirstName")

            END SET

        END PROPERTY

        PROPERTY LastName AS STRING

            GET

                RETURN SELF:_lastName

            END GET

            SET

                SELF:_lastName := value

                SELF:NotifyPropertyChanged("LastName")

            END SET

        END PROPERTY

        PROPERTY Country AS STRING

            GET

                RETURN SELF:_country

            END GET

            SET

                SELF:_country := value

                SELF:NotifyPropertyChanged("Country")

            END SET

        END PROPERTY

        PROPERTY Company AS STRING

            GET

                RETURN SELF:_company

            END GET

            SET

                SELF:_company := value

                SELF:NotifyPropertyChanged("Company")

            END SET

        END PROPERTY

        PROPERTY RegistrationDate AS System.Nullable<System.DateTime>

            GET

                RETURN SELF:_registrationDate

            END GET

            SET

                SELF:_registrationDate := value

                SELF:NotifyPropertyChanged("RegistrationDate")

            END SET

        END PROPERTY

        PROPERTY HasPaid AS System.Nullable<LOGIC>

            GET

                RETURN SELF:_hasPaid

            END GET

            SET

                SELF:_hasPaid := value

                SELF:NotifyPropertyChanged("HasPaid")

            END SET

        END PROPERTY

        PROPERTY IsAlone AS System.Nullable<LOGIC>

            GET

                RETURN SELF:_isAlone

            END GET

            SET

                SELF:_isAlone := value

                SELF:NotifyPropertyChanged("IsAlone")

            END SET

        END PROPERTY

        PROPERTY Newbie AS System.Nullable<LOGIC>

            GET

                RETURN SELF:_newbie

            END GET

            SET

                SELF:_newbie := value

                SELF:NotifyPropertyChanged("Newbie")

            END SET

        END PROPERTY

        PROPERTY SessionA AS LOGIC

            GET

                RETURN SELF:_sessionA

            END GET

            SET

                SELF:_sessionA := value

                SELF:NotifyPropertyChanged("SessionA")

            END SET

        END PROPERTY

        PROPERTY SessionB AS LOGIC

            GET

                RETURN SELF:_sessionB

            END GET

            SET

                SELF:_sessionB := value

                SELF:NotifyPropertyChanged("SessionB")

            END SET

        END PROPERTY

        PROPERTY SessionC AS LOGIC

            GET

                RETURN SELF:_sessionC

            END GET

            SET

                SELF:_sessionC := value

                SELF:NotifyPropertyChanged("SessionC")

            END SET

        END PROPERTY

    end class

END NAMESPACE //----- VL15_VM01

===============================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

BEGIN NAMESPACE VL15_VM01

PARTIAL CLASS ViewConfReg INHERIT Window

    PUBLIC oReg2 as Registration

    CONSTRUCTOR()

        SUPER()

        InitializeComponent()

        oReg2 := Registration{}

        SELF:Initialize()

    RETURN

    CONSTRUCTOR(oR as Registration)

        SUPER()

        InitializeComponent()

        oReg2 := oR

        SELF:Initialize()

    RETURN

    METHOD Initialize() AS VOID

        SELF:Title := "VL15 :- Conference Registration :"

        SELF:DataContext := self:oReg2

    RETURN

END CLASS

END NAMESPACE

===============================================================================================

<Window x:Class="VL15_VM01.ViewConfReg"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Name="My_Conference_Registration"

    Title="ViewConfReg" Height="360" Width="440"

    Background="Beige">

    <Grid>

        <TextBox Name="tbxFirst"

                 HorizontalAlignment="Left" Height="23" Margin="31,26,0,0"

                 TextWrapping="Wrap"

                 Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>

        <TextBox Name="tbxLast"

                 HorizontalAlignment="Left" Height="23" Margin="31,54,0,0"

                 TextWrapping="Wrap"

                 Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>

        <TextBox Name="tbxCountry"

                 HorizontalAlignment="Left" Height="23" Margin="31,82,0,0"

                 TextWrapping="Wrap"

                 Text="{Binding Country, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>

        <TextBox Name="tbxCompany"

                 HorizontalAlignment="Left" Height="23" Margin="31,110,0,0"

                 TextWrapping="Wrap"

                 Text="{Binding Company, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>

        <CheckBox Name="chbxPaid" Margin="31,150,0,0"

                  Content="Has Paid :" HorizontalAlignment="Left"

                  VerticalAlignment="Top" IsChecked="{Binding HasPaid}"/>

        <CheckBox Name="chbxAlone" Margin="31,170,0,0"

                  Content="Is Alone :" HorizontalAlignment="Left"

                  VerticalAlignment="Top" IsChecked="{Binding IsAlone}"/>

        <Label Content="Session Days Attending :" HorizontalAlignment="Left" Margin="31,219,0,0"

               VerticalAlignment="Top"/>

        <CheckBox Name="chbxSessionA" Content="A :" HorizontalAlignment="Left"

                  Margin="31,250,0,0" VerticalAlignment="Top" IsChecked="{Binding SessionA}"/>

        <CheckBox Name="chbxSessionB" Content="B :" HorizontalAlignment="Left"

                  Margin="31,270,0,0" VerticalAlignment="Top" IsChecked="{Binding SessionB}"/>

        <CheckBox Name="chbxSessionC" Content="C :" HorizontalAlignment="Left"

                  Margin="31,290,0,0" VerticalAlignment="Top" IsChecked="{Binding SessionC}"/>

        <Label Content="Personal Details :" HorizontalAlignment="Left"

               Margin="31,0,0,0" VerticalAlignment="Top"/>

        <CheckBox Name="chbxNewbie" Content="Newbie :" HorizontalAlignment="Left"

                  Margin="31,190,0,0" VerticalAlignment="Top" IsChecked="{Binding Newbie}"/>

    </Grid>

</Window>

===============================================================================================

===============================================================================================

PHH - 9th. December 2014.


Chapter 2 - Sample(s) two - moving towards View / ViewModel

MVVM stands for Model, View, ViewModel.

We can think of this as the data to be seen and displayed, the screen on which the data is seen,

and the object (or thing) which makes these two come together in a functioning way.

Remember, your data will remain deeper in the layers of coding, usually a couple of layers beneath the

GUI surface itself.

But as we code and structure our applications we will be thinking of View, ViewModel, Model(s).

Since a View is a form and ViewModel the supporting data for the form, and Model the business data

to supply to the ViewModel, we can rewrite this as.

'Form' - 'Form support data' - 'Business data' - the chain of .NET objects from the GUI surface down to the

deeply seated data.

Although the terminology of MVVM is simple enough, for quite a while it seems to get in the way of us

understanding what is happening, and what it is etc..

Note that 'Business data' is data which generally comes from SQL databases - or at least back-end DBs.

One of the main reasons for using data binding correctly and efficiently, is to cut down, or even eliminate

altogether, the need for data to be moved from one class object to a similar one (and back again later) as

the application runs. Data values are unnecessarily being passed around in memory.

A list of Products, read in from a back-end data source, should most probably stay in the form in which it

(the list) is returned from the SQL tables. So there is a definite need to pass this through to the on-screen

form, not to process and change its data values and the likes.

Try to cut back (cut down) on the number of times data values pass from one objects to another.

PHH - 8th. December 2014.


Basic Second sample

We have seen that in order to improve out ability and potential to 'data bind', we need our

data object for binding to be a separate object, quite separate to the 'View' object.

The WPF form, or Window, is now to be called a 'View' by us in these eNotes.

The View has a number of UI elements on its surface, and only bindings that are set to public

properties (PPs) of a data object - which is loosely coupled to it.

The bindings are made in the View's XAML script. No data is within the View itself.

Don't make bindings in the code of the data object, which we will now call the 'ViewModel'.

So the GUI is called 'View' and the data object coupled to it is the 'ViewModel'.

We also need to know that a 'Model' is a data object, any data object but usually one made from

a back-end data source.

However, the data object specifically designed and set-up for loose coupling to the 'View' is called

the 'ViewModel'.

If we instantiate one VM (ViewModel) we can have this coupled to more than one View object. This

means that UI element attributes on multiple Views can be bound to the one ViewModel (VM).

Lets make a new sample to show some (or all) of these things.

Just so it is easier to compare, we will keep the View (screen) part as it was in the sample in the

previous section - it will be just the VM and coupling which we change.

The 'ViewModel' - how to design it :

We are going to design our VM (ViewModel) such that it can be coupled (loosely) to one or more

separate View objects.

Any data editing or change will be seen in all Views where the binding takes place. Checking binding

by using multiple (and similar) Views is a good way to see that data binding is working as it should be.

A 'VM' should hold its data and data changes, as long as it is in existence after instantiation.

Often new guys get confused between separate instances of the same VM, these will never be the same

and are to be seen as two quite different data objects. Changes made to one VM will not be seen in

the other - so we need to take CARE when coupling VMs to our Views.

We MUST think out the 'scope' of VMs and that the chosen scope will do as we require ;-0)

Quite and art I can assure you - BUT - not rocket science !

In our SE pane create in the existing application a new folder for our VMs - see below :-

============================================

Now we need a code file in which to place the VM class code.

Try to make a new PRG file as I have in the following image :-

===========================================

And here is the file open, with me having started to enter some code :-

=============================================================

To the above code 'skeleton' we are to add all the public property 'stuff' that we had previously

in our code behind (Windows2).

Here is what I have copied and pasted, then tidied up to suit our needs :-

==================================================================

Yep! - the same properties but set with slightly different values so we can visually check and

follow during our screen tests etc..

Now that we have a separate ViewModel class, we now also need a new Window with which to test it.

Making a new Window - 'Window3' :

Go into the SE pane and add a new WPF Window - see below for my third one named 'Window3' :-

===========================================

For guys new to using Visual Studio the XAML design surface looks like this shown below :-

====================================================================================

Yes, just and empty default 'stub' at the moment, as too is the PRG file, that we call "the code behind".

Checkout the following if you are new to WPF and Visual Studio :-

==========================================================

I have now started to tidy the .NET code and the Vulcan code looks like this shown below :-

=========================================================

And now for the 'magic' part - we can go to the XAML script of 'Window2' and copy most of the details and

then paste then into the new Window3.

Here is what I got in just a few seconds :-

=========================================================================================================

And - YES - we can even leave the bindings as the names of the public properties have stayed the same when

we constructed the new VM class.

Lets now try out the new VM class by instantiating and making a loose coupling - check out below :-

===========================================================================================================================

All the UI element details seem to have come through from the data bindings.

Where do we go next ?

Well, the problem is this, when we use the above code to create a new Window3 object, we also instantiate the

ViewModel, just before we set-up the coupling to the DataContext property on Window3.

This means we can't use the same object (VM) to bind with anything other than the one copy of Windows3.

What we really want is to create the VM data object before we come to the Constructor of the Window3 class,

and pass in the VM object as an initial parameter. Then we could do the same for multiple Windows3 instantiations.

Lets work on this approach ...........

A 'Window' to launch another 'Window' :

What we need to do is effectively create a higher 'level' that the WIndow3 instantiation process.

If we create a 'launch' form we can then set it up to launch (or create and show) multiple windows

of type Window3 - one after another.

Lets create, or add, this extra Window :-

=============================================

And to make the correct window show at application run time change the app XAML script as seen below :-

=========================================================================================

Here is our new launch Window with a suitable push button control :-

============================================================================================================

As you can see from lines 26 & 27 the current code only launches a new window without supplying a

VM object. This means that if we test the multiple screens then we will have separate VM objects, and no

data changes should show 'across' the forms shown below :-

======================================================================================================================

With the .NET code as it is we can edit the TextBox contents and nothing shows in the other forms, even when we change

focus on the TextBox.

I have tried to show this 'disconnection' across the forms in the following image :-

===============================================================

Now then, it is quite easy to remedy this, and make the data binding work across all of the

displayed forms.

Check out the following image carefully - see how text and dates have both changed on all displayed screens

or WPF forms :-

===============================================================================================================================================

In the above image we see the code change in the launch screen - we have to locally instantiate

the VM, and not wait till we get into the Window3 instantiation.

Obviously we need to pass the objects into the Constructor - seen in line 31 above.

Line 24 is the palace that the single creation of the VM takes place - then it is just used over and

over again, as the push button is clicked.

Below I am showing how a date change is immediately reflected in the other forms - meaning it happens

straight away, just as we would hope it would :-

============================================================================

Lets now see how we set up the launching window.

Check this out below :-

=========================================================================================================

Yep! - I know, we are using an event, and MVVM will require that we use commands. This is OK for now I feel.

The interesting changes shown below are to do with the constructor input parameter - line 19.

=================================================================

The passed in VM object is loosely coupled to the suitable attribute/property on line 23.

Now then folks, if we have gotten this right we should be able to see another interesting

behaviour. The VM should retain the changed data even when all previously open windows are closed.

Because the VM is still in scope it continues to exist, so when we open a first window the data value

is displayed correctly.

Here in the following image is the opening of a new first window, and this time the date is 13 - which

is the value I changed it to before the windows closing process - check below :-

====================================================

So what if we wish to be able to see the data value on the launch screen itself ?

Lets see how we can bind a suitable UI element to the 'LaunchWindow' class.

First we need to loosely couple the data object (VM) the the launch screen :-

[ .. check out line 26 below .. ]

===========================================================================

Yes, its one of the 'SELF' couplings once again ;-0)

And now here is the accompanying XAML script and binding (line 10) :-

=====================================================================================================

Lets move on to see what this looks like at runtime - study the following image :-

==============================================================================

You will have to take it from me that when we edit or change one value, the other one appears

to change immediately - and that is both ways around, either editing at the launch screen or the

Window3 screen.

And finally a full look at the new added element :-

===========================================================

You need to realise that this last set of bindings and tests while editing, are simply to show that

we have one ViewModel object, which is bound to multiple elements, and that changing any one

shows the same changes reflected (shown) in the others.

We are starting to see what real data binding is all about - AND - that VMs and Views are required

to make it work correctly.

Time to move on, lets go to the next subsection and see how Models can supply data to VM's in a

more flexible way that what we have seen so far.

See you there ...............

PHH - 20th. & 21st. February 2015.


working scrip and code

============================================================================

<Application x:Class="WpfUCsVulcanTest.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="LaunchWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

============================================================================

<Window x:Class="WpfUCsVulcanTest.LaunchWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="LaunchWindow" Height="300" Width="300" Background="DeepSkyBlue">

    <Grid>

        <Button Content="Show Window3" HorizontalAlignment="Left" Margin="24,25,0,0"

                Name="pbShowWindow3" VerticalAlignment="Top" Width="104"

                Click="pbShowWindow3_Click" />

    </Grid>

</Window>

============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

begin namespace WpfUCsVulcanTest

partial class LaunchWindow inherit Window

    public oW3VM as Window3ViewModel

    constructor()

        super()

        InitializeComponent()

        self:oW3VM := Window3ViewModel{}

        //----- one data object for all oWin3 objects -----

    return

    private method pbShowWindow3_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oWin3 := Window3{self:oW3VM}

        oWin3:Show()

    return

end class

end namespace

============================================================================

<Window x:Class="WpfUCsVulcanTest.Window3"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window 3 - second sample :" Height="400" Width="400" Background="MintCream">

    <Grid>

        <DatePicker HorizontalAlignment="Left" Margin="26,10,0,0" Width="120"

                    SelectedDate="{Binding TestDT}" VerticalAlignment="Top" />

        <ListBox HorizontalAlignment="Left" Height="191" Margin="180,10,0,0"

                 ItemsSource="{Binding aList}" Width="202" VerticalAlignment="Top"/>

        <TextBox HorizontalAlignment="Left" Height="23" Margin="26,241,0,0" Width="120"

                 Text="{Binding TestString}" TextWrapping="Wrap" VerticalAlignment="Top"/>

        <TextBlock HorizontalAlignment="Left" Margin="180,241,0,0" VerticalAlignment="Top"

                   Text="{Binding BlockString2}" TextWrapping="Wrap" Height="23" Width="125"/>

        <CheckBox Content="CheckBox" HorizontalAlignment="Left" VerticalAlignment="Top"

                  Margin="29,295,0,0" Height="21" Width="117"

                  IsChecked="{Binding TestLogic}"/>

        <Label Content="{Binding LabelTest3}" HorizontalAlignment="Left"

               Height="27" Width="125" Margin="180,289,0,0" VerticalAlignment="Top" />

    </Grid>

</Window>

============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace WpfUCsVulcanTest

partial class Window3 inherit Window

    constructor(oW3VM as Window3ViewModel)

        super()

        InitializeComponent()

        //-------------------------------------

        self:DataContext := oW3VM

        //-------------------------------------

    return

end class

end namespace

============================================================================

//----- Product.prg -----

#using System

#using System.Collections.Generic

//----- added for LINQ -----

//#using System.Data.Linq.Mapping  //----- needed for Table & Column .....

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

BEGIN NAMESPACE WpfUCsVulcanTest

    //[Table(Name:="Products")];

    class Product

        //----- Fields -----

        private _cost as real8

        private _dateAdded as System.Nullable<System.DateTime>

        private _description as string

        private _name as string

        private _price as real8

        private _productId as Long

        private _type as string

        //----- Events -----

        Event PropertyChanged AS System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

         constructor();super()

            //

            self:ProductId := -1

         constructor(cN as string, cD as string, cT as string, nC as real8, nP as real8, dtA as System.Nullable<System.DateTime>)

            super()

            self:ProductId := -1

            self:Name := cN

            self:Description := cD

            self:@@Type := cT

            self:Cost := nC

            self:Price := nP

            self:DateAdded := dtA

        return

        //----- Methods -----

        static method GetProductCollection() as System.Collections.ObjectModel.ObservableCollection<Product>

            return System.Collections.ObjectModel.ObservableCollection<Product>{Product.GetProductsList()}

        static method GetProductsList() as System.Collections.Generic.List<Product>

            local aList as List<Product>

            aList := List<Product>{}

            aList:Add(Product{"Long stand 19", "Holder for long pouch 19", "stand", 17.03, 19.73, System.DateTime{2001, 1, 1}})

            aList:Add(Product{"Short stand 19", "Holder for long pouch 19", "stand", 15.23, 17.52, System.DateTime{2003, 3, 3}})

            aList:Add(Product{"Extra long stand 19", "Holder for long pouch 19", "stand", 21.27, 24.09, System.DateTime{2002, 2, 2}})

            aList:Add(Product{"Narrow pouch 19", "Pouch 19", "bag", 1.35, 2.45, System.DateTime{2004, 4, 4}})

            aList:Add(Product{"Standard pouch 19", "Pouch 19", "bag", 1.45, 2.19, System.DateTime{2006, 6, 6}})

            aList:Add(Product{"Wide pouch 19", "Pouch 19", "bag", 1.55, 2.56, System.DateTime{2008, 8, 8}})

            aList:Add(Product{"Extra wide pouch 19", "Pouch 19", "bag", 1.65, 2.81, System.DateTime{2010, 10, 10}})

            aList:Add(Product{"Dry Storage", "Small", "box", 1.05, 1.9, System.DateTime{2005, 5, 5}})

            aList:Add(Product{"Dry Storage", "Medium", "box", 1.35, 2.08, System.DateTime{2007, 7, 7}})

            aList:Add(Product{"xxxDry Storage", "xxMedium", "xbox", 1.35, 2.08, DateTime{2003, 4, 5}} )

        return aList

        static method GetNewProductCollection() as System.Collections.ObjectModel.ObservableCollection<Product>

            return System.Collections.ObjectModel.ObservableCollection<Product>{Product.GetNewProductsList()}

        static method GetNewProductsList() as System.Collections.Generic.List<Product>

            local aList as List<Product>

            aList := List<Product>{}

            aList:Add(Product{})

            aList:Add(Product{})

            aList:Add(Product{})

            aList:Add(Product{})

        return aList

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return Name+" : "+ProductId:ToString()

        //----- Properties -----

        property Cost as real8

            get

                return self:_cost

            end get

            set

                self:_cost := value

                self:NotifyPropertyChanged("Cost")

            end set

        end property

        property DateAdded as System.Nullable<System.DateTime>

            get

                return self:_dateAdded

            end get

            set

                self:_dateAdded := value

                self:NotifyPropertyChanged("DateAdded")

            end set

        end property

        property Description as string

            get

                return self:_description

            end get

            set

                self:_description := value

                self:NotifyPropertyChanged("Description")

            end set

        end property

        property Name as string

            get

                return self:_name

            end get

            set

                self:_name := value

                self:NotifyPropertyChanged("Name")

            end set

        end property

        property Price as real8

            get

                return self:_price

            end get

            set

                self:_price := value

                self:NotifyPropertyChanged("Price")

            end set

        end property

        property ProductId as long

            get

                return self:_productId

            end get

            set

                self:_productId := value

                self:NotifyPropertyChanged("ProductId")

            end set

        end property

        property @@Type as string

            get

                return self:_type

            end get

            set

                self:_type := value

                self:NotifyPropertyChanged("Type")

            end set

        end property

    end class //----- Product -----

end namespace //----- WpfMVLstartVN -----

============================================================================

PHH - 20th. February 2015.


Conference second sample

PHH - 22nd. February 2015.


working script and code

================================================

==============================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace VL15_VM02

partial class Window1 inherit Window

    public oReg as Registration

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

    return

    method Initialize() as void

        self:My_Main_Win:Width := 360

        self:My_Main_Win:Title := "Vulcan.Live.15 demo One :"

        self:oReg := DataModels.GetSingleRegistration2()

    return

    //----- Event Handler -----

    private method pbViewConfReg_Click( sender as System.Object, ;

                                e as System.Windows.RoutedEventArgs ) as System.Void

        local oVCR as ViewConfReg

        oVCR := ViewConfReg{self:oReg}

        oVCR:Show()

    return

end class

end namespace

==============================================================================================

<Window x:Class="VL15_VM02.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300"

    Name="My_Main_Win" Background="Bisque">

    <Grid>

        <Button Name="pbViewConfReg"

                Content="View Conf. Reg." HorizontalAlignment="Left"

                Margin="10,19,0,0" VerticalAlignment="Top"

                Width="118" Background="LightBlue"

                Click="pbViewConfReg_Click"/>

    </Grid>

</Window>

==============================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE VL15_VM02

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

================================================

<Application x:Class="VL15_VM02.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

==============================================================================================

//----- Registration.prg -----

//----- Monday December 8th. 2014. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM02

    class Registration implements INotifyPropertyChanged

        //----- Fields -----

        private _registrationId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        private _company as string

        private _registrationDate as System.Nullable<System.DateTime>

        private _hasPaid as System.Nullable<logic>

        private _isAlone as System.Nullable<logic>

        private _newbie as System.Nullable<logic>

        private _sessionA as logic

        private _sessionB as logic

        private _sessionC as logic

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:RegistrationId := -1

        return

        constructor(cF as string, cL as string, cCT as string, cCP as string, dtReg as System.DateTime,;

                    lP as System.Nullable<logic>, lA as System.Nullable<logic>, lN as System.Nullable<logic>,;

                    lSA as logic,lSB as logic,lSC as logic)

            super()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            self:Company := cCP

            self:RegistrationDate := System.Nullable<System.DateTime>{dtReg}

            //----------------------

            self:HasPaid := lP

            self:IsAlone := lA

            self:Newbie := lN

            //----------------------

            self:SessionA := lSA

            self:SessionB := lSB

            self:SessionC := lSC

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        //----- Properties -----

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        property Company as string

            get

                return self:_company

            end get

            set

                self:_company := value

                self:NotifyPropertyChanged("Company")

            end set

        end property

        property RegistrationDate as System.Nullable<System.DateTime>

            get

                return self:_registrationDate

            end get

            set

                self:_registrationDate := value

                self:NotifyPropertyChanged("RegistrationDate")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property IsAlone as System.Nullable<logic>

            get

                return self:_isAlone

            end get

            set

                self:_isAlone := value

                self:NotifyPropertyChanged("IsAlone")

            end set

        end property

        property Newbie as System.Nullable<logic>

            get

                return self:_newbie

            end get

            set

                self:_newbie := value

                self:NotifyPropertyChanged("Newbie")

            end set

        end property

        property SessionA as logic

            get

                return self:_sessionA

            end get

            set

                self:_sessionA := value

                self:NotifyPropertyChanged("SessionA")

            end set

        end property

        property SessionB as logic

            get

                return self:_sessionB

            end get

            set

                self:_sessionB := value

                self:NotifyPropertyChanged("SessionB")

            end set

        end property

        property SessionC as logic

            get

                return self:_sessionC

            end get

            set

                self:_sessionC := value

                self:NotifyPropertyChanged("SessionC")

            end set

        end property

    end class

end namespace //----- VL15_VM02

==============================================================================================

//----- InMemDS4Registration.prg -----

//----- December 8th. 2014 -----

BEGIN NAMESPACE VL15_VM02

class DataModels

    static method GetSingleRegistration() as Registration

        local implied oReg := Registration{}

        oReg := Registration{}

        oReg:FirstName := "Dan"

        oReg:LastName := "Logan"

        oReg:Country := "Romania"

        oReg:Company := "Super Fly"

        oReg:HasPaid := true

        oReg:IsAlone := true

        oReg:Newbie := false

        oReg:RegistrationDate := DateTime.Now

        oReg:RegistrationId := 22

        oReg:SessionA := false

        oReg:SessionB := true

        oReg:SessionC := true

    return oReg

    static method GetSingleRegistration2() as Registration

        local implied oReg := Registration{"Dan","Logan","Romania",;

                    "Super Fly",DateTime.Now,true,true,false,false,true,true}

        oReg:RegistrationId := 22

    return oReg

end class

end namespace

==============================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

BEGIN NAMESPACE VL15_VM02

PARTIAL CLASS ViewConfReg INHERIT Window

    PUBLIC oReg2 as Registration

    CONSTRUCTOR()

        SUPER()

        InitializeComponent()

        oReg2 := Registration{}

        SELF:Initialize()

    RETURN

    //----- data comes in as 'Model' object -----

    //----- later to be replaced with a 'ViewModel' object -----

    CONSTRUCTOR(oR as Registration)

        SUPER()

        InitializeComponent()

        oReg2 := oR

        SELF:Initialize()

    RETURN

    METHOD Initialize() AS VOID

        SELF:Title := "VL15 :- Conference Registration :"

        SELF:DataContext := self:oReg2

    RETURN

END CLASS

END NAMESPACE

==============================================================================================

<Window x:Class="VL15_VM02.ViewConfReg"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Name="My_Conference_Registration"

    Title="ViewConfReg" Height="360" Width="440" Background="Beige">

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBox" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="CheckBox" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <Label Content="Personal Details :" HorizontalAlignment="Left"

               Margin="31,0,0,0" VerticalAlignment="Top"/>

        <TextBox Name="tbxFirst" Margin="31,26,0,0"

                 Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />

        <TextBox Name="tbxLast" Margin="168,26,0,0"

                 Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCountry" Margin="31,55,0,0"

                 Text="{Binding Country, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCompany" Margin="31,83,0,0"

                 Text="{Binding Company, UpdateSourceTrigger=PropertyChanged}"/>

        <CheckBox Name="chbxPaid" Margin="31,150,0,0"

                  Content="Has Paid :" IsChecked="{Binding HasPaid}"/>

        <CheckBox Name="chbxAlone" Margin="31,170,0,0"

                  Content="Is Alone :" IsChecked="{Binding IsAlone}"/>

        <CheckBox Name="chbxNewbie" Margin="31,190,0,0"

                  Content="Newbie :" IsChecked="{Binding Newbie}"/>

        <Label Content="Session Days Attending :" HorizontalAlignment="Left" Margin="31,219,0,0"

               VerticalAlignment="Top"/>

        <CheckBox Name="chbxSessionA" Content="A :"

                  Margin="31,250,0,0" IsChecked="{Binding SessionA}"/>

        <CheckBox Name="chbxSessionB" Content="B :"

                  Margin="31,270,0,0" IsChecked="{Binding SessionB}"/>

        <CheckBox Name="chbxSessionC" Content="C :"

                  Margin="31,290,0,0" IsChecked="{Binding SessionC}"/>

        <DatePicker HorizontalAlignment="Left" Margin="31,116,0,0" VerticalAlignment="Top"

                    SelectedDate="{Binding RegistrationDate, Mode=TwoWay}"

                    DisplayDate="{Binding RegistrationDate}"/>

    </Grid>

</Window>

==============================================================================================

==============================================================================================

===============================================

PHH - 9th. December 2014.


Chapter 3 - Sample(s) three - moving further towards MVVM

PHH - 8th. December 2014.


Basic third sample

Okay then guys, in Chapters 1 and 2 we have seen (in the 'Basic' part of those sections) that

we can scope our ViewModel objects so that we can share data binding across multiple WPF forms.

Because we were using similar forms (the View was the same) we could easily and happily use the

same ViewModel (VM) to provide the single line coded 'loose coupling'.

Now then, we are to go further than this, and look into the scenario in which we want to have two

separate (different) Views, each supported by its own VM object, designed for that View class - BUT -

that part of the data supplied is required in each of the two VMs.

Let me make this clear and as simple as it is by providing a good example.

We are to have two Views, one for Customers and one for Products. We will have a VM for each and

so these will be called 'CustomerViewModel' and 'ProductViewModel'.

The public properties of both will be suitable to do the jobs for Customers and Products.

Now the BIG difference is that we wish to be able to display a current list of Products on BOTH of the

Views screen displays.

We need to show a Read / Only list of products in the Customer screen, and we need to have a Read /

Write list of the same products in the Product screen.

We need UI list elements in both Views to be bound to the same data as far as Products is concerned.

This scenario is probably as good an example of using Models as we can easily make, so lets do it,

enjoy doing it, and learn as much as we can.

Lets think this problem through ..............

Designing a Solution to our 'VM' Data Access :

If both VMs are to present to the View the same data object associated with a public property, then this

data object needs to be available before we instantiate the VMs.

In fact data objects are commonly called 'Models', and the special one to support the View is obviously

called a ViewModel.

So we need a Model which is actually the Products data, which is instantiated and then passed to both

of the VMs in turn - as input parameters.

Lets try and make a Model around the Products list, or Collection.

Making a suitable Model (for Products) :

Now that we are going to start making Model classes and objects we need a new folder within the SE pane.

Here is what I have added :-

============================================

And now we need to add into the new folder a fresh and empty code file and

give it an appropriate name - see below :-

===============================================

As you can see above, the new file is called 'ProductsModel.prg'.

The general format of this file will be similar to my first attempts shown in the following image :-

==========================================================================================

Yes, guys, we do have a problem ;-0((

The problem is simple enough, we have currently got our 'Model' code mixed in with our Business class

definition code - it was convenient at the time, but now it is giving us issues and problems.

Lets look at the Product business class code - check below :-

===============================================================================================================================================

We provided a couple of STATIC methods to allow us to easily provide suitable lists and collections

of Product items.

Although it was convenient at the time, we really mixed up the Model functionality with our Business

class specification - now it 'bites' us !!

Instead of us messing around and trying to make our existing code adapt to the new requirement, let

us be brave and bite the bullet, and remove all four STATIC methods from the Product class definition.

Yes, there are two for 'New' products as well as existing ones. This means we will have to change some

existing standard application code late as well.

Here is the freshly updated Models class, with all four static methods included :-

================================================================================================

Since we have changed the method names from what they were previously, we will have to edit and change

a few lines throughout the application generally. But the compile will help us there - by indicating the lines

in which we have errors.

Oh! the cleaned up Product class now looks like this :-

=============================================================================================================

Whoops! - line 11 should read as below :-

======================================================================

Let us at the moment concentrate on the new Model / ViewModel structure.

Adding the changes to our existing one screen display - 'Window3' :

Let us now study what we need to do at the 'launch' screen to be able to use our new Model / VM structure.

Below are the details seen in the 'LaunchWindow' - check them VERY carefully :-

=======================================================================================

Line 25 shown above, is where we supply a data object as input parameter to the Constructor of the

ViewModel class called 'Windows3ViewModel'

Previously we had found this data from within the VM code itself - now things have improved!

So we need to see the changes we had to make in the Constructor of the 'Window3ViewModel' class,

so that the code on line 25 above will work correctly. Effectively we are placing data into a data object.

Here below is the adapted code of the ViewModel - there are a few changes to notice :-

========================================================================

The green vertical lines at the RHS (right hand side) margin indicate where changes were made.

We need to have an empty Constructor as well as one taking data injection.

We have also change the list to a proper collection - see line 28. This will make it more flexible in

future, for changing the collection, not just properties on the items in the Collection.

And now we need to build and run the application - here is my result :-

==============================================================================

Okay, not much change at all, considering the amount of effort we put in ;-0((

But at least we now have a R/O list made from Model data injection into the ViewModel.

Lets move on ..................

Making a second View, and VM to also use the Model we just made :

Okay then folks, lets do this another way, let us study what we are going to make when we get our script and code correct.

Here is what we are after, check out the list item 'Short stand 1999' as it has become after editing :-

[ .. study all the details CAREFULLY .. ]

======================================================================================================================================================

Above we see that we have two separate Views - Window3 and Window4.

Each has a separate ViewModel, and the same single Model object is injected into the Constructors

for the VMs. So data injection occurs for 'Windows3ViewModel' and 'Windows4ViewModel'.

Editing List Item Details - DataTemplate :

Okay then folks, time we improved our list display for each item displayed.

Let us create a static resource, a DataTemplate in fact.

We will see two forms of the same data template being used by me, one based on TextBlocks and the other on TextBoxes.

The first one will be Read / Only as it uses TextBlocks - check these details :-

=================================================================================================================================

The above image shows the results of the XAML script when it is applied.

The following image shows XAML script which is to allow editing, it will be Read / Write :-

==========================================================================================

And below we have a clear detailed image showing immediate data changes across the two screens, one

is R/O and the other R/W.

The red one is R/O and the green one R/W. You can tell by the slightly different element displays.

===========================================================================================================

When editing takes place we often need to move focus away from the element being edited, but a few seem

to appear to be immediate, or instantaneous.

Check boxes and DatePickers seem to be immediate.

So lets remind ourselves of how the LaunchWindow initializes things when it is created and displayed.

Check out these details, particularly the Constructor :-

==========================================================================================

And here is the existing code for the new 'Window4ViewModel' class :-

[ .. very similar to the first one called 'Window3ViewModel .. ]

=========================================================================================

Now then folks, you may have seen that so far in the VM classes I have code stuff without tracking

Public Property changes - we need to address this problem, and get things RIGHT !!

Lets move on a step or two ...........

'ViewModels' and tracking property Changes :

Okay you guys, now lets tidy up our approach to, and coding of, the ViewModel classes.

I have found from painful, and bitter, experience that we are best to track changes in all public properties

that we define within the VM itself.

If we use INotifyPropertyChange in all our classes from Business through Models to VM then the data

binding we do in our Views will work 100% of the time - as long as we get our scoping right for VMs and

Models.

So lets make the suitable changes to the existing two VM classes we have been using previously in this

subsection.

First lets see what we have before we start :-

===========================================================================================

And now we need to study thoroughly, and in detail, the newer form of the first of our VM classes.

Checkout all the change details below :-

========================================================================================================

Then finally, after doing the same sort of changes to the second of our VMs, we can build and run our

application - check this out :-

====================================================

In order to display the above image we MUST have used the new classes - as the following code would

suggest :-

[ .. lines 29 and 30 are where the new classes are used .. ]

==========================================================================================

PLEASE do not underestimate the need for property tracking using 'INotifyPropertyChanged'.

Once I used it correctly and extensively in my data related classes then my problems and issues

just went away (regarding data binding) ;-0)

Time to move on, see you in the next section ...................

PHH - 22nd. February 2015.


working script and code

===================================================================================

//----- Product.prg -----

#using System

//----- added for LINQ -----

//#using System.Data.Linq.Mapping  //----- needed for Table & Column .....

#using System.Collections.Generic

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace WpfUCsVulcanTest

    class Product implements INotifyPropertyChanged

        //----- Fields -----

        private _cost as real8

        private _dateAdded as System.Nullable<System.DateTime>

        private _description as string

        private _name as string

        private _price as real8

        private _productId as Long

        private _type as string

        //----- Events -----

        Event PropertyChanged AS System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor();super()

        //

        self:ProductId := -1

        constructor(cN as string, cD as string, cT as string, nC as real8, nP as real8, ;

                                dtA as System.Nullable<System.DateTime>)

            super()

            self:ProductId := -1

            self:Name := cN

            self:Description := cD

            self:@@Type := cT

            self:Cost := nC

            self:Price := nP

            self:DateAdded := dtA

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return Name+" : "+ProductId:ToString()

        //----- Properties -----

        property Cost as real8

            get

                return self:_cost

            end get

            set

                self:_cost := value

                self:NotifyPropertyChanged("Cost")

            end set

        end property

        property DateAdded as System.Nullable<System.DateTime>

            get

                return self:_dateAdded

            end get

            set

                self:_dateAdded := value

                self:NotifyPropertyChanged("DateAdded")

            end set

        end property

        property Description as string

            get

                return self:_description

            end get

            set

                self:_description := value

                self:NotifyPropertyChanged("Description")

            end set

        end property

        property Name as string

            get

                return self:_name

            end get

            set

                self:_name := value

                self:NotifyPropertyChanged("Name")

            end set

        end property

        property Price as real8

            get

                return self:_price

            end get

            set

                self:_price := value

                self:NotifyPropertyChanged("Price")

            end set

        end property

        property ProductId as long

            get

                return self:_productId

            end get

            set

                self:_productId := value

                self:NotifyPropertyChanged("ProductId")

            end set

        end property

        property @@Type as string

            get

                return self:_type

            end get

            set

                self:_type := value

                self:NotifyPropertyChanged("Type")

            end set

        end property

    end class //----- Product -----

end namespace //----- WpfMVLstartVN -----

===================================================================================

//----- ProductsModel.prg -----

//----- PHH - 22nd. February 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-----------------------------------

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace WpfUCsVulcanTest

partial class Models

    constructor()

        super()

        self:Initialize()

    return

    method Initialize() as void

        //----------- set properties ------------

    return

    //----- Methods -----

    static method GetProdsColl() as ObservableCollection<Product>

    return ObservableCollection<Product>{GetProdsList()}

    static method GetProdsList() as List<Product>

        local aList as List<Product>

        aList := List<Product>{}

        aList:Add(Product{"Long stand 19", "Holder for long pouch 19", ;

                        "stand", 17.03, 19.73, System.DateTime{2001, 1, 1}})

        aList:Add(Product{"Short stand 19", "Holder for long pouch 19", "stand", 15.23, 17.52, System.DateTime{2003, 3, 3}})

        aList:Add(Product{"Extra long stand 19", "Holder for long pouch 19", "stand", 21.27, 24.09, System.DateTime{2002, 2, 2}})

        aList:Add(Product{"Narrow pouch 19", "Pouch 19", "bag", 1.35, 2.45, System.DateTime{2004, 4, 4}})

        aList:Add(Product{"Standard pouch 19", "Pouch 19", "bag", 1.45, 2.19, System.DateTime{2006, 6, 6}})

        aList:Add(Product{"Wide pouch 19", "Pouch 19", "bag", 1.55, 2.56, System.DateTime{2008, 8, 8}})

        aList:Add(Product{"Extra wide pouch 19", "Pouch 19", "bag", 1.65, 2.81, System.DateTime{2010, 10, 10}})

        aList:Add(Product{"Dry Storage", "Small", "box", 1.05, 1.9, System.DateTime{2005, 5, 5}})

        aList:Add(Product{"Dry Storage", "Medium", "box", 1.35, 2.08, System.DateTime{2007, 7, 7}})

        aList:Add(Product{"xxxDry Storage", "xxMedium", "xbox", 1.35, 2.08, ;

                        DateTime{2003, 4, 5}} )

    return aList

    static method GetNewProdsColl() as ObservableCollection<Product>

    return ObservableCollection<Product>{GetNewProdsList()}

    static method GetNewProdsList() as List<Product>

        local aList as List<Product>

        aList := List<Product>{}

        aList:Add(Product{})

        aList:Add(Product{})

        aList:Add(Product{})

        aList:Add(Product{})

    return aList

end class

end namespace

===================================================================================

//----- Window3ViewModel.prg  -----

//----- PHH - 21st. February 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-----------------------------------

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace WpfUCsVulcanTest

class Window3ViewModel // implements INotifyPropertyChanged

    property TestString as string Auto

    property TestDT as DateTime Auto

    property TestLogic as Boolean Auto

    property BlockString2 as string Auto

    property LabelTest3 as string Auto

    property aList as ObservableCollection<Product> Auto

    constructor(oMProds as ObservableCollection<Product>)

        super()

        self:Initialize()

        self:aList := oMProds

    return

    constructor()

        super()

        self:Initialize()

        self:aList := ObservableCollection<Product>{}

    return

    method Initialize() as void

        //----------- set properties ------------

        self:TestString := "Vulcan Victory 3!"

        self:TestDT := DateTime.Now

        self:TestLogic := true

        self:BlockString2 := "my Block Test 3"

        self:LabelTest3 := "my Label Test 3"

    return

end class

end namespace

===================================================================================

//----- Window4ViewModel.prg  -----

//----- PHH - 22nd. February 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-----------------------------------

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace WpfUCsVulcanTest

    class Window4ViewModel //implements INotifyPropertyChanged

    property Test4String as string Auto

    property Test4DT as DateTime Auto

    property Test4Logic as Boolean Auto

    property BlockString4 as string Auto

    property LabelTest4 as string Auto

    property aList4 as ObservableCollection<Product> Auto

    constructor(oMProds as ObservableCollection<Product>)

        super()

        self:Initialize()

        self:aList4 := oMProds

    return

    constructor()

        super()

        self:Initialize()

        self:aList4 := ObservableCollection<Product>{}

    return

    method Initialize() as void

        //----------- set properties ------------

        self:Test4String := "Vulcan Victory 4 !"

        self:Test4DT := DateTime.Now

        self:Test4Logic := true

        self:BlockString4 := "my Block Test 4"

        self:LabelTest4 := "my Label Test 4"

    return

end class

end namespace

===================================================================================

<Application x:Class="WpfUCsVulcanTest.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="LaunchWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

===================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE WpfUCsVulcanTest

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

===================================================================================

<Window x:Class="WpfUCsVulcanTest.LaunchWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="LaunchWindow" Height="300" Width="300" Background="DeepSkyBlue">

    <Grid>

        <Button Content="Show Window3" HorizontalAlignment="Left" Margin="24,25,0,0"

                Name="pbShowWindow3" VerticalAlignment="Top" Width="104"

                Click="pbShowWindow3_Click" Background="LightCoral"/>

        <Button Content="Show Window 4" HorizontalAlignment="Left" Margin="24,66,0,0"

                Name="pbShowWindow4" VerticalAlignment="Top" Width="104"

                Click="pbShowWindow4_Click" Background="LightGreen"/>

    </Grid>

</Window>

===================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

#using System.Collections.ObjectModel   //----- ObservableCollection .....

//----------------------------------

begin namespace WpfUCsVulcanTest

    partial class LaunchWindow inherit Window

        export oW3VM as Window3ViewModel

        export oW4VM as Window4ViewModel

        export oM34 as ObservableCollection<Product>

    constructor()

        super()

        InitializeComponent()

        //----- data injection ! -----

        self:oM34 := Models.GetProdsColl()

        self:oW3VM := Window3ViewModel{self:oM34}

        self:oW4VM := Window4ViewModel{self:oM34}

    return

    private method pbShowWindow3_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oWin3 := Window3{self:oW3VM}

        oWin3:Show()

    return

    private method pbShowWindow4_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oWin4 := Window4{self:oW4VM}

        oWin4:Show()

    return

    end class

end namespace

===================================================================================

<Window x:Class="WpfUCsVulcanTest.Window3"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window 3 - second sample :" Height="400" Width="400" Background="LightCoral">

    <Grid>

        <Grid.Resources>

            <DataTemplate x:Key="ourProdTemp">

                <StackPanel Orientation="Vertical">

                    <TextBlock Text="{Binding Name}" FontWeight="Bold"/>

                    <TextBlock Text="{Binding Description}" FontStyle="Italic"/>

                    <TextBlock Text="{Binding Price}" Foreground="OrangeRed"/>

                </StackPanel>

            </DataTemplate>

        </Grid.Resources>

        <DatePicker HorizontalAlignment="Left" Margin="26,10,0,0" Width="120"

                    SelectedDate="{Binding TestDT}" VerticalAlignment="Top" />

        <ListBox HorizontalAlignment="Left" Height="191" Margin="180,10,0,0"

                 ItemsSource="{Binding aList}" Width="202" VerticalAlignment="Top"

                 ItemTemplate="{StaticResource ResourceKey=ourProdTemp}"/>

        <TextBox HorizontalAlignment="Left" Height="23" Margin="26,241,0,0" Width="120"

                 Text="{Binding TestString}" TextWrapping="Wrap" VerticalAlignment="Top"/>

        <TextBlock HorizontalAlignment="Left" Margin="180,241,0,0" VerticalAlignment="Top"

                   Text="{Binding BlockString2}" TextWrapping="Wrap" Height="23" Width="125"/>

        <CheckBox Content="CheckBox" HorizontalAlignment="Left" VerticalAlignment="Top"

                  Margin="29,295,0,0" Height="21" Width="117"

                  IsChecked="{Binding TestLogic}"/>

        <Label Content="{Binding LabelTest3}" HorizontalAlignment="Left"

               Height="27" Width="125" Margin="180,289,0,0" VerticalAlignment="Top" />

    </Grid>

</Window>

===================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace WpfUCsVulcanTest

partial class Window3 inherit Window

    constructor(oW3VM as Window3ViewModel)

        super()

        InitializeComponent()

        //-------------------------------------

        self:DataContext := oW3VM

        //-------------------------------------

    return

end class

end namespace

===================================================================================

<Window x:Class="WpfUCsVulcanTest.Window4"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window 4 - third sample :" Height="400" Width="400" Background="LightGreen">

    <Grid>

        <Grid.Resources>

            <DataTemplate x:Key="our4ProdTemp">

                <StackPanel Orientation="Vertical">

                    <TextBox Text="{Binding Name}" FontWeight="Bold"/>

                    <TextBox Text="{Binding Description}" FontStyle="Italic"/>

                    <TextBox Text="{Binding Price}" Foreground="OrangeRed"/>

                </StackPanel>

            </DataTemplate>

        </Grid.Resources>

        <DatePicker HorizontalAlignment="Left" Margin="26,10,0,0" Width="120"

                    SelectedDate="{Binding Test4DT}" VerticalAlignment="Top" />

        <ListBox HorizontalAlignment="Left" Height="191" Margin="180,10,0,0"

                 ItemsSource="{Binding aList4}" Width="202" VerticalAlignment="Top"

                 ItemTemplate="{StaticResource ResourceKey=our4ProdTemp}"/>

        <TextBox HorizontalAlignment="Left" Height="23" Margin="26,241,0,0" Width="120"

                 Text="{Binding Test4String}" TextWrapping="Wrap" VerticalAlignment="Top"/>

        <TextBlock HorizontalAlignment="Left" Margin="180,241,0,0" VerticalAlignment="Top"

                   Text="{Binding BlockString4}" TextWrapping="Wrap" Height="23" Width="125"/>

        <CheckBox Content="CheckBox" HorizontalAlignment="Left" VerticalAlignment="Top"

                  Margin="29,295,0,0" Height="21" Width="117"

                  IsChecked="{Binding Test4Logic}"/>

        <Label Content="{Binding LabelTest4}" HorizontalAlignment="Left"

               Height="27" Width="125" Margin="180,289,0,0" VerticalAlignment="Top" />

    </Grid>

</Window>

===================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-----------------------------------------

begin namespace WpfUCsVulcanTest

    partial class Window4 inherit Window

    constructor(oW4VM as Window4ViewModel)

        super()

        InitializeComponent()

        //-------------------------------------

        self:DataContext := oW4VM

        //-------------------------------------

    return

    end class

end namespace

===================================================================================

===================================================================================

//----- Window3ViewModel.prg  -----

//----- PHH - 21st. February 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-----------------------------------

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace WpfUCsVulcanTest

class Window3ViewModel implements INotifyPropertyChanged

    //----- Fields -----

    private _testString as string

    private _testDT as DateTime

    private _testLogic as Boolean

    private _blockString2 as string

    private _labelTest3 as string

    private _aList as ObservableCollection<Product>

    //----- Properties -----

    property TestString as string

        get

            return self:_testString

        end get

        set

            self:_testString := value

            self:NotifyPropertyChanged("TestString")

        end set

    end property

    property TestDT as DateTime

        get

            return self:_testDT

        end get

        set

            self:_testDT := value

            self:NotifyPropertyChanged("TestDT")

        end set

    end property

    property TestLogic as Boolean

        get

            return self:_testLogic

        end get

        set

            self:_testLogic := value

            self:NotifyPropertyChanged("TestLogic")

        end set

    end property

    property BlockString2 as string

        get

            return self:_blockString2

        end get

        set

            self:_blockString2 := value

            self:NotifyPropertyChanged("BlockString2")

        end set

    end property

    property LabelTest3 as string

        get

            return self:_labelTest3

        end get

        set

            self:_labelTest3 := value

            self:NotifyPropertyChanged("LabelTest3")

        end set

    end property

    property aList as ObservableCollection<Product>

        get

            return self:_aList

        end get

        set

            self:_aList := value

            self:NotifyPropertyChanged("aList")

        end set

    end property

    //----- Events -----

    event PropertyChanged as PropertyChangedEventHandler

    //----- Constructors -----

    constructor(oMProds as ObservableCollection<Product>)

        super()

        self:Initialize()

        self:aList := oMProds

    return

    constructor()

        super()

        self:Initialize()

        self:aList := ObservableCollection<Product>{}

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        //----------- set properties ------------

        self:TestString := "Vulcan Victory 3!"

        self:TestDT := DateTime.Now

        self:TestLogic := true

        self:BlockString2 := "my Block Test 3"

        self:LabelTest3 := "my Label Test 3"

    return

end class

end namespace

===================================================================================

//----- Window4ViewModel.prg  -----

//----- PHH - 22nd. February 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-----------------------------------

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace WpfUCsVulcanTest

class Window4ViewModel implements INotifyPropertyChanged

    //----- Fields -----

    private _test4String as string

    private _test4DT as DateTime

    private _test4Logic as Boolean

    private _blockString4 as string

    private _labelTest4 as string

    private _aList4 as ObservableCollection<Product>

    //----- Properties -----

    property Test4String as string

        get

            return self:_test4String

        end get

        set

            self:_test4String := value

            self:NotifyPropertyChanged("Test4String")

        end set

    end property

    property Test4DT as DateTime

        get

            return self:_test4DT

        end get

        set

            self:_test4DT := value

            self:NotifyPropertyChanged("Test4DT")

        end set

    end property

    property Test4Logic as Boolean

        get

            return self:_test4Logic

        end get

        set

            self:_test4Logic := value

            self:NotifyPropertyChanged("Test4Logic")

        end set

    end property

    property BlockString4 as string

        get

            return self:_blockString4

        end get

        set

            self:_blockString4 := value

            self:NotifyPropertyChanged("BlockString4")

        end set

    end property

    property LabelTest4 as string

        get

            return self:_labelTest4

        end get

        set

            self:_labelTest4 := value

            self:NotifyPropertyChanged("LabelTest4")

        end set

    end property

    property aList4 as ObservableCollection<Product>

        get

            return self:_aList4

        end get

        set

            self:_aList4 := value

            self:NotifyPropertyChanged("aList4")

        end set

    end property

    //----- Events -----

    event PropertyChanged as PropertyChangedEventHandler

    //----- Constructors -----

    constructor(oMProds as ObservableCollection<Product>)

        super()

        self:Initialize()

        self:aList4 := oMProds

    return

    constructor()

        super()

        self:Initialize()

        self:aList4 := ObservableCollection<Product>{}

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        //----------- set properties ------------

        self:Test4String := "Vulcan Victory 4 !"

        self:Test4DT := DateTime.Now

        self:Test4Logic := true

        self:BlockString4 := "my Block Test 4"

        self:LabelTest4 := "my Label Test 4"

    return

end class

end namespace

===================================================================================

PHH - 22nd. February 2015.


Conference third sample

PHH - 22nd. February 2015.


working script and code

======================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace VL15_VM03

partial class Window1 inherit Window

    public oReg as Registration

    public oRVM as RegistrationViewModel

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

    return

    method Initialize() as void

        self:My_Main_Win:Width := 360

        self:My_Main_Win:Title := "Vulcan.Live.15 demo One :"

        self:oReg := DataModels.GetSingleRegistration2()

    return

    //----- Event Handler (button click) -----

    private method pbViewConfReg_Click( sender as System.Object, ;

                                e as System.Windows.RoutedEventArgs ) as System.Void

        self:oRVM := RegistrationViewModel{self:oReg}

        local oRV as RegistrationView

        oRV := RegistrationView{self:oRVM}

        oRV:Show()

    return

end class

end namespace

======================================================================================

<Window x:Class="VL15_VM03.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300"

    Name="My_Main_Win" Background="Bisque">

    <Grid>

        <Button Name="pbViewConfReg"

                Content="View Conf. Reg." HorizontalAlignment="Left"

                Margin="10,19,0,0" VerticalAlignment="Top"

                Width="118" Background="LightBlue"

                Click="pbViewConfReg_Click"/>

    </Grid>

</Window>

======================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE VL15_VM03

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

====================================

<Application x:Class="VL15_VM03.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

======================================================================================

//----- Registration.prg -----

//----- Monday December 8th. 2014. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM03

    class Registration implements INotifyPropertyChanged

        //----- Fields -----

        private _registrationId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        private _company as string

        private _registrationDate as System.Nullable<System.DateTime>

        private _hasPaid as System.Nullable<logic>

        private _isAlone as System.Nullable<logic>

        private _newbie as System.Nullable<logic>

        private _sessionA as logic

        private _sessionB as logic

        private _sessionC as logic

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:RegistrationId := -1

        return

        constructor(cF as string, cL as string, cCT as string, cCP as string, dtReg as System.DateTime,;

                    lP as System.Nullable<logic>, lA as System.Nullable<logic>, lN as System.Nullable<logic>,;

                    lSA as logic,lSB as logic,lSC as logic)

            super()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            self:Company := cCP

            self:RegistrationDate := System.Nullable<System.DateTime>{dtReg}

            //----------------------

            self:HasPaid := lP

            self:IsAlone := lA

            self:Newbie := lN

            //----------------------

            self:SessionA := lSA

            self:SessionB := lSB

            self:SessionC := lSC

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        //----- Properties -----

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        property Company as string

            get

                return self:_company

            end get

            set

                self:_company := value

                self:NotifyPropertyChanged("Company")

            end set

        end property

        property RegistrationDate as System.Nullable<System.DateTime>

            get

                return self:_registrationDate

            end get

            set

                self:_registrationDate := value

                self:NotifyPropertyChanged("RegistrationDate")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property IsAlone as System.Nullable<logic>

            get

                return self:_isAlone

            end get

            set

                self:_isAlone := value

                self:NotifyPropertyChanged("IsAlone")

            end set

        end property

        property Newbie as System.Nullable<logic>

            get

                return self:_newbie

            end get

            set

                self:_newbie := value

                self:NotifyPropertyChanged("Newbie")

            end set

        end property

        property SessionA as logic

            get

                return self:_sessionA

            end get

            set

                self:_sessionA := value

                self:NotifyPropertyChanged("SessionA")

            end set

        end property

        property SessionB as logic

            get

                return self:_sessionB

            end get

            set

                self:_sessionB := value

                self:NotifyPropertyChanged("SessionB")

            end set

        end property

        property SessionC as logic

            get

                return self:_sessionC

            end get

            set

                self:_sessionC := value

                self:NotifyPropertyChanged("SessionC")

            end set

        end property

    end class

end namespace //----- VL15_VM02

======================================================================================

//----- InMemDS4Registration.prg -----

//----- December 8th. 2014 -----

BEGIN NAMESPACE VL15_VM03

class DataModels

    static method GetSingleRegistration() as Registration

        local implied oReg := Registration{}

        oReg := Registration{}

        oReg:FirstName := "Dan"

        oReg:LastName := "Logan"

        oReg:Country := "Romania"

        oReg:Company := "Super Fly"

        oReg:HasPaid := true

        oReg:IsAlone := true

        oReg:Newbie := false

        oReg:RegistrationDate := DateTime.Now

        oReg:RegistrationId := 22

        oReg:SessionA := false

        oReg:SessionB := true

        oReg:SessionC := true

    return oReg

    static method GetSingleRegistration2() as Registration

        local implied oReg := Registration{"Dan","Logan","Romania",;

                    "Super Fly",DateTime.Now,true,true,false,false,true,true}

        oReg:RegistrationId := 22

    return oReg

end class

end namespace

======================================================================================

//----- RegistrationViewModel.prg -----

//----- Monday 8th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM03

class RegistrationViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _oReg3 as Registration

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        oReg3 := Registration{}

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oR as Registration)

        super()

        oReg3 := oR

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

    return

    //----- Properties -----

    property oReg3 as Registration

        get

            return self:_oReg3

        end get

        set

            self:_oReg3 := value

            self:NotifyPropertyChanged("oReg3")

        end set

    end property

end class

end namespace

======================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace VL15_VM03

partial class RegistrationView inherit Window

    public oRVM as RegistrationViewModel

    constructor()

        super()

        InitializeComponent()

        //self:oRVM := RegistrationViewModel{Registration{}}

        self:Initialize()

    return

    //----- data comes in as 'Model' object -----

    //----- later to be replaced with a 'ViewModel' object -----

    constructor(oR as RegistrationViewModel)

        super()

        InitializeComponent()

        oRVM := oR

        self:Initialize()

    return

    method Initialize() as void

        self:Title := "VL15 :- Conference Registration :"

        self:DataContext := self:oRVM

    return

end class

end namespace

======================================================================================

<Window x:Class="VL15_VM03.RegistrationView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Name="My_Conference_Registration"

    Title="ViewConfReg" Height="360" Width="440" Background="Beige">

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBox" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="CheckBox" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <Label Content="Personal Details :" HorizontalAlignment="Left"

               Margin="31,0,0,0" VerticalAlignment="Top"/>

        <TextBox Name="tbxFirst" Margin="31,26,0,0"

                 Text="{Binding Path=oReg3.FirstName, UpdateSourceTrigger=PropertyChanged}" />

        <TextBox Name="tbxLast" Margin="168,26,0,0"

                 Text="{Binding oReg3.LastName, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCountry" Margin="31,55,0,0"

                 Text="{Binding oReg3.Country, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCompany" Margin="31,83,0,0"

                 Text="{Binding oReg3.Company, UpdateSourceTrigger=PropertyChanged}"/>

        <CheckBox Name="chbxPaid" Margin="31,150,0,0"

                  Content="Has Paid :" IsChecked="{Binding oReg3.HasPaid}"/>

        <CheckBox Name="chbxAlone" Margin="31,170,0,0"

                  Content="Is Alone :" IsChecked="{Binding oReg3.IsAlone}"/>

        <CheckBox Name="chbxNewbie" Margin="31,190,0,0"

                  Content="Newbie :" IsChecked="{Binding oReg3.Newbie}"/>

        <Label Content="Session Days Attending :" HorizontalAlignment="Left" Margin="31,219,0,0"

               VerticalAlignment="Top"/>

        <CheckBox Name="chbxSessionA" Content="A :"

                  Margin="31,250,0,0" IsChecked="{Binding oReg3.SessionA}"/>

        <CheckBox Name="chbxSessionB" Content="B :"

                  Margin="31,270,0,0" IsChecked="{Binding oReg3.SessionB}"/>

        <CheckBox Name="chbxSessionC" Content="C :"

                  Margin="31,290,0,0" IsChecked="{Binding oReg3.SessionC}"/>

        <DatePicker HorizontalAlignment="Left" Margin="31,116,0,0" VerticalAlignment="Top"

                    SelectedDate="{Binding oReg3.RegistrationDate, Mode=TwoWay}"

                    DisplayDate="{Binding oReg3.RegistrationDate}"/>

        <TextBlock HorizontalAlignment="Left" Margin="168,55,0,0" TextWrapping="Wrap"

                   VerticalAlignment="Top" Width="156" Height="51" FontSize="22" FontWeight="Bold">

            <StackPanel Orientation="Horizontal" Background="AliceBlue" Width="156" Height="52">

                <TextBlock Text="{Binding oReg3.FirstName}"/>

                <TextBlock Text=" "/>

                <TextBlock Text="{Binding oReg3.LastName}"/>

            </StackPanel>

        </TextBlock>

    </Grid>

</Window>

======================================================================================

partial class Window1 inherit Window

    public oReg as Registration

    public oRVM as RegistrationViewModel

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

    return

    method Initialize() as void

        self:My_Main_Win:Width := 360

        self:My_Main_Win:Title := "Vulcan.Live.15 demo One :"

        //----- Model and ViewModel data must exist before a call to the View! -----

        self:oReg := DataModels.GetSingleRegistration2()

        self:oRVM := RegistrationViewModel{self:oReg}

    return

    //----- Event Handler (button click) -----

    private method pbViewConfReg_Click( sender as System.Object, ;

                                e as System.Windows.RoutedEventArgs ) as System.Void

        local oRV as RegistrationView

        oRV := RegistrationView{self:oRVM}

        oRV:Show()

    return

end class

==========================================================================================

======================================================================================

================================================

PHH - 9th. December 2014.


Chapter 4 - Sample four - from Data to VM to View, easy!

PHH - 8th. December 2014.


Basic fourth sample

So far we have progressed quite nicely with our improved design of Views, ViewModels, and Models.

We have seen how we need to consider all three aspects of our application design when we wish to

making Data Binding work well for us and our users.

However, we probably have not done enough as yet on how we can provide data objects for data injection

into our VM constructors.

This is particularly true when we have a bunch of collections which have most probably come from a SQL

database, and probably from some LINQ query on that DB.

Suppose we have collection data for Customers, Products, Suppliers, Sales, Contacts, that sort of stuff.

And what if we wish to provide a few of these data collections to one particular VM ?

Here below is a working example - a straightforward one, but there are many other possibilities.

Checkout the new ViewModel (VM) :-

==============================================

Ass the name suggests 'PeopleSessions' is all to do with the possible conference sessions and also the

people involved, like speakers and attendees, as well as the presentations.

Lets have a look at the structure and detail of this new more complex VM for 'PeopleSessions' :-

============================================================================================

As you can see above, we have three Constructors - one for no input parameters (empty constructor)

and a second for four parameters (one each for Session, Speaker, Attendee and Presentation).

However, we have a third Constructor overload, and this 'interesting' one takes a single input of an

object of type "PeopleSessionModel2DB". We will discuss this further in a little while, since it involves

data read in by LINQ from an Entity Framework (code first) database.

First lets look at the XAML designer details for the View which 100% corresponds with this VM :-

==============================================================================================

As you can see above, each list UI element binds to a collection of items of the types previously

discussed. Notice that the Speakers and Attendees are displayed in ListBoxes.

So how is the View for 'PeopleSessions' launched in our application ? Take a look at the next image :-

==================================================================================

As you can see on line 73 the Constructor used is the one which takes a single input parameter, not

the empty one, or the one requiring four inputs.

We also need to see how at a very early stage in our application execution process, the Model created

from the Entity Framework database query is made and instantiated.

Below check out in particular line 24 and 50 - study carefully :-

=========================================================================

If we look at the SE pane of our solution we see the new Model - check below :-

==========================================

And now we can study in turn, both the simpler Model - which uses data from a hard coded

STATIC method :-

======================================================================================

Before we move on to the more complex, and probably more real life example, of where we

supply an EF data context object using which we can query the database and get returned data

lists - check in detail below :-

======================================================================================

Code lines 33 through 40 shown above are responsible for setting the Model properties.

Now finally, we get to see the form we use as a launch Window - one option of the many

is the one we are concentrating on in this subsection - see below :-

===============================================

And in response to a button click with the mouse we see the following screen details when

the new Window (form) is shown on screen :-

======================================================================================

Notice above we have two drop lists and two ListBoxes.

Short Summary :

So to summarise, we can say that it is probably a good idea to limit the number of different input

parameters to a Constructor for a ViewModel, and this can be done by creating special Models

which have public properties corresponding to each of the objects which would have otherwise

been supplied as input parameters.

Take the time, keep it simple, organised, and tidy.

Time to move on, see you in the next subsection ........................

PHH - 23rd. February 2015.


working script and code

==============================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Full Conf. (two) :" Height="420" Width="500"

        Background="Beige">

    <Grid>

        <Grid.Resources>

            <Style TargetType="Button" >

                <Setter Property="Width" Value="133"/>

                <Setter Property="Height" Value="26"/>

                <Setter Property="FontSize" Value="13"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

            </Style>

        </Grid.Resources>

        <Button Name="pbRegistration" Content="Registration"   Margin="10,10,0,0"

                Click="pbRegistration_Click"/>

        <Button Name="pbSpeaker" Content="Speaker" Margin="10,41,0,0"

                Click="pbSpeaker_Click"/>

        <Button Name="pbSession" Content="Session"

                Margin="10,72,0,0" Click="pbSession_Click" />

        <Button Name="pbAttendee" Content="Attendee" Margin="10,103,0,0"

                Click="pbAttendee_Click"/>

        <Button Name="pbLectureRoom" Content="LectureRoom" Margin="10,134,0,0"

                Click="pbLectureRoom_Click"/>

        <Button Name="pbHotelReservation" Content="HotelReservation" Margin="10,165,0,0"

                Click="pbHotelReservation_Click"/>

        <Button Name="pbPresentation" Content="Presentation" Margin="10,196,0,0"

                Click="pbPresentation_Click"/>

        <Button Content="PeopleSessions" HorizontalAlignment="Left" Margin="10,243,0,0"

                Name="pbPeopleSessions" VerticalAlignment="Top" Width="133" Click="pbPeopleSessions_Click" />

        <Button Content="UCs Attendee" HorizontalAlignment="Left" Margin="10,295,0,0"

                Name="pbUCsAttendee" VerticalAlignment="Top" Width="133" Click="pbUCsAttendee_Click"/>

    </Grid>

</Window>

==============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class Window1 inherit Window

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

    end class

end namespace

==============================================================================

// Window1_Part2.prg

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

partial class Window1 inherit Window

    public db as ConfContext

    public oPSM2 as PeopleSessionsModel2DB

    public aListA as List<Attendee>

    public method Initialize() as void

        self:db := ConfContext{}

        if self:db:Database:Exists()

            self:db:Database:Delete() //----- no need if we use SSOE function -----

            self:db:Database:Create()

            if self:db:Database:Exists()

                SeedTables.SeedAllTables(db)

            endif

        else

            self:db:Database:Create()

            if self:db:Database:Exists()

                SeedTables.SeedAllTables(db)

            endif

        endif

       /* try

            //SeedTables.SeedAllTables(db)

        catch oEX as SystemException

            MessageBox.Show(oEX:Message,"my Main Error :")

            MessageBox.Show(oEX:InnerException:Message,"my Main Inner Error :")

        end try*/

        //-------------------------------------------

        self:oPSM2 := PeopleSessionsModel2DB{db}

        self:aListA := CS_LinqLibrary.ReturnAllAttendees(db)

    return

    private method pbUCsAttendee_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        //-----------------------------------------------------

        local implied oxAttUCs := xAttendeeUCs{}

        //oxAttUCs:DataContext := PeopleSessionsViewModel{self:oPSM2}

        oxAttUCs:Show()

        //-----------------------------------------------------

    return

    private method pbPeopleSessions_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        //-----------------------------------------------------

        local implied oPSV := PeopleSessionsView{}

        oPSV:DataContext := PeopleSessionsViewModel{self:oPSM2}

        oPSV:Show()

        //-----------------------------------------------------

    return

    private method pbRegistration_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oRegV := RegistrationView{}

        oRegV:Show()

    return

    private method pbSpeaker_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oSpkV := SpeakerView{}

        oSpkV:Show()

    return

    private method pbAttendee_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oAttV := AttendeeView{self:aListA}

        oAttV:Show()

    return

    private method pbLectureRoom_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oLectRV := LectureRoomView{}

        oLectRV:Show()

    return

    private method pbHotelReservation_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oHRV := HotelReservationView{}

        oHRV:Show()

    return

    private method pbPresentation_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oPresV := PresentationView{}

        oPresV:Show()

    return

    private method pbSession_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oSessV := SessionView{}

        oSessV:Show()

    return

end class

end namespace

==============================================================================

<Application x:Class="FullConf_VL15_Linq_EF6_2.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

==============================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE FullConf_VL15_Linq_EF6_2

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

==============================================================================

//----- PeopleSessionsModel.prg -----

//----- PHH - Saturday 10th. January 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

class PeopleSessionsModel2DB

    constructor()

        super()

        self:aSessions := List<Session>{}

        self:aSpeakers := List<Speaker>{}

        self:aPresentations := List<Presentation>{}

        self:aAttendees := List<Attendee>{}

        self:Initialize()

    return

    constructor(db as ConfContext)

        super()

        self:aSessions := CS_LinqLibrary.ReturnAllSessions(db)

        self:aSpeakers := CS_LinqLibrary.ReturnAllSpeakers(db)

        self:aPresentations := CS_LinqLibrary.ReturnAllPresentations(db)

        self:aAttendees := CS_LinqLibrary.ReturnAllAttendees(db)

        self:Initialize()

    return

    //----- Methods -----

    method Initialize() as void

    return

    //----- Properties -----

    property aSessions as List<Session> Auto

    property aSpeakers as List<Speaker> Auto

    property aPresentations as List<Presentation> Auto

    property aAttendees as List<Attendee> Auto

end class

class PeopleSessionsModel

    constructor()

        super()

        self:aSessions := List<Session>{}

        self:aSpeakers := List<Speaker>{}

        self:aPresentations := List<Presentation>{}

        self:aAttendees := List<Attendee>{}

        self:Initialize()

    return

    constructor(aSession as List<Session>, aSpk as List<Speaker>,;

                    aPres as List<Presentation>, aAtt as List<Attendee>)

        super()

        self:aSessions := aSession

        self:aSpeakers := aSpk

        self:aPresentations := aPres

        self:aAttendees := aAtt

        self:Initialize()

    return

    //----- Methods -----

    method Initialize() as void

    return

    //----- Properties -----

    property aSessions as List<Session> Auto

    property aSpeakers as List<Speaker> Auto

    property aPresentations as List<Presentation> Auto

    property aAttendees as List<Attendee> Auto

end class

end namespace

==============================================================================

//----- PeopleSessionsViewModel.prg -----

//----- Saturday 10th. January 2015. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace FullConf_VL15_Linq_EF6_2

class PeopleSessionsViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _aSessions as List<Session>

    private _aSpeakers as List<Speaker>

    private _aPresentations as List<Presentation>

    private _aAttendees as List<Attendee>

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    //----- constructors -----

    constructor()

        super()

        self:aSessions := List<Session>{}

        self:aSpeakers := List<Speaker>{}

        self:aPresentations := List<Presentation>{}

        self:aAttendees := List<Attendee>{}

        self:Initialize()

    return

    constructor(aSession as List<Session>, aSpk as List<Speaker>,;

                    aPres as List<Presentation>, aAtt as List<Attendee>)

        super()

        self:aSessions := aSession

        self:aSpeakers := aSpk

        self:aPresentations := aPres

        self:aAttendees := aAtt

        self:Initialize()

    return

    constructor(oPSM2 as PeopleSessionsModel2DB)

        super()

        self:aSessions := oPSM2:aSessions

        self:aSpeakers := oPSM2:aSpeakers

        self:aPresentations := oPSM2:aPresentations

        self:aAttendees := oPSM2:aAttendees

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

    return

    //----- Properties -----

    property aSessions as List<Session>

        get

            return self:_aSessions

        end get

        set

            self:_aSessions := value

            self:NotifyPropertyChanged("aSessions")

        end set

    end property

    property aSpeakers as List<Speaker>

        get

            return self:_aSpeakers

        end get

        set

            self:_aSpeakers := value

            self:NotifyPropertyChanged("aSpeakers")

        end set

    end property

    property aPresentations as List<Presentation>

        get

            return self:_aPresentations

        end get

        set

            self:_aPresentations := value

            self:NotifyPropertyChanged("aPresentations")

        end set

    end property

    property aAttendees as List<Attendee>

        get

            return self:_aAttendees

        end get

        set

            self:_aAttendees := value

            self:NotifyPropertyChanged("aAttendees")

        end set

    end property

end class

end namespace

==============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace FullConf_VL15_Linq_EF6_2

    partial class PeopleSessionsView inherit Window

        constructor()

            super()

            InitializeComponent()

        return

    end class

end namespace

==============================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.PeopleSessionsView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="People-Sessions - View : " Height="360" Width="500"

    Background="LightSkyBlue">

    <Grid>

        <ComboBox HorizontalAlignment="Left" Margin="30,31,0,0"

                  Name="cbxOne" VerticalAlignment="Top" Width="186"

                  ItemsSource="{Binding aSessions}" Height="26"/>

        <ComboBox HorizontalAlignment="Left" Margin="266,31,0,0"

                  Name="cbxTwo" VerticalAlignment="Top" Width="185"

                  ItemsSource="{Binding aPresentations}" Height="26"/>

        <ListBox HorizontalAlignment="Left" Height="160" Margin="31,102,0,0"

                 Name="lbxOne" VerticalAlignment="Top" Width="185"

                 ItemsSource="{Binding aSpeakers}"/>

        <ListBox HorizontalAlignment="Left" Height="160" Margin="266,102,0,0"

                 Name="lbxTwo" VerticalAlignment="Top" Width="185"

                 ItemsSource="{Binding aAttendees}"/>

    </Grid>

</Window>

==============================================================================

==============================================================================

==============================================================================

==============================================================================

==============================================================================

PHH - 23rd. February 2015.


Starting the Project

====================================================================================================

============================================================================================================================

===================================================

===================================================

===============================================================================

==================================================================================

=======================================================================

===================================================

================================================

===============================================

PHH - 9th. December 2014.


The main 'selection' window

=========================================================

=============================================

==========================================================================

====================================================================================

=================================================================================================

========================================================

PHH - 9th. December 2014.


The 'Classes' required

Before we start to think too much about our 'View' supported by the 'ViewModel' object, which in turn is

instantiated around our 'Model' objects (the data), we are often well advised to focus in detail on the

actual 'Class' object items themselves.

Yes, we need to think carefully about the classes of the custom data items we will use to instantiate

objects to then pass into our 'ViewModels' - often described as 'Data Injection' !

Remember our custom or business classes must be fully responsive to property changes, and present

Public properties for use by our other code sections.

Here below is an image of the three code files we have to support our three classes for the fourth sample

application we are creating and testing :-

============================================

Let us now move on to study each of these in detail.

Accommodation :

The 'Accommodation' class is new to us from the third sample we studied. It is a simple class which

allows us to hold some basic details about the hotel accommodation for the conference delegates.

Check out carefully the following information :-

==================================================================================================

=============================================================================================

===================================================================================

DietaryNeeds :

=============================================================================================

========================================================================================================================================

=========================================================================

============================================

Registration :

================================================================================================

==================================================================================================================================

=============================================================================

PHH - 9th. December 2014.


The data 'Models' required

Please remember that the way we are handling 'Models' in the first four sample applications (at least) is

a simple one which is 'in-memory'.

What I mean is that we as yet are not bothering ourselves with the extra complexities of back-end data servers,

although these days with EF (Entity Framework 6) and 'Code first' it is a whole lot easier than it used to be,

so don't panic - we will get there in the end.

For now lets look at a few simple classes which provide us with STATIC methods which we can use to easily

provide suitable data when we need it for providing to our ViewModels via 'Data Injection'.

First of all lets look at the two new Models for this fourth sample application of ours. First that for :-

Accommodation :

We can see below that there are two quite separate ways to do this - one using the more complex Constructor.

Check out the details carefully :-

=================================================================================================

Okay then guys, above is nothing clever, or even remotely complex - we just need get our data code correct,

so we need to take notice of what we do.

Lets now move on to another new Model - that for :-

DietaryNeeds :

Once again a simple case of instantiating a new class (in this case 'DietaryNeeds') and providing data values.

Check this out carefully :-

==============================================================================================

And once again above, we see that there are two quite separate STATIC methods in our 'Model' class, and

one uses the complex Constructor, while the other uses a very basic property assignment approach.

Lets now move on to the Model we used in previous and earlier samples :-

Registration :

We will include the following details for completion, even though we have seen them before :-

====================================================================================================

And once again we see two STATIC methods, quite separate from one another.

I generally use the '2' or second method in the rest of the test code, be you may like to try the other

out for yourself.

Lets move on ..............

See you in the next sub-section.

PHH - 9th. December 2014.


Creating the 'ViewModels'

Any 'ViewModel' generally contains none of very few actual data values.

Most (or all) of the data values should be supplied to the ViewModel via data injection.

It is acceptable to use a few local data values in the VM itself, as long as they are to support

the working of the VM, and are not for use elsewhere in the application.

Application data should be provided for by use of Model data objects, which are supplied via the

constructor to the ViewModel when it is instantiated.

Before we go any deeper into this approach (a basic MVVM pattern approach) let us look at the

details of the Solution Explorer (SE) pane we have in sample four - check below :-

==================================================

The new one to this fourth sample application is 'RegAccDietViewModel' and we can see the

PRG code file above.

If we now move on a pace or two we can see below that we can provide more complex Constructors for

us to use with the new 'VM' we are discussing - check this out :-

==================================================================================================

I will leave you to work out and test how to make Constructors which take two 'injection' objects, and

also locally instantiate a default for that not being injected.

Here is the stub of what you are needing to create :-

==========================================================================

Okay guys, lets move along - lets see how we need to handle Property changes.

VM - Responding to Change - 'Properties' :

If we look at the code at the start of the VM declaration / definition we see this below :-

=======================================================================================

Line 23 shows that we are using the same interface as we did in our Class definitions.

We need Public properties in the VM which can then bind to the UI elements in the View.

If you try to get away with not doing the notification change code thoroughly then you will make

issues and problems for yourself.

I always make my classes and my ViewModels fully responsive to Property changes, as far as

most of the Public properties are concerned.

Yes, you may have a few local VM fields and properties which you do not include in the notification

'set' but you need to be very careful, and wait till you are more experienced perhaps ;-0)

==============================================================================

========================================================================

PHH - 9th. December 2014.


Designing the 'Views'

Yes folks, this is a real 'Life Skill' ;-0)

As well as making the format of the 'View' for ease of use by the user / client, we need to also

take into account the 'shape' of the underlying data.

If we have designed our data structures right for out Tables in the back-end data source, then the

format of the data will reflect the business problems to solve as well as the tasks required to be

carried out involving the data.

So when we come to creating and designing the form / window, we need to balance up both the

requirements of the View (and user interaction) as well as the underlying data structure and format.

================================================

RegAccDietView :

===============================================================================

========================================================================================================

=====================================================================================================================================================

=======================================================================================

RegistrationView :

==============================================================================

=============================================================================================================================

=======================================================================

PHH - 9th. December 2014.


Running and Testing the application

=================================================================

===================================================================

====================================================================================

===========================================================================================================================================================

=====================================================================================================================================

PHH - 9th. December 2014.


working script and code

====================================================

=====================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace VL15_VM04

PARTIAL CLASS Window1 INHERIT Window

    export oReg as Registration

    export oAcc as Accommodation

    export oDiet as DietaryNeed

    //----------------------------------

    export oRVM as RegistrationViewModel

    export oRADVM as RegAccDietViewModel

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

    return

    method Initialize() as void

        self:My_Main_Win:Width := 360

        self:My_Main_Win:Title := "Vulcan.Live.15 demo Four :"

        //----- Model and ViewModel data must exist before a call to the View! -----

        self:oReg := DataModelsReg.GetSingleRegistration2()

        self:oRVM := RegistrationViewModel{self:oReg}

        //--------------------------------------------------------------------------

        //----- 3 Models and ViewModel data must exist before a call to the View! -----

        self:oAcc := DataModelsAcc.GetSingleAccommodation2()

        self:oDiet := DataModelsDN.GetSingleDietaryNeed2()

        self:oRADVM := RegAccDietViewModel{self:oReg, self:oAcc, self:oDiet}

    return

    //----- Event Handler (button click) -----

    private method pbViewConfReg_Click( sender as System.Object, ;

                                e as System.Windows.RoutedEventArgs ) as System.Void

        local oRV as RegistrationView

        //----- think of this as 'Data Injection' -----

        oRV := RegistrationView{self:oRVM}

        oRV:Show()

    return

    private method pbViewRegAccDiet_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local oRADV as RegAccDietView

        //----- think of this as 'Data Injection' -----

        oRADV := RegAccDietView{self:oRADVM}

        oRADV:Show()

    return

    end class

end namespace

=====================================================================================

<Window x:Class="VL15_VM04.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300"

    Name="My_Main_Win" Background="Bisque">

    <Grid>

        <Grid.Resources>

            <Style TargetType="Button">

                <Setter Property="HorizontalAlignment" Value="Left"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

                <Setter Property="Height" Value="26"/>

            </Style>

        </Grid.Resources>

        <Button Name="pbViewConfReg"

                Content="View Conf. Reg."

                Margin="10,19,0,0"

                Background="LightBlue"

                Click="pbViewConfReg_Click"/>

        <Button Name="pbViewRegAccDiet"

                Content="View RegAccDiet"

                Margin="51,57,0,0"

                Background="LightGoldenrodYellow"

                Click="pbViewRegAccDiet_Click" />

    </Grid>

</Window>

=====================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE VL15_VM04

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

=====================================================================================

<Application x:Class="VL15_VM04.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

=====================================================================================

//----- Registration.prg -----

//----- Monday December 9th. 2014. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM04

    class Registration implements INotifyPropertyChanged

        //----- Fields -----

        private _registrationId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        private _company as string

        private _registrationDate as System.Nullable<System.DateTime>

        private _hasPaid as System.Nullable<logic>

        private _isAlone as System.Nullable<logic>

        private _newbie as System.Nullable<logic>

        private _sessionA as logic

        private _sessionB as logic

        private _sessionC as logic

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:RegistrationId := -1

        return

        constructor(cF as string, cL as string, cCT as string, cCP as string, dtReg as System.DateTime,;

                    lP as System.Nullable<logic>, lA as System.Nullable<logic>, lN as System.Nullable<logic>,;

                    lSA as logic,lSB as logic,lSC as logic)

            super()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            self:Company := cCP

            self:RegistrationDate := System.Nullable<System.DateTime>{dtReg}

            //----------------------

            self:HasPaid := lP

            self:IsAlone := lA

            self:Newbie := lN

            //----------------------

            self:SessionA := lSA

            self:SessionB := lSB

            self:SessionC := lSC

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        //----- Properties -----

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        property Company as string

            get

                return self:_company

            end get

            set

                self:_company := value

                self:NotifyPropertyChanged("Company")

            end set

        end property

        property RegistrationDate as System.Nullable<System.DateTime>

            get

                return self:_registrationDate

            end get

            set

                self:_registrationDate := value

                self:NotifyPropertyChanged("RegistrationDate")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property IsAlone as System.Nullable<logic>

            get

                return self:_isAlone

            end get

            set

                self:_isAlone := value

                self:NotifyPropertyChanged("IsAlone")

            end set

        end property

        property Newbie as System.Nullable<logic>

            get

                return self:_newbie

            end get

            set

                self:_newbie := value

                self:NotifyPropertyChanged("Newbie")

            end set

        end property

        property SessionA as logic

            get

                return self:_sessionA

            end get

            set

                self:_sessionA := value

                self:NotifyPropertyChanged("SessionA")

            end set

        end property

        property SessionB as logic

            get

                return self:_sessionB

            end get

            set

                self:_sessionB := value

                self:NotifyPropertyChanged("SessionB")

            end set

        end property

        property SessionC as logic

            get

                return self:_sessionC

            end get

            set

                self:_sessionC := value

                self:NotifyPropertyChanged("SessionC")

            end set

        end property

    end class

end namespace //----- VL15_VM04

=====================================================================================

//----- DietaryNeeds.prg -----

//----- Tuesday December 9th. 2014. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM04

    class DietaryNeed implements INotifyPropertyChanged

        //----- Fields -----

        //----- all three required to have values > 0 -----

        private _dietaryId as long

        private _registrationId as long

        private _accommodationId as long

        //----- only one of three below -----

        private _isVegan as System.Nullable<logic>

        private _isVegetarian as System.Nullable<logic>

        private _isCarnivore as System.Nullable<logic>

        //----- none, any, or all of the next bunch ! -----

        private _hasBreakfast as System.Nullable<logic>

        private _hasLunch as System.Nullable<logic>

        private _hasDinner as System.Nullable<logic>

        private _isAlcoholFree as System.Nullable<logic>

        private _isDiabetic as System.Nullable<logic>

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:DietaryId := -1

        return

        constructor(nRI as long, nAI as long, ;

                    lVG as System.Nullable<logic>, lVT as System.Nullable<logic>, lCV as System.Nullable<logic>,;

                    lBK as System.Nullable<logic>, lLN as System.Nullable<logic>, lDN as System.Nullable<logic>,;

                    lAF as System.Nullable<logic>, lDB as System.Nullable<logic> )

            super()

            self:DietaryId := -1

            self:RegistrationId := nRI

            self:AccommodationId := nAI

            //---------------------------------

            self:IsVegan := lVG

            self:IsVegetarian := lVT

            self:IsCarnivore := lCV

            //----------------------

            self:HasBreakfast := lBK

            self:HasLunch := lLN

            self:HasDinner := lDN

            //----------------------

            self:IsAlcoholFree := lAF

            self:IsDiabetic := lDB

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        //----- Properties -----

        property DietaryId as long

            get

                return self:_dietaryId

            end get

            set

                self:_dietaryId := value

                self:NotifyPropertyChanged("DietaryId")

            end set

        end property

        property AccommodationId as long

            get

                return self:_accommodationId

            end get

            set

                self:_accommodationId := value

                self:NotifyPropertyChanged("AccommodationId")

            end set

        end property

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property IsVegan as System.Nullable<logic>

            get

                return self:_isVegan

            end get

            set

                self:_isVegan := value

                self:NotifyPropertyChanged("IsVegan")

            end set

        end property

        property IsVegetarian as System.Nullable<logic>

            get

                return self:_isVegetarian

            end get

            set

                self:_isVegetarian := value

                self:NotifyPropertyChanged("IsVegetarian")

            end set

        end property

        property IsCarnivore as System.Nullable<logic>

            get

                return self:_isCarnivore

            end get

            set

                self:_isCarnivore := value

                self:NotifyPropertyChanged("IsCarnivore")

            end set

        end property

        property HasBreakfast as System.Nullable<logic>

            get

                return self:_hasBreakfast

            end get

            set

                self:_hasBreakfast := value

                self:NotifyPropertyChanged("HasBreakfast")

            end set

        end property

        property HasLunch as System.Nullable<logic>

            get

                return self:_hasLunch

            end get

            set

                self:_hasLunch := value

                self:NotifyPropertyChanged("HasLunch")

            end set

        end property

        property HasDinner as System.Nullable<logic>

            get

                return self:_hasDinner

            end get

            set

                self:_hasDinner := value

                self:NotifyPropertyChanged("HasDinner")

            end set

        end property

        property IsAlcoholFree as System.Nullable<logic>

            get

                return self:_isAlcoholFree

            end get

            set

                self:_isAlcoholFree := value

                self:NotifyPropertyChanged("IsAlcoholFree")

            end set

        end property

        property IsDiabetic as System.Nullable<logic>

            get

                return self:_isDiabetic

            end get

            set

                self:_isDiabetic := value

                self:NotifyPropertyChanged("IsDiabetic")

            end set

        end property

    end class

end namespace //----- VL15_VM04

=====================================================================================

//----- Accommodation.prg -----

//----- Tuesday December 9th. 2014. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM04

    class Accommodation implements INotifyPropertyChanged

        //----- Fields -----

        private _accommodationId as long

        private _registrationId as long

        private _reservationDate as System.Nullable<System.DateTime>

        private _startDate as System.Nullable<System.DateTime>

        private _numberOfNights as int

        private _roomNumber as int

        private _hasDoubleRoom as System.Nullable<logic>

        private _hasPaid as System.Nullable<logic>

        private _totalPaid as double

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:AccommodationId := -1

        return

        constructor(nRI as int, dtRes as System.Nullable<System.DateTime>, ;

                    dtSt as System.Nullable<System.DateTime>, nN as int,;

                    nRM as int, lDR as System.Nullable<logic>,;

                    lPD as System.Nullable<logic>, nTP as double)

            super()

            self:AccommodationId := -1

            //---------------------------------

            self:RegistrationId := nRI

            SELF:ReservationDate := dtRes

            self:StartDate := dtSt

            //----------------------

            self:NumberOfNights := nN

            self:RoomNumber := nRM

            //----------------------

            self:HasDoubleRoom:= lDR

            self:HasPaid := lPD

            //----------------------

            self:TotalPaid := nTP

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        //----- Properties -----

        property AccommodationId as long

            get

                return self:_accommodationId

            end get

            set

                self:_accommodationId := value

                self:NotifyPropertyChanged("AccommodationId")

            end set

        end property

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property ReservationDate as System.Nullable<System.DateTime>

            get

                return self:_reservationDate

            end get

            set

                self:_reservationDate := value

                self:NotifyPropertyChanged("ReservationDate")

            end set

        end property

        property StartDate as System.Nullable<System.DateTime>

            get

                return self:_startDate

            end get

            set

                self:_startDate := value

                self:NotifyPropertyChanged("StartDate")

            end set

        end property

        property NumberOfNights as int

            get

                return self:_numberOfNights

            end get

            set

                self:_numberOfNights := value

                self:NotifyPropertyChanged("NumberOfNights")

            end set

        end property

        property RoomNumber as int

            get

                return self:_roomNumber

            end get

            set

                self:_roomNumber := value

                self:NotifyPropertyChanged("RoomNumber")

            end set

        end property

        property HasDoubleRoom as System.Nullable<logic>

            get

                return self:_hasDoubleRoom

            end get

            set

                self:_hasDoubleRoom := value

                self:NotifyPropertyChanged("HasDoubleRoom")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property TotalPaid as double

            get

                return self:_totalPaid

            end get

            set

                self:_totalPaid := value

                self:NotifyPropertyChanged("TotalPaid")

            end set

        end property

    end class

end namespace //----- VL15_VM04

=====================================================================================

//----- InMemDS4Registration.prg -----

//----- December 8th. 2014 -----

BEGIN NAMESPACE VL15_VM04

class DataModelsReg

    static method GetSingleRegistration() as Registration

        local implied oReg := Registration{}

        //oReg := Registration{}

        oReg:FirstName := "Dan"

        oReg:LastName := "Logan"

        oReg:Country := "Romania"

        oReg:Company := "Super Fly"

        oReg:HasPaid := true

        oReg:IsAlone := true

        oReg:Newbie := false

        oReg:RegistrationDate := DateTime.Now

        oReg:RegistrationId := 22

        oReg:SessionA := false

        oReg:SessionB := true

        oReg:SessionC := true

    return oReg

    static method GetSingleRegistration2() as Registration

        local implied oReg := Registration{"Dan","Logan","Romania",;

                    "Super Fly",DateTime.Now,true,true,false,false,true,true}

        oReg:RegistrationId := 22

    return oReg

end class

end namespace

=====================================================================================

//----- InMemDS4DietartNeed.prg -----

//----- December 9th. 2014 -----

BEGIN NAMESPACE VL15_VM04

class DataModelsDN

    static method GetSingleDietaryNeed() as DietaryNeed

        local implied oDN := DietaryNeed{}

        oDN:DietaryId := -1

        oDN:RegistrationId := 22

        oDN:AccommodationId := 1234

        oDN:IsVegan := false

        oDN:IsVegetarian := false

        oDN:IsCarnivore := true

        oDN:HasBreakfast := true

        oDN:HasLunch := true

        oDN:HasDinner := true

        oDN:IsAlcoholFree := false

        oDN:IsDiabetic := false

    return oDN

    static method GetSingleDietaryNeed2() as DietaryNeed

        local implied oDN := DietaryNeed{22,1234,false, false, true,;

                                          true, true, true, false, false}

        oDN:DietaryId := -1

    return oDN

end class

end namespace

=====================================================================================

//----- InMemDS4Accommodation.prg -----

//----- December 9th. 2014 -----

BEGIN NAMESPACE VL15_VM04

class DataModelsAcc

    static method GetSingleAccommodation() as Accommodation

        local implied oAcc := Accommodation{}

        oAcc:AccommodationId := -1 //----- just to be sure ! -----

        //--------------------------------------------------------

        oAcc:RegistrationId := 22

        oAcc:ReservationDate := DateTime{2015,03,13}

        oAcc:StartDate := DateTime{2015,04,19}

        oAcc:NumberOfNights := 3

        oAcc:RoomNumber := 135

        oAcc:HasDoubleRoom := false

        oAcc:HasPaid := true

        oAcc:TotalPaid := 234

    return oAcc

    static method GetSingleAccommodation2() as Accommodation

        local implied oAcc := Accommodation{22,DateTime{2015,03,13},;

                                DateTime{2015,04,19},3,135,false,true,234}

        oAcc:AccommodationId := -1 //----- just to be sure ! -----

    return oAcc

end class

end namespace

=====================================================================================

//----- RegistrationViewModel.prg -----

//----- Monday 8th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM04

class RegistrationViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _oReg4 as Registration

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        oReg4 := Registration{}

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oR as Registration)

        super()

        oReg4 := oR

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

    return

    //----- Properties -----

    property oReg4 as Registration

        get

            return self:_oReg4

        end get

        set

            self:_oReg4 := value

            self:NotifyPropertyChanged("oReg4")

        end set

    end property

end class

end namespace

=====================================================================================

//----- RegAccDietViewModel.prg -----

//----- Monday 9th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_VM04

class RegAccDietViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _oReg4 as Registration

    private _oAcc4 as Accommodation

    private _oDiet4 as DietaryNeed

    //-----------------------------

    private _windowTitle as string

    private _runTime as DateTime

    private _developer as string

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        oReg4 := Registration{}

        oAcc4 := Accommodation{}

        oDiet4 := DietaryNeed{}

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oR as Registration, oA as Accommodation, oD as DietaryNeed)

        super()

        oReg4 := oR

        oAcc4 := oA

        oDiet4 := oD

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:WindowTitle := "Multiple Model Injections :"

        self:Developer := "Philip H. Hepburn"

        self:RunTime := DateTime.Now

    return

    //----- Properties -----

    property oReg4 as Registration

        get

            return self:_oReg4

        end get

        set

            self:_oReg4 := value

            self:NotifyPropertyChanged("oReg4")

        end set

    end property

    property oAcc4 as Accommodation

        get

            return self:_oAcc4

        end get

        set

            self:_oAcc4 := value

            self:NotifyPropertyChanged("oAcc4")

        end set

    end property

    property oDiet4 as DietaryNeed

        get

            return self:_oDiet4

        end get

        set

            self:_oDiet4 := value

            self:NotifyPropertyChanged("oDiet4")

        end set

    end property

    property Developer as string

        get

            return self:_developer

        end get

        set

            self:_developer := value

            self:NotifyPropertyChanged("Developer")

        end set

    end property

    property WindowTitle as string

        get

            return self:_windowTitle

        end get

        set

            self:_windowTitle := value

            self:NotifyPropertyChanged("WindowTitle")

        end set

    end property

    property RunTime as DateTime

        get

            return self:_runTime

        end get

        set

            self:_runTime := value

            self:NotifyPropertyChanged("RunTime")

        end set

    end property

end class

end namespace

=====================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace VL15_VM04

partial class RegistrationView inherit Window

    public oRVM as RegistrationViewModel

    //----- data comes in as a 'ViewModel' object -----

    constructor(oR as RegistrationViewModel)

        super()

        InitializeComponent()

        oRVM := oR

        self:Initialize()

    return

    method Initialize() as void

        self:Title := "VL15 :- Conference Registration :"

        self:DataContext := self:oRVM

    return

end class

end namespace

=====================================================================================

<Window x:Class="VL15_VM04.RegistrationView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Name="My_Conference_Registration"

    Title="ViewConfReg" Height="360" Width="440" Background="Beige">

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBox" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="CheckBox" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <Label Content="Personal Details :" HorizontalAlignment="Left"

               Margin="31,0,0,0" VerticalAlignment="Top"/>

        <TextBox Name="tbxFirst" Margin="31,26,0,0"

                 Text="{Binding Path=oReg4.FirstName, UpdateSourceTrigger=PropertyChanged}" />

        <TextBox Name="tbxLast" Margin="168,26,0,0"

                 Text="{Binding oReg4.LastName, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCountry" Margin="31,55,0,0"

                 Text="{Binding oReg4.Country, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCompany" Margin="31,83,0,0"

                 Text="{Binding oReg4.Company, UpdateSourceTrigger=PropertyChanged}"/>

        <CheckBox Name="chbxPaid" Margin="31,150,0,0"

                  Content="Has Paid :" IsChecked="{Binding oReg4.HasPaid}"/>

        <CheckBox Name="chbxAlone" Margin="31,170,0,0"

                  Content="Is Alone :" IsChecked="{Binding oReg4.IsAlone}"/>

        <CheckBox Name="chbxNewbie" Margin="31,190,0,0"

                  Content="Newbie :" IsChecked="{Binding oReg4.Newbie}"/>

        <DatePicker HorizontalAlignment="Left" Margin="31,116,0,0" VerticalAlignment="Top"

                    SelectedDate="{Binding oReg4.RegistrationDate, Mode=TwoWay}"

                    DisplayDate="{Binding oReg4.RegistrationDate}"/>

    </Grid>

</Window>

=====================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace VL15_VM04

partial class RegAccDietView inherit Window

    public oRADVM as RegAccDietViewModel

    //----- All data comes in as a 'ViewModel' object -----

    constructor(oR as RegAccDietViewModel)

        super()

        InitializeComponent()

        oRADVM := oR

        self:Initialize()

    return

    method Initialize() as void

        self:Title := "VL15 :- Conference Registration :"

        self:DataContext := self:oRADVM

    return

end class

end namespace

=====================================================================================

<Window x:Class="VL15_VM04.RegAccDietView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="RegAccDiet" Height="320" Width="600"

        Background="LightBlue">

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBox" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="CheckBox" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

            <Style TargetType="DatePicker" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

            <Style TargetType="Label" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

                <Setter Property="FontWeight" Value="Bold"/>

                <Setter Property="FontSize" Value="16"/>

            </Style>

        </Grid.Resources>

        <Label Content="Personal Details :"

               Margin="31,0,0,0"/>

        <TextBox Name="tbxFirst" Margin="31,54,0,0"

                 Text="{Binding Path=oReg4.FirstName, UpdateSourceTrigger=PropertyChanged}" />

        <TextBox Name="tbxLast" Margin="31,26,0,0"

                 Text="{Binding oReg4.LastName, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCountry" Margin="31,82,0,0"

                 Text="{Binding oReg4.Country, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Name="tbxCompany" Margin="31,110,0,0"

                 Text="{Binding oReg4.Company, UpdateSourceTrigger=PropertyChanged}"/>

        <CheckBox Name="chbxPaid" Margin="31,181,0,0"

                  Content="Has Paid :" IsChecked="{Binding oReg4.HasPaid}"/>

        <CheckBox Name="chbxAlone" Margin="31,201,0,0"

                  Content="Is Alone :" IsChecked="{Binding oReg4.IsAlone}"/>

        <CheckBox Name="chbxNewbie" Margin="31,221,0,0"

                  Content="Newbie :" IsChecked="{Binding oReg4.Newbie}"/>

        <DatePicker HorizontalAlignment="Left" Margin="31,147,0,0" VerticalAlignment="Top"

                    SelectedDate="{Binding oReg4.RegistrationDate, Mode=TwoWay}"

                    DisplayDate="{Binding oReg4.RegistrationDate}"/>

        <!-- ============================================================================ -->

        <TextBox Margin="218,26,0,0" Text="{Binding oAcc4.RegistrationId, UpdateSourceTrigger=PropertyChanged}" Width="61"/>

        <TextBox Margin="218,54,0,0" Text="{Binding oAcc4.AccommodationId, UpdateSourceTrigger=PropertyChanged}" Width="61"/>

        <DatePicker Margin="218,82,0,0" SelectedDate="{Binding oAcc4.ReservationDate}" DisplayDate="{Binding oAcc4.ReservationDate}"/>

        <DatePicker Margin="218,111,0,0" SelectedDate="{Binding oAcc4.StartDate}" DisplayDate="{Binding oAcc4.ReservationDate}"/>

        <TextBox Margin="218,144,0,0" Text="{Binding oAcc4.NumberOfNights, UpdateSourceTrigger=PropertyChanged}" Width="42"/>

        <TextBox Margin="218,172,0,0" Text="{Binding oAcc4.RoomNumber, UpdateSourceTrigger=PropertyChanged}" Width="42"/>

        <TextBox Margin="218,200,0,0" Text="{Binding oAcc4.TotalPaid, UpdateSourceTrigger=PropertyChanged}" Width="42"/>

        <CheckBox Content="Has double room :" Margin="218,228,0,0" IsChecked="{Binding oAcc4.HasDoubleRoom}"/>

        <CheckBox Content="Has paid :" Margin="218,248,0,0" IsChecked="{Binding oAcc4.HasPaid}"/>

        <!-- ================================================================================================================= -->

        <CheckBox Content="Breakfast :" Margin="393,155,0,0" IsChecked="{Binding oDiet4.HasBreakfast}"/>

        <CheckBox Content="Lunch :" Margin="393,175,0,0" IsChecked="{Binding oDiet4.HasLunch}"/>

        <CheckBox Content="Dinner :" Margin="393,195,0,0" IsChecked="{Binding oDiet4.HasDinner}"/>

        <CheckBox Content="Alcohol free :" Margin="393,215,0,0" IsChecked="{Binding oDiet4.IsAlcoholFree}"/>

        <CheckBox Content="Diabetic :" Margin="393,235,0,0" IsChecked="{Binding oDiet4.IsDiabetic}"/>

        <Label Content="Accommodation :" Margin="218,0,0,0"/>

        <Label Content="Dietary Needs :" Margin="393,121,0,0"/>

    </Grid>

</Window>

=====================================================================================

=====================================================================================

PHH - 9th. December 2014.


Chapter 5 - Sample five - a list of 'Custom' items in a View

=================================

=======================================

===============================================================

====================================================================================================

=============================================================

PHH - 8th. & 12th. December 2014.


Starting the Project

Okay you guys, lets make this chapter a good one !

Lets start off by closing everything down that is open in Visual Studio 2013 (update 4) and

starting a brand new one entitled "VL15_Lists_Of_All_Sorts".

Then as we add to our work on lists and collections we can add extra projects to this, and/or

even extra Views (Windows) to the same Solution / Project.

=============================================================================================

===================================================================

==============================================================================================================================

[ .. Whoops ! - I have named the Project what I wanted only the Solution to be called - we will have to do a 'rename' later .. ]

And after adding the solution and project to Source Control we have the following in the SE pane :-

===========================================================

======================================================================

=========================================================

=========================================================

===========================================================

================================================================================================

=========================================================================================

========================================================================================

=========================================================================

PHH -12th. December 2014.


Adding 'Project/Solution' to Source Control

==================================================================================================================================

================================================================================================

==========================================================================================

=================================================================

==================================================

=============================================

==================================================

==============================================================================================

==================================================

======================================================================================================================

===========================================================

=============================================================

=====================================================

===========================================================

=====================================================================

============================================================

===========================================================

===============================================

PHH -12th. December 2014.


Adding the extra folders for 'Views' and stuff

=====================================================================================================

========================================================

PHH -12th. December 2014.


Adding an Image folder and photo files

=================================================

========================================

============================================================================================

====================================================================================================================================================================

=============================================================

PHH -14th. December 2014.


Getting our Classes and Enums together

=========================================================================================

==================================================================================================================

========================================

======================================

PHH -13th. December 2014.


Required 'enum's for Class use

====================================================================================

==============================================================================================================

=============================================

============================================================

PHH -13th. December 2014.


Improved version of 'DietaryNeed'

PHH -13th. December 2014.


Improved version of 'Accommodation'

PHH -13th. December 2014.


Improved version of 'Registration'

PHH -13th. December 2014.


Making a data Collection

When we require lists of custom items, or business items, there are two .NET classes we need to

use to give us all the functionality we could ever need.

These are typed lists ... List<T> ... and type observable collections ... OberservableCollection<T> ....

The later can even be easily made for an object of the former - an 'OC' made from a List<T>. We shall

see this in action later in this subsection.

Meanwhile we had better study what we already have for our class 'Registration' - just for a single 'item'.

Check out the following image details - thoroughly :-

===============================================================================================

[ .. both of the above STATIC method return a full single class 'item' - both work equally well .. ]

The following collapsed view of the code may help us get our head around it :-

======================================================================================

Notice for the second STATIC method I have had to make a change (or correction really) to the class Constructor.

The change Constructor for 'Registration' now looks like the following :-

=============================================================================================================================================

Yes, in order to make the Constructor accept 'null' dates (DateTime) we added the 'dtReg' highlighted text on line 35.

And the next image shows how we pass this into the property assignments :-

===============================================================================================================================

Okay folks, lets move on to 'Collections', and how to make them from our single 'items'.

Collections - making some Suitable ones for List based UI elements :

We only need to deal in two different classes of list based objects, in order to be able to access all Data Binding responsiveness.

Below you will see us using 'List<Registration>' as well as 'ObservableCollection<Registration>'.

To start with study below lines 43 through 58 - the STATIC method returns a List of registration objects, or items :-

================================================================================================================================================

Basically, in the code above (when the code is run) we have instantiated four objects of type 'Registration' and

added them to a typed List.

This means that the List object only holds items of type 'Registration'. This List is suitable for binding to many

list UI elements, as long as the items themselves do not change - Added or Removed etc..

When we do need our item list object to keep track of list changes then we need to make it of type 'ObservableCollection'

(OC) as this type tracks changes in the list, or 'Collection'.

In the above image study carefully lines 40 & 41. The List from line 58 is being used to instantiate the 'OC'.

Moving on .................

We now need to go to the next subsection on "Creating Models", as it is in the Models that we will make

most use of the STATIC classes discussed above.

'Models' are the things we are after, but 'Collections' are what the 'Models' really are. 'Model' is a general 'descriptive'

terminology the other 'Collection' is more because that is what they 'are' !

See you in the next section ...................

PHH -12th. & 13th. December 2014.


Creating Models based on Collections

Remember that 'Models' are basically 'usable data' !

We supply one or more Models to our ViewModel objects when we instantiate them - called 'injection'.

All the data (or most of it) which is shown on the UI element display in our View is actually in the Model.

So for us generally, when we see a list of items in a list element, we are looking directly at the original

collection of items, assembled to make the Model in the first place.

VERY often in our Views we need to display lists of custom items, we call these 'Collections' whether they

are List<T> or indeed ObservableCollection<T>.

As long as we define our class (or the items) correctly, and handle 'notification' changes, then data binding

will work as expected for properties within the collection items.

If we are requiring in our View display a collection which can grow, shrink and change (item by item) then we

need to use the 'ObservableCollection' type as this has in-built functionality to track item changes - that

is the items themselves, not the item properties.

Lets get busy and make a Model file under the 'c_Models' folder.

Highlight the node in the SE pane for Models, then bring up the Context Menu as seen below :-

===================================================================================================

Add a new item of type 'Code File' - as seen in the following image :-

=============================================================================================================

And because we are not getting our data (yet) from a back-end data store, name the file "InMemDS4Registration".

This reads as ... in memory data set for Registration items ....

Here is what I now have in my VS IDE :-

==========================================

I will now copy the code from a previous demo application (sample four) into the new empty 'stub' of a file.

Here is what I have - you can get the code from the later subsection "working script and code" - check this :-

=================================================================================================

Collapse the code sections to see a much simpler scree display :-

========================================================================================

Remember that I have made a necessary change to the Constructor in the class definition for 'Registration' - check below :-

=============================================================================================================================================

And now we can view once again the STATIC methods we saw in the last subsection - these are for 'Registration'.

VERY soon we will be making new ones for the other two classes we are using, so make sure you fully understand

what it is we are doing.

Check out in detail lines 40 through 58 - and see that the empty Window shows the code compiles and runs - not pretty, but it runs !

=========================================================================================================================================================

In the above code we also see the way to handle 'null's for dates (DateTime) and so if we can do this we

can easily adapt our code to handle 'nulls' for other types too.

Making 'Collections' for classes 'Accommodation and 'DietaryNeeds' :

I think it will be a good idea to move on into some child sections from here, so that stuff does not get

to long and complicated etc.

See you in the first child section for 'DietartyNeed' .........................

PHH -12th. December 2014.


Collections for Model based on 'DietaryNeed'

PHH -13th. December 2014.


Creating a ViewModel to display Collections

PHH -12th. December 2014.


Creating the main 'Window1' form

===============================================

==========================================================================================================

=======================================================

==========================================================================================================================

============================================================================================================================

=====================================================================================================================================

==================================================================

PHH -13th. December 2014.


Making our 'Views' - and tidy scripting !?

========================================================================================================

===========================================================================================================

===========================================================

====================================================================

=============================================================

PHH -13th. December 2014.


placing Resources in the App.xaml file

========================================================================================

=================================================================================

As yet we still need to add Styles for the list / collection related GUI Tools / classes.

Look out for these later - ListBox, ComboBox, DataGrid etc..

PHH -13th. December 2014.


Trying out our first List display

Please note that the following image shows a 'quick' way to allow us to bind a collection object

to a list UI element.

In later subsections we will return to the proper ViewModel approach, where the collection object will

be a Public property on the VM class we define.

For now just check out the following details :-

=============================================================================================================================================

And when we compile and run the application, and then from the main window select the ListBox push button,

we see the following on our monitor / screen :-

====================================================================================================

Note in line 9, because we are assigning to the DataContext property / attribute, the complete list/collection

object itself, we only need to specify 'binding' with no qualifier.

When we use a VM object and the collection is a public property, then we will need to qualify with something

like 'Path=oRegColl'.

A little tip or trick !? :

Well, you saw the ugly output in the above image, this comes about when we do nothing but bind the

list collection and show the form.

If we write an extra little 'ToString()' method in our class which is that of the items in the list, then we get

the following - a big improvement I feel ;-0)

============================================================

Let us now move on to the next subsection (from this child section) to see how easily we

can further improve our listed display of collection items, using DataTemplates.

See you there ............

PHH -13th. December 2014.


What is a DataTemplate, how is it used ?

=================================================================================================================================================

===================================================================================================================

===========================================================================================================================================================

PHH -12th. December 2014.


Improving our ListBox View display

Okay then guys, we are getting to the more exciting parts of Data Binding, WPF form design, and

also XAML scripting.

The wonderful things we can do with Collections of Custom objects and list UI elements, as well as

data grid UI elements, is just fantastic. I really enjoy the challenge, and the success.

Here is where we started, when we bound our first 'OC' ObservableCollection object to the WPF window.

Remember how 'yucky' it was ? - see below :-

===============================================

The only useful thing in the above image is that we can see that we have four list elements,

or four items in our collection.

Then by simply adding a suitable 'ToString' method to the collection item class we got the following display :-

==============================================

Better, "but still no cigar" ;-0))

Well then, lets take a look at what we can display instead, once we know how to use a little

XAML script - slightly more advanced but certainly NOT complex or complicated - check this out :-

==============================================================

Yes, this time we have three public properties from the items in the bound collection (bound

to the ListBox) - and the collection is a property of the ViewModel which itself is loosely coupled

to the 'View' form itself.

Let us start to check out some of this by looking in detail to the next image - see below :-

[ .. study in particular lines 11 through 22 .. ]

==================================================================================================================================

Yes, instead of using the 'ToString()' method the WPF/XAML system is using the defined 'DataTemplate' object to

layout in the UI just what we wish to see.

The beauty of a 'DataTemplate' is that it is so VERY flexible - we seem to be able to do anything.

The most obvious thing is that we can construct a visual element for the collection item, but the element

itself can be composed of many bound items, of different type, and displayed in a variety of ways.

Lets move on a step further ....

A simple Alternative :

Before we get too heavily involved in the 'display' fun, let us check out a simple alternative, shown above

on line 23. If we just need one property displayed then we can specify a 'DisplayMemberPath' attribute property

from the collection item.

==================================================================================================

Yes, the above works OK, but I always seem to use a 'DataTemplate' myself - as they are so easy to set-up and use.

It the above script for the 'DataTemplate', we see lines 15,16, & 17 look a bit clumsy in some respects, and

the next sample image (see below) is probably a better syntax alternative.

Check these details - the new script is for the second ListBox on the RHS (right) :-

=============================================================

Here is the alternative syntax :-

[ .. checkout lines 35 through 37 .. ]

====================================================================================================================

With 'Run' we can compose a wide variety of data types as well as images.

More on this in later Chapters and Sections.

Lets add a bit more variety in our output, and change the second ListBox to show the property 'Company'

in place of 'Country' and add a touch of green as well ;-)

=====================================================================================================

Lets now goo a little further and look at editing, or changing, the values of the bound Public properties.

TextBox vs TextBlock - getting the most from both :

Okay folks, this is both easy and MOST effective. If we use a TextBlock element then we can't edit the content.

However, if we use a TextBox element then we are able to edit and make changes.

In the following image see how the first ListBox is now editable, and how the second ones shows all changes.

Study the following image details VERY carefully :-

=====================================================================================================================================================

In the above image I have edited the first names - but the last one has not had its changed value

shown in the RHS simply because the UI element is still in focus.

First lets make a change to allow Franks detail to be fully displayed - correctly :-

=================================================================================================

And now lets make a change on line 15 so that changes in the TextBlock are seen as soon as they are made in the TextBlocks

of the LHS (left) ListBox.

Check below carefully :-

=======================================================================================================================

Setting the 'Width' attribute to 'Auto' is a handy tip when doing 'DataTemplate' work.

Short Summary :

Well, it would seem as though our data binding and our data displayed in templates is working OK.

However, one thing we must try to checkout is can we see changes when we have more than one similar

'View' - when we have two or three Views called 'ListBoxView' !?

We need to try it - now !

====================================================================================================================================================

Yep! - it seems to work fine in all three test windows, as long as I change the launching code

to that which is seen below - so as the data in Model and ViewModel is not local to the calling

event handler.

Check this out and then give yourself a break ;-0)

=========================================================================================

PLEASE be aware that there are many things still to be discussed which can greatly add to the

look and feel of interesting and very functional item display for UI list elements, so keep watching

and reading!

See the subsection the one after next, entitled "Designing / Making more complex DataTemplates".

See you in the next sub-section ..............

PHH -13th. & 14th. December 2014.


Empty 'Constructors' better to define them !

Somewhere in these eNotes I will have told you (at least once) that my style of coding is to always

provide an empty 'Constructor' to all of my classes.

I have found that I get less unforeseen issues from the compiler and parser if I provide a Constructor

which take zero parameters (none).

Here is an example of what can happen without us realising there was any issue at all.

Here is what looks like a perfectly good bit of code, to define a 'View' class (or window).

Check it out carefully :-

======================================================================================

And if we look at the accompanying XAML file, shown below in the XAML editor, we see a blue

wavy line under the leading tag for 'Window'.

As you can see below, the tooltip when we hover the mouse over the wavy area tells us what is wrong.

Look at the details thoroughly :-

============================================================================================================================================================

Yes ! - 'parameterless' is their way of saying my 'empty' phrase ;-0)

So lets put this right - check below to see what I added :-

=====================================================================================================

Okay guys, then why is this ?

All I can say is that sometimes, in some code sections the 'system' needs to be able to serialize objects,

and one stipulation of serialization is that there exists in the class to be serialized a 'parameterless'

Constructor.

Whether this is the case her I can't say - I just do it as a matter of my personal 'code style'.

However, if you do supply 'empty' Constructors then you need to make sure that they would work OK when

called, so you may need to further adjust your style of coding to make things robust !

Lets move on to the next subsection - see you there ..................

PHH -14th. December 2014.


working code and script for improvements

============================================================================

[ .. alternative code in the next lined section .. ]

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//=======================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

    partial class Window1 inherit Window

        constructor()

          super()

          InitializeComponent()

        return

        private method pbMainListBox_Click( sender as System.Object, e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinLB as ListBoxView

            local oOCcheck as ObservableCollection<Registration>

            oOCcheck := DataModels.GetRegistrationCollection()

            oWinLB := ListBoxView{ListsThreeViewModel{oOCcheck}}  //----- Data Injection -----

            oWinLB:Show()

        return

        private method pbMainComboBox_Click( sender as System.Object, e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinCB as ComboBoxView

            oWinCB := ComboBoxView{}

            oWinCB:Show()

        return

        private method pbMainDataGrid_Click( sender as System.Object, e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinDGmV as DataGrid_myView

            oWinDGmV := DataGrid_myView{}

            oWinDGmV:Show()

        return

    end class

end namespace

============================================================================

[ .. alternative and more advanced way to share bound data .. ]

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//=======================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

    partial class Window1 inherit Window

        public oWinLB as ListBoxView

        public oOCcheck as ObservableCollection<Registration>

        public oLTVM as ListsThreeViewModel

        constructor()

          super()

          InitializeComponent()

          self:Initialize()

        return

        method Initialize() as void

            oOCcheck := DataModels.GetRegistrationCollection()

            oLTVM := ListsThreeViewModel{oOCcheck}

        return

        private method pbMainListBox_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

            oWinLB := ListBoxView{self:oLTVM}  //----- Data Injection -----

            oWinLB:Show()

        return

        private method pbMainComboBox_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinCB as ComboBoxView

            oWinCB := ComboBoxView{}

            oWinCB:Show()

        return

        private method pbMainDataGrid_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinDGmV as DataGrid_myView

            oWinDGmV := DataGrid_myView{}

            oWinDGmV:Show()

        return

    end class

end namespace

============================================================================

<Window x:Class="VL15_Lists_01.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Lists and Collections :" Height="300" Width="300" Background="BurlyWood">

    <Grid>

        <Button Name="pbMainListBox" Content="ListBox" Margin="10,10,162,223" Click="pbMainListBox_Click"/>

        <Button Name="pbMainComboBox" Content="ComboBox" Margin="10,51,162,182" Click="pbMainComboBox_Click"/>

        <Button Name="pbMainDataGrid" Content="DataGrid" Margin="10,92,162,141" Click="pbMainDataGrid_Click"/>

    </Grid>

</Window>

============================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

begin namespace VL15_Lists_Of_All_Sorts

   partial class App inherit Application

   end class

end namespace

=========================================

============================================================================

[ .. later (below) there is a Resources file including DataTemplates .. ]

<Application x:Class="VL15_Lists_Of_All_Sorts.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

        <Style TargetType="TextBlock" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="RadioButton" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Button" >

            <Setter Property="VerticalAlignment" Value="Stretch"/>

            <Setter Property="HorizontalAlignment" Value="Stretch"/>

            <Setter Property="Height" Value="Auto"/>

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Background" Value="Yellow"  />

            <Setter Property="VerticalContentAlignment" Value="Center"/>

            <Setter Property="HorizontalContentAlignment" Value="Center"/>

            <Setter Property="Width" Value="120"/>

            <Setter Property="Height" Value="36"/>

        </Style>

        <Style TargetType="TextBox" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

        </Style>

        <Style TargetType="CheckBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="DatePicker" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Label" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="FontSize" Value="16"/>

        </Style>

    </Application.Resources>

</Application>

============================================================================

//----- a_MyEnums.prg -----

//----- PHH - 1th. December 2014. -----

begin namespace VL15_Lists_01

    public enum FoodPreference

        Vegan

        Vegetarian

        Carnivore

        FishOnly

    end

    public enum HotelAccommodation

        Single

        Double

        Suite

        None

    end

    public enum SessionsAttending

        All

        AB

        AC

        BC

        None

    end

end  namespace

============================================================================

//----- Registration.prg -----

//----- Monday December 8th. 2014. copied December 12th. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_Lists_01

    class Registration implements INotifyPropertyChanged

        //----- Fields -----

        private _registrationId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        private _company as string

        private _registrationDate as System.Nullable<System.DateTime>

        private _hasPaid as System.Nullable<logic>

        private _isAlone as System.Nullable<logic>

        private _newbie as System.Nullable<logic>

        private _eSessions as SessionsAttending

        private _photoImage as string

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:RegistrationId := -1

        return

        constructor(cF as string, cL as string, cCT as string, cCP as string, dtReg as System.Nullable<System.DateTime>,;

                    lP as System.Nullable<logic>, lA as System.Nullable<logic>, lN as System.Nullable<logic>,;

                    eS as SessionsAttending, cPhotoImg as string)

            super()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            self:Company := cCP

            self:RegistrationDate := dtReg

            //----------------------

            self:HasPaid := lP

            self:IsAlone := lA

            self:Newbie := lN

            //----------------------

            self:eSessions := eS

            self:PhotoImage := cPhotoImg

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return self:FirstName+" "+self:LastName

        //----- Properties -----

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        property Company as string

            get

                return self:_company

            end get

            set

                self:_company := value

                self:NotifyPropertyChanged("Company")

            end set

        end property

        property RegistrationDate as System.Nullable<System.DateTime>

            get

                return self:_registrationDate

            end get

            set

                self:_registrationDate := value

                self:NotifyPropertyChanged("RegistrationDate")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property IsAlone as System.Nullable<logic>

            get

                return self:_isAlone

            end get

            set

                self:_isAlone := value

                self:NotifyPropertyChanged("IsAlone")

            end set

        end property

        property Newbie as System.Nullable<logic>

            get

                return self:_newbie

            end get

            set

                self:_newbie := value

                self:NotifyPropertyChanged("Newbie")

            end set

        end property

        //-----------------------------------------------

        property eSessions as SessionsAttending

            get

                return self:_eSessions

            end get

            set

                self:_eSessions := value

                self:NotifyPropertyChanged("eSessions")

            end set

        end property

        property PhotoImage as string

            get

                return self:_photoImage

            end get

            set

                self:_photoImage := value

                self:NotifyPropertyChanged("PhotoImage")

            end set

        end property

        //-----------------------------------------------

    end class

end namespace //----- VL15_VM02

============================================================================

//----- InMemDS4Registration.prg -----

//----- December 8th. 2014 -----

#using System

#using System.Collections.Generic

#using System.Windows

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

class DataModels

    static method GetSingleRegistration() as Registration

        local implied oReg := Registration{}

        oReg := Registration{}

        oReg:FirstName := "Dan"

        oReg:LastName := "Logan"

        oReg:Country := "Romania"

        oReg:Company := "Super Fly"

        oReg:HasPaid := true

        oReg:IsAlone := true

        oReg:Newbie := false

        oReg:RegistrationDate := DateTime.Now

        oReg:RegistrationId := 22

        oReg:eSessions := SessionsAttending.All

        oReg:PhotoImage := "..."

    return oReg

    static method GetSingleRegistration2() as Registration

        local implied oReg := Registration{"Dan","Logan","Romania",;

                    "Super Fly",DateTime.Now,true,true,false,SessionsAttending.All,"DanLogan.jpg"}

        oReg:RegistrationId := 22

    return oReg

    //===============================================================================================

    static method GetRegistrationCollection() as ObservableCollection<Registration>

    return ObservableCollection<Registration>{GetaBunchOfRegistrations()}

    static method GetaBunchOfRegistrations() as List<Registration>

        // ------- getting a 'NULL' ---------

        local oNDT as Nullable<DateTime>

        oNDT := Nullable<DateTime>{}    //----- without a value ------

        //------------------------------------------------------------

        local aList as List<Registration>

        aList := List<Registration>{}

        aList:Add(Registration{"Dan","Logan","Romania","Super Fly",DateTime{2015, 01, 17},;

            true,true,false,SessionsAttending.All,"Images/DanLogan.jpg"})

        aList:Add(Registration{"Willie","Moore","USA","ATnT",oNDT,;

            false,true,false,SessionsAttending.AB,"Images/WillieMoore.jpg"})

        aList:Add(Registration{"Frank","Maraite","Germany","Drone Survey",DateTime{2015, 02, 23},;

            true,false,false,SessionsAttending.BC,"Images/ImageFrank2.jpg"})

        aList:Add(Registration{"Fabrice","Foray","France","Grafxsoft",oNDT,;

            true,false,false,SessionsAttending.AC,"Images/ImageFabrice.jpg"})

    return aList

    //===============================================================================================

end class

end namespace

============================================================================

//----- ListsThreeViewModel.prg -----

//----- Saturday 13th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_Lists_01

class ListsThreeViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _oRegColl as ObservableCollection<Registration>

    private _oRegLst as List<Registration>

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        //oRegColl := ObservableCollection<Registration>{}

        oRegColl := DataModels.GetRegistrationCollection()

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oRC as ObservableCollection<Registration>)

        super()

        //oRegColl := ObservableCollection<Registration>{}

        oRegColl := oRC

        self:Initialize()

    return

    constructor(oRL as List<Registration>)

        super()

        oRegLst := List<Registration>{}

        oRegLst := oRL

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

    return

    //----- Properties -----

    property oRegColl as ObservableCollection<Registration>

        get

            return self:_oRegColl

        end get

        set

            self:_oRegColl := value

            self:NotifyPropertyChanged("oReColl")

        end set

    end property

    property oRegLst as List<Registration>

        get

            return self:_oRegLst

        end get

        set

            self:_oRegLst := value

            self:NotifyPropertyChanged("oReLst")

        end set

    end property

    /*property TestString as string

        get

            return self:_testString

        end get

        set

            self:_testString := value

            self:NotifyPropertyChanged("TestString")

        end set

    end property*/

end class

end namespace   //----- VL15_Lists_01

============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

    partial class ListBoxView inherit Window

        constructor()

            super()

            InitializeComponent()

        return

        constructor(oLTVM as ListsThreeViewModel)

            super()

            InitializeComponent()

            self:DataContext := oLTVM

        return

    end class

end namespace

============================================================================

<Window x:Class="VL15_Lists_01.ListBoxView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Simple - ListBox - View :" Height="300" Width="390" Background="LightBlue">

    <Grid>

        <ListBox HorizontalAlignment="Left" Height="249"

                 Margin="10,10,0,0"

                 VerticalAlignment="Top" Width="161"

                 ItemsSource="{Binding oRegColl}" >

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <StackPanel Orientation="Vertical">

                        <StackPanel Orientation="Horizontal">

                            <TextBox Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}"

                                     FontWeight="Bold" Width="Auto"/>

                            <TextBox Text=" " Width="Auto"/>

                            <TextBox Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"

                                     FontStyle="Italic" Width="Auto"/>

                        </StackPanel>

                        <TextBlock Text="{Binding Path=Country}" Foreground="Red"/>

                    </StackPanel>

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

        <ListBox HorizontalAlignment="Left" Height="249"

                 Margin="218,10,0,0"

                 VerticalAlignment="Top" Width="154"

                 ItemsSource="{Binding oRegColl}" >

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <StackPanel Orientation="Vertical">

                        <StackPanel Orientation="Horizontal">

                            <TextBlock Width="Auto">

                                <Run Text="{Binding Path=FirstName}" FontStyle="Italic"/>

                                <Run Text=" " />

                                <Run Text="{Binding LastName}" FontWeight="Bold" Foreground="Blue"/>

                            </TextBlock>

                        </StackPanel>

                        <TextBlock Text="{Binding Path=Company}" Foreground="Green"/>

                    </StackPanel>

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

    </Grid>

</Window>

============================================================================

[ ..alternative script to use with App Resources .. ]

<Window x:Class="VL15_Lists_01.ListBoxView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Simple - ListBox - View :" Height="300" Width="390" Background="LightBlue">

    <Grid>

        <ListBox Height="249"

                 Margin="10,10,0,0"

                 ItemsSource="{Binding oRegColl}"

                 ItemTemplate="{StaticResource MyFirstLB_DT}">

        </ListBox>

        <ListBox Height="249"

                 Margin="207,10,0,0"

                 ItemsSource="{Binding oRegColl}"

                 ItemTemplate="{StaticResource ResourceKey=ThisWillWork}" >

        </ListBox>

    </Grid>

</Window>

============================================================================

<Application x:Class="VL15_Lists_Of_All_Sorts.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

        <DataTemplate x:Key="MyFirstLB_DT">

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBox Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}"

                                     FontWeight="Bold" Width="Auto"/>

                    <TextBox Text=" " Width="Auto"/>

                    <TextBox Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"

                                     FontStyle="Italic" Width="Auto"/>

                </StackPanel>

                <TextBlock Text="{Binding Path=Country}" Foreground="Red"/>

            </StackPanel>

        </DataTemplate>

        <DataTemplate x:Key="ThisWillWork">

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Width="Auto">

                                <Run Text="{Binding Path=FirstName}" FontStyle="Italic"/>

                                <Run Text=" " />

                                <Run Text="{Binding LastName}" FontWeight="Bold" Foreground="Blue"/>

                    </TextBlock>

                </StackPanel>

                <TextBlock Text="{Binding Path=Company}" Foreground="Green"/>

                <TextBlock Text="{Binding Path=Country}" Foreground="OrangeRed"/>

            </StackPanel>

        </DataTemplate>

        <Style TargetType="ListBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="Width" Value="160"/>

        </Style>

        <Style TargetType="TextBlock" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="RadioButton" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Button" >

            <Setter Property="VerticalAlignment" Value="Stretch"/>

            <Setter Property="HorizontalAlignment" Value="Stretch"/>

            <Setter Property="Height" Value="Auto"/>

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Background" Value="Yellow"  />

            <Setter Property="VerticalContentAlignment" Value="Center"/>

            <Setter Property="HorizontalContentAlignment" Value="Center"/>

            <Setter Property="Width" Value="120"/>

            <Setter Property="Height" Value="36"/>

        </Style>

        <Style TargetType="TextBox" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

        </Style>

        <Style TargetType="CheckBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="DatePicker" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Label" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="FontSize" Value="16"/>

        </Style>

    </Application.Resources>

</Application>

============================================================================

PHH -14th. December 2014.


Selecting 'on-screen' from a Collection

Okay folks, you guys now know how to bind collections to the ListBox UI element, and also

use DataTemplates to improve the item details we wish to display.

What we have not as yet done is examine the requirements for selection of list / collection item

and subsequent display on the window / form.

Once again we need to approach this problem from the ViewModel end of things.

By this I mean that if we create a public property to hold the selected (when selected) we can then

simply bind this property to the suitable attribute of the ListBox on our View.

Think of this as always having the code and logic in the VM, and nothing but bindings in the View.

This is getting too 'wordy', we need some examples and some images !

*** Just to put your mind at rest, this is going to be both easy and fun ;-0)) ***

Take a careful look at the next image, the second item in the first ListBox has been selected, and a

short text summary is then displayed in the newly added TextBlock UI element :-

====================================================================

To see what has been done to script and code to make this work for us, lets start by taking

a look at the XAML script, and the small amount of extra text typed into the editor :-

[ .. lines 11, and 14 & 15 - just two extra bindings ..]

======================================================================================================

If you study the above image you see that we have a binding for the selection on the ListBox control, and

also one for the returned summary detail of the selected list item.

Behind the bindings added, we must have two new public properties - to support each data binding, one

for each.

Let us first look at the private fields which will be used for the required properties :-

[ .. lines 34 & 35 are newly added .. ]

================================================================================

And now we need to see the new Vulcan code, added to create the public properties, as

well as support to the methods 'Initialize' and 'MakeSelRegSum'.

Study below the simple but necessary code members :-

=========================================================================

Please be aware that we can do almost anything once we have the selected item from the

listed collection, we have just chosen to do something VERY simple to visually demonstrate that

we have our new bindings working correctly.

Now that you have seen the required code, lets see what happens when we first display the View

for 'ListBox', check below :-

====================================================================

Yes, as you can see, the way our code is written we have no selected item when open

the form /screen.

When we select the first item (for Dan) we then get our TextBlock filled with information.

Here is what I get on my system :-

===================================================================

Now then, lets try something more interesting ................

Selection - Going a Step Further :

Okay then folks, now we are going to move a few paces further on, and also see how easy 'binding' is

when we already have a 'ViewModel' coded and in place, and populated generally by data injection.

We have so far seen how the text short summary can be bound to a single 'TextBlock' element, and the

property being bound is a public one belonging to the ViewModel itself, and not being supplied by injection.

Well now we will make the BIG step forward and add a bunch of TextBox elements which can be used both

to display the selected item property values, but also to allow editing of the field / property data.

Although we have quite a few options on how to change our existing double ListBox test application, the

most common type of scenario is when the list / collection items are Read Only (R/O) but the selected item

properties Read Write (R/W), and so can be changed on-screen.

Let us take a look at such a scenario - study the following image carefully :-

===================================================================

In the above image I have moved the second ListBox element from the right (RHS) of screen, over

to the left - so it is the R/O version of the list/collection that we are seeing. I have also moved and

shrunk the yellow TextBlock summary - just to get it out of the way.

On the right hand side (RHS) we can now see uneditable list items from the 'ObservableCollection'.

And new to the screen, on the RHS, we now have four TextBox elements and a 'DatePicker' control.

All five of these UI elements allow the user to change data values.

Shown below is the XAML script which provides the 'View' look as well as the functionality - check it out :-

=================================================================================

*** Remember *** that there are styles present in the "App.xaml" file which set default values

for many attributes of the UI elements being used.

Notice that by editing the characters of the first TextBox we have changes showing immediately in the

listed item which is currently 'selected' - so 'Frank' has become ' Frankie baby!! '.

Study the following details thoroughly :-

==================================================================

Oh! should have said - notice the displayed date ! Nothing special ?

Well, take a look at the window/form when we have Willie selected - why is our

DatePicker control not showing a date ?

Check the image shown below and try to answer my question - see the other changes too :-

===================================================================

[ .. above I have edited 3 of the four text fields relating to Willie .. ]

The answer to the question can be easily answered if we look at the original data - yes, the 'Model' used.

Take a careful look at the following image details :-

================================================================================================================

Look above at code lines 51 & 52, it is in line 51 where we see that the property called 'RegistrationDate' is being

supplied with a 'null' using ' oNDT ' - this is a 'null dateTime' and DO NOT say 'value' as the whole point of a 'null' is

that the property then does NOT have a value - it is 'null' !!!

Don't fight the above, just learn and go with the flow - also do not run away and try to give everything an 'empty' / zero

type of value - it is just not the modern or sensible approach.

If you ever intend to use SQL Server then get your head into using 'Null' correctly.

So to make a short summary of above, if the DatePicker is supplied with 'Null' then it handles it fine and OK. I will

leave you to make some further experiments with this.

Time to move forward - lets do some testing .............

Testing the Selection with Multiple Views open :

Let us remind ourselves that a VERY GOOD way to test screens which have data binding employed in their design

and construction, is to open multiple screens and see how one relates to another when we select items and edit values.

What do we see with our code as it is at the moment ? Checkout below :-

=============================================================================================================

Yes, if I select Frank in one View screen, then the second View instance reacts to also display Frank as

the selected collection item. And this also works this way if I select from the second screen.

So lets see the code which does this, and work out of ourselves 'why' !?

=======================================================================================

With the code as it is above, all the objects for the View 'launch' are created at Window instantiation time.

Only the View itself is instantiated within the click event handler method.

So the Model and ViewModel are created and exist, outside of the handler itself.

Therefore we are using the same VM (ViewModel) for each instance of the View - this means that all 'local'

public properties of the VM are the same object for all Views launched.

Lets move on a pace or two ...............

Making a Subtle (code) Change - but Big Performance Difference :

Let us now study the code after I have made some editing changes - check this out VERY thoroughly :-

==========================================================================================

In the above code, the first thing to notice (and realise) is that only the Model (data) is created

on a class-wide basis - the class being the main (or launch) window / form. See line 33.

This means that the collection items are exactly the same objects in each of the multiple ListBoxView

screens launched by a button click. So any change to a property on a selected item will be shown on

all screens open.

However, the local ViewModel instantiated at the time of a button click, means that the local public

properties within the VM will all point (hold?) different data objects.

Above, study line 39 to see that data injection of the existing Model is used to create a local copy of

the ViewModel.

The result, or consequence of this, is that a local public property in VM like 'SelectedReg' is quite

separate and different in each of the many View instance we see and use.

This means we can have Frank selected in one screen, Willie in a second screen, and friend Dan in

yet a third screen - the selected registration property is said to be 'localised' to the View.

We need to see this in action / operation - study the image shown below :-

========================================================================================================================

Yep ! - all three selections appear to be different and separate - and Willie still has a 'Null' date ;-)

So far with the above test we have demonstrated (or actually illustrated) the localisation of some public

properties, but what if we now try to make some editing changes ?

Check out the following and make your own conclusions :-

======================================================================================================================

Notice in the above image we have edited the text in the TextBox control at top right of the foremost screen.

We see ' Frankie BABY!! 'in the R/O list on the left, and also in the R/W TextBox on the right.

Now then, the interesting observation to be had, is if we look at the collection items displayed in the

ListBoxes of the background screens. In the unselected items (for Frank) we see that the text changes

have been completed and displayed - simply because the data (Model) object being used is the same one.

Okay guys, I think you need some time to think carefully on what we have just done and described ;-)

See you in the next subsection ..............

PHH -12th. & 15th. December 2014.


working script and code

==================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//=======================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

    partial class Window1 inherit Window

        public oWinLB as ListBoxView

        public oOCcheck as ObservableCollection<Registration>

        public oLTVM as ListsThreeViewModel

        constructor()

          super()

          InitializeComponent()

          self:Initialize()

        return

        method Initialize() as void

            oOCcheck := DataModels.GetRegistrationCollection()

            //oLTVM := ListsThreeViewModel{oOCcheck}  //----- Data Injection -----

        return

        private method pbMainListBox_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

            self:oLTVM := ListsThreeViewModel{self:oOCcheck}  //----- Data Injection -----

            oWinLB := ListBoxView{self:oLTVM}

            oWinLB:Show()

        return

        private method pbMainComboBox_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinCB as ComboBoxView

            oWinCB := ComboBoxView{}

            oWinCB:Show()

        return

        private method pbMainDataGrid_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

            local oWinDGmV as DataGrid_myView

            oWinDGmV := DataGrid_myView{}

            oWinDGmV:Show()

        return

    end class

end namespace

==================================================================================

<Window x:Class="VL15_Lists_01.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Lists and Collections :" Height="300" Width="300" Background="BurlyWood">

    <Grid>

        <Button Name="pbMainListBox" Content="ListBox" Margin="10,10,162,223" Click="pbMainListBox_Click"/>

        <Button Name="pbMainComboBox" Content="ComboBox" Margin="10,51,162,182" Click="pbMainComboBox_Click"/>

        <Button Name="pbMainDataGrid" Content="DataGrid" Margin="10,92,162,141" Click="pbMainDataGrid_Click"/>

    </Grid>

</Window>

==================================================================================

<Application x:Class="VL15_Lists_Of_All_Sorts.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

        <DataTemplate x:Key="MyFirstLB_DT">

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBox Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}"

                                     FontWeight="Bold" Width="Auto"/>

                    <TextBox Text=" " Width="Auto"/>

                    <TextBox Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"

                                     FontStyle="Italic" Width="Auto"/>

                </StackPanel>

                <TextBlock Text="{Binding Path=Country}" Foreground="Red"/>

            </StackPanel>

        </DataTemplate>

        <DataTemplate x:Key="ThisWillWork">

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Width="Auto">

                                <Run Text="{Binding Path=FirstName}" FontStyle="Italic"/>

                                <Run Text=" " />

                                <Run Text="{Binding LastName}" FontWeight="Bold" Foreground="Blue"/>

                    </TextBlock>

                </StackPanel>

                <TextBlock Text="{Binding Path=Company}" Foreground="Green"/>

                <TextBlock Text="{Binding Path=Country}" Foreground="OrangeRed"/>

            </StackPanel>

        </DataTemplate>

        <Style TargetType="ListBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="Width" Value="160"/>

        </Style>

        <Style TargetType="TextBlock" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="RadioButton" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Button" >

            <Setter Property="VerticalAlignment" Value="Stretch"/>

            <Setter Property="HorizontalAlignment" Value="Stretch"/>

            <Setter Property="Height" Value="Auto"/>

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Background" Value="Yellow"  />

            <Setter Property="VerticalContentAlignment" Value="Center"/>

            <Setter Property="HorizontalContentAlignment" Value="Center"/>

            <Setter Property="Width" Value="120"/>

            <Setter Property="Height" Value="36"/>

        </Style>

        <Style TargetType="TextBox" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

        </Style>

        <Style TargetType="CheckBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="DatePicker" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Label" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="FontSize" Value="16"/>

        </Style>

    </Application.Resources>

</Application>

==================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

begin namespace VL15_Lists_Of_All_Sorts

   partial class App inherit Application

   end class

end namespace

==================================================================================

//----- Registration.prg -----

//----- Monday December 8th. 2014. copied December 12th. -----

//----- 'as simple as it can get, and work correctly ! -----

#using  System

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_Lists_01

    class Registration implements INotifyPropertyChanged

        //----- Fields -----

        private _registrationId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        private _company as string

        private _registrationDate as System.Nullable<System.DateTime>

        private _hasPaid as System.Nullable<logic>

        private _isAlone as System.Nullable<logic>

        private _newbie as System.Nullable<logic>

        private _eSessions as SessionsAttending

        private _photoImage as string

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            self:RegistrationId := -1

        return

        constructor(cF as string, cL as string, cCT as string, cCP as string, dtReg as System.Nullable<System.DateTime>,;

                    lP as System.Nullable<logic>, lA as System.Nullable<logic>, lN as System.Nullable<logic>,;

                    eS as SessionsAttending, cPhotoImg as string)

            super()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            self:Company := cCP

            self:RegistrationDate := dtReg

            //----------------------

            self:HasPaid := lP

            self:IsAlone := lA

            self:Newbie := lN

            //----------------------

            self:eSessions := eS

            self:PhotoImage := cPhotoImg

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return self:FirstName+" "+self:LastName

        //----- Properties -----

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        property Company as string

            get

                return self:_company

            end get

            set

                self:_company := value

                self:NotifyPropertyChanged("Company")

            end set

        end property

        property RegistrationDate as System.Nullable<System.DateTime>

            get

                return self:_registrationDate

            end get

            set

                self:_registrationDate := value

                self:NotifyPropertyChanged("RegistrationDate")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property IsAlone as System.Nullable<logic>

            get

                return self:_isAlone

            end get

            set

                self:_isAlone := value

                self:NotifyPropertyChanged("IsAlone")

            end set

        end property

        property Newbie as System.Nullable<logic>

            get

                return self:_newbie

            end get

            set

                self:_newbie := value

                self:NotifyPropertyChanged("Newbie")

            end set

        end property

        //-----------------------------------------------

        property eSessions as SessionsAttending

            get

                return self:_eSessions

            end get

            set

                self:_eSessions := value

                self:NotifyPropertyChanged("eSessions")

            end set

        end property

        property PhotoImage as string

            get

                return self:_photoImage

            end get

            set

                self:_photoImage := value

                self:NotifyPropertyChanged("PhotoImage")

            end set

        end property

        //-----------------------------------------------

    end class

end namespace //----- VL15_VM02

==================================================================================

//----- InMemDS4Registration.prg -----

//----- December 8th. 2014 -----

#using System

#using System.Collections.Generic

#using System.Windows

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

class DataModels

    static method GetSingleRegistration() as Registration

        local implied oReg := Registration{}

        oReg := Registration{}

        oReg:FirstName := "Dan"

        oReg:LastName := "Logan"

        oReg:Country := "Romania"

        oReg:Company := "Super Fly"

        oReg:HasPaid := true

        oReg:IsAlone := true

        oReg:Newbie := false

        oReg:RegistrationDate := DateTime.Now

        oReg:RegistrationId := 22

        oReg:eSessions := SessionsAttending.All

        oReg:PhotoImage := "..."

    return oReg

    static method GetSingleRegistration2() as Registration

        local implied oReg := Registration{"Dan","Logan","Romania",;

                    "Super Fly",DateTime.Now,true,true,false,SessionsAttending.All,"DanLogan.jpg"}

        oReg:RegistrationId := 22

    return oReg

    //===============================================================================================

    static method GetRegistrationCollection() as ObservableCollection<Registration>

    return ObservableCollection<Registration>{GetaBunchOfRegistrations()}

    static method GetaBunchOfRegistrations() as List<Registration>

        // ------- getting a 'NULL' ---------

        local oNDT as Nullable<DateTime>

        oNDT := Nullable<DateTime>{}    //----- without a value ------

        //------------------------------------------------------------

        local aList as List<Registration>

        aList := List<Registration>{}

        aList:Add(Registration{"Dan","Logan","Romania","Super Fly",DateTime{2015, 01, 17},;

            true,true,false,SessionsAttending.All,"Images/DanLogan.jpg"})

        aList:Add(Registration{"Willie","Moore","USA","ATnT",oNDT,;

            false,true,false,SessionsAttending.AB,"Images/WillieMoore.jpg"})

        aList:Add(Registration{"Frank","Maraite","Germany","Drone Survey",DateTime{2015, 02, 23},;

            true,false,false,SessionsAttending.BC,"Images/ImageFrank2.jpg"})

        aList:Add(Registration{"Fabrice","Foray","France","Grafxsoft",oNDT,;

            true,false,false,SessionsAttending.AC,"Images/ImageFabrice.jpg"})

    return aList

    //===============================================================================================

end class

end namespace

==================================================================================

//----- ListsThreeViewModel.prg -----

//----- Saturday 13th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_Lists_01

class ListsThreeViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _oRegColl as ObservableCollection<Registration>

    private _oRegLst as List<Registration>

    //----- added for selection purposes -----

    private _oselectedReg as Registration

    private _selRegSum as string

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        //oRegColl := ObservableCollection<Registration>{}

        oRegColl := DataModels.GetRegistrationCollection()

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oRC as ObservableCollection<Registration>)

        super()

        //oRegColl := ObservableCollection<Registration>{}

        oRegColl := oRC

        self:Initialize()

    return

    constructor(oRL as List<Registration>)

        super()

        oRegLst := List<Registration>{}

        oRegLst := oRL

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:oSelectedReg := Registration{}

    return

    method MakeSelRegSum() as string

        local cSelRegSum := "" as string

        cSelRegSum += self:oSelectedReg:FirstName + e"\n"

        cSelRegSum += self:oSelectedReg:LastName + e"\n"

        cSelRegSum += self:oSelectedReg:Company + e"\n"

        cSelRegSum += self:oSelectedReg:Country + e"\n"

    return cSelRegSum

    //----- Properties -----

    property oSelectedReg as Registration

        get

            return self:_oselectedReg

        end get

        set

            self:_oselectedReg := value

            self:NotifyPropertyChanged("oSelectedReg")

            self:SelRegSum := MakeSelRegSum()

        end set

    end property

    property SelRegSum as string

        get

            return self:_selRegSum

        end get

        set

            self:_selRegSum := value

            self:NotifyPropertyChanged("SelRegSum")

        end set

    end property

    property oRegColl as ObservableCollection<Registration>

        get

            return self:_oRegColl

        end get

        set

            self:_oRegColl := value

            self:NotifyPropertyChanged("oReColl")

        end set

    end property

    property oRegLst as List<Registration>

        get

            return self:_oRegLst

        end get

        set

            self:_oRegLst := value

            self:NotifyPropertyChanged("oReLst")

        end set

    end property

    /*property TestString as string

        get

            return self:_testString

        end get

        set

            self:_testString := value

            self:NotifyPropertyChanged("TestString")

        end set

    end property*/

end class

end namespace   //----- VL15_Lists_01

==================================================================================

<Window x:Class="VL15_Lists_01.ListBoxView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Simple - ListBox - View :" Height="300" Width="390" Background="LightCoral">

    <Grid>

        <ListBox Height="35"

                 Margin="10,224,0,0"

                 ItemsSource="{Binding oRegColl}"

                 ItemTemplate="{StaticResource MyFirstLB_DT}"

                 SelectedItem="{Binding oSelectedReg}">

        </ListBox>

        <TextBlock Margin="207,223,0,0" Text="{Binding SelRegSum}" Background="Yellow"

                   Height="34" Foreground="DarkBlue"/>

        <ListBox Height="196"

                 Margin="10,10,0,0"

                 ItemsSource="{Binding oRegColl}"

                 ItemTemplate="{StaticResource ResourceKey=ThisWillWork}"

                 SelectedItem="{Binding oSelectedReg}">

        </ListBox>

        <TextBox Margin="207,13,0,0" Text="{Binding oSelectedReg.FirstName,

                 UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Margin="207,41,0,0" Text="{Binding oSelectedReg.LastName,

                 UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Margin="207,69,0,0" Text="{Binding oSelectedReg.Company,

                 UpdateSourceTrigger=PropertyChanged}"/>

        <TextBox Margin="207,97,0,0" Text="{Binding oSelectedReg.Country,

                 UpdateSourceTrigger=PropertyChanged}"/>

        <DatePicker Margin="207,125,0,0"

                    DisplayDate="{Binding oSelectedReg.RegistrationDate}"

                    SelectedDate="{Binding oSelectedReg.RegistrationDate}"

                    Height="37"

                    Width="120"/>

    </Grid>

</Window>

==================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

    partial class ListBoxView inherit Window

        constructor()

            super()

            InitializeComponent()

        return

        constructor(oLTVM as ListsThreeViewModel)

            super()

            InitializeComponent()

            self:DataContext := oLTVM

        return

    end class

end namespace

==================================================================================

==================================================================================

PHH - 16th. December 2014.


ComboBox lists - and item selection

PHH -15th. December 2014.


Changing the 'Collection' - Adding and Removing

Okay folks, we have gotten quite good at editing property values on items within a Collection,

but we now need to move on to changing (or editing) the Collection itself.

By the above we really mean Adding to, or Removing from, the collection 'list'. We often see and

hear 'list' being used loosely when we are discussing 'Collections'. So 'list' is a general term for a

bunch of collection items - and so an ObservableCollection is often termed a 'list' - notice the small

'l' as 'List' is a class of object and in particular a 'List<T>'.

So we talk about lists of items, even when we have a typed collection.

Why use an 'ObservableCollection' (OC) class type ? :

Quite simply, the 'OC' class has built in functionality to handle all the 'list' stuff we would expect.

Like the collection changing length due to additions and deletions, but also stuff to do with item ordering.

Since this stuff is really NOT directly related to MVVM coding patterns, we will just show one sample to

illustrate some of the basic points of all this.

And, since we are not using an MVVM framework, we will use a couple of push buttons and some click events.

Lets make a start .....................

Adding a New Registration item to the Existing list (Collection) :

Let us have a quick look at what we are aiming to do, let us start with the 'View' - check this below :-

================================================================================================================

Yes, we need an extra (fourth) button on our main 'launch' form, and a new View and ViewModel to be available for

use in the 'click' event handler method.

*** Remember *** if we were using an MVVM framework we would use 'Command's in place of 'Event's. We are

only using a few button click events while exploring Data Binding fully in WPF - without any extra frameworks or

libraries, just pure .NET 'out of the box'.

In the above image please note that we have a standard list display on the left (hand side) - then we have a whole

set of controls to display a new and default / blank Registration class object. All of the controls are editable, so

that the user may enter the correct information.

Notice that we have seemingly 'correctly' handled the 'Null' settings for the four controls 'DatePicker' and three

'CheckBox'es.

We will see below how the ComboBox control is filled with 'enums' for Sessions.

The basic idea is that the user edits and selects all of the control contents, and then clicks the 'Add' button to

cause the property values to be saved as a new Registration object into the existing Collection object.

*** Note *** on the absence of Labels - to keep the screen clear and simple, I have added Tooltips instead.

Check this out below :-

=================================================================================================================

All of the input controls have a Tooltip so that we the users can tell what is required in each or the successive inputs.

Here is an image of two of the Tooltip script entries - lines 42 & 47, check them out :-

============================================================================================

Lets move on a step or two ...............

Setting up the Drop List (ComboBox) control with 'enums' :

Lets take a moment to see an image of what we are after - check this below :-

==============================

Yes, we need a suitably filled list or collection, both will do as there will be no changes to the list items,

which we then bind to the ComboBox, and we also wish to make the selected default the first item, that

showing 'None' - item index zero.

As with any binding situation done for the MVVM pattern of development, we need to have a suitable Public

Property in the relevant ViewModel.

Before we can look at details, we need to create a new VM entitled 'CollectionChangeViewModel'.

Making a ViewModel to go with the 'CollectionChange' View :

As we have done previously, use the node in the SE pane and the 'context menu' to create a new code file

within the 'b_ViewModels' folder - see below :-

===========================================================

Basically, I copied the existing code content into this new blank code file, from the earlier VM for

'ListThreeViewModel' file and did a bunch of editing.

Here, shown below, is a partly collapsed / expanded look at this new VM, to let us see the relevant

new parts - study carefully :-

================================================================================================

If you study thoroughly the above code image, you will see the parts needed to support the Enum collection.

And as usual we need to create a Public Property for data binding purposes - lines 70 & 29.

Lines 57, and 60 through 67 are used to fill the ComboBox, once we have set the binding script in the XAML file.

Below is shown the script :-

======================================================================================

Lets move on ...............

Making a Suitable 'View' for Collection Change :

Before we get drawn any further into looking at code and script details, we had better look at the creation

of a new View - one obviously called 'CollectionChangeView'.

Here are some relevant images :-

===========================================================

Above we have 'Added' a new Window item into the 'View' folder.

And here below we have dragged and dropped a few suitable controls from the Toolbox pane.

After dragging I did edit and clean the XAML script to make it clearer and easier to read and manage.

Checkout the designer surface - see below :-

===============================================================

And now we had better have a look at some of the more important script lines.

Controls similar to those used in previous samples have been collapsed to make it easier for us to study the other detail.

Study the following image thoroughly :-

=====================================================================================================================================

In the above image, check out all of the visible 'bindings' and 'tooltips' as well.

And as I confessed earlier, we need to have a few Click event handlers, because we are not using an MVVM framework.

So here is the 'code behind' - a bit more than it should be, in length :-

[ .. OK, I know, we have yet to include the code to handle the Events - patience !! .. ]

=====================================================================================

Lets move forward a little, and test what we have now ..................

Testing the Functionality of the Inputting of New Information :

Before we worry about saving a new Registration object into our existing Collection, let us

see if we can in fact edit all our input controls in a way we are hoping will work for us later.

Here is a sample I have just done there now, a couple of minutes ago :-

==========================================================

============================================================

========================================================

=========================================================

=====================================================================================================

==============================================================================================

==============================================================================

=============================================================================

==============================================================================================

=============================================================

================================================================

==========================================================

=====================================================================================================

=======================================================================================================

==============================================================================================================

We need to solve the problem of not allowing the empty default Registration object from being saved in the list,

as well as not allowing empty (or unspecified) inputs to be saved, as well as the case of validating some data

values which may be specified incorrectly.

In our case - seen clearly above - we only can really validate the string fields / properties, as we have no numeric

ones and the dates and logic inputs will be OK whatever, since we allow 'nulls' to be provided.

We need to address the topic of Property/ Field validation in a later topic section (Chapter 17), as it is a big issue

in its own right.

Lets now move on to the child subsection from here where we will study 'Removal' or 'Deletion' of collection items.

See you there .............

PHH -16th. & 17th. December 2014.


Removing items - this is easier !

Okay guys, the good news is that creating a View and a ViewModel to delete or remove an

item from a collection is much easier than when we wish to add an item.

Because we don't need to bother with individual property values of the item to be removed,

all we need do is select the required item in a list control, save the selected item as such, and

then specify that we wish to delete / remove it. As simple as that ;-)

Obviously we will need to display enough detail in the DataTemplate used to show the list items,

but that is relatively easy - as we have seen earlier.

Because the task of item removal is much easier than new item addition, we can actually adapt

the existing 'CollectionChangeView' to suit our extra needs.

Here is what it now looks like at my end - on my desktop development system - see below :-

===============================================================================================

In appearance, and on the surface of things, there is not really a lot of difference, or much extra to see.

Basically we have added a 'Remove' button.

Removal will depend on an item in the list (the Collection) being first selected by the user, then removal

can take place.

I still have some ends to tidy up as yet, but we can see working the main part of this general procedure.

If we look at the new code from above, once again and in more detail we can talk ourselves through the

requirements - first check below and study the details carefully :-

====================================================================================================

The 'RemoveFromCollection' method is part of the ViewModel which supports the 'CollectionChangeView'

window class.

This method simply need to know the item which has been selected (if any) - this is one issue which needs

to be handled right - when there is no selected item !?

Because the item selected will be just a pointer to the actual item object of the Collection, we can then use

directly the 'Remove()' method belonging to the ObservableCollection class.

The code above has some simple test lines which need removing and improving - we could show a fuller

detailed output and representation of the item, as a better check.

A lot of the small detailed tidying I will leave to you as it is the main MVVM stuff we are focusing on here in

these eNotes.

Okay then, what of the selected item - we we add some code like that we had in the 'ListBoxView' window.

=====================================================================================

As seen above we need code for the selected Registration object as well as a 'summary string' to

represent the selected item in a 'MessageBox' display.

And now we are going to see that when instantiation of a View takes place ('CollectionChange') we

need to provide a default Registration - check this out :-

============================================================

And now we can see an improved 'Remove' method which provides a fuller set of details :-

==========================================================================================================================

Obviously, I had to click on Frank in the ListBox to cause the message box display as seen above.

I will leave you to improve the Date display, if you so wish.

And we need to check that this code will be okay for items (guys) where the date is 'Null' - check

below for Willie's item :-

========================================================

As you can see above the 'Null' entry for the 'RegistrationDate' property has been handled OK.

Also we see below that the removal goes to plan :-

==============================

To facilitate these actions we do need suitable Public properties, similar to those we

have used in previous View definitions - check these out :-

====================================================================

And finally for the script code explanation, we need to see the push button click event and its

handler - checkout the following image details :-

=====================================================================================

Notice that in line 76 we are calling a method code from the 'ViewModel' - remember, all code should be in the

VM, and nothing the the View 'code behind' if we are doing MVVM correctly.

If we were to use a framework for MVVM we could also eliminate the Event code, but as I said before,

"One step at a time".

Here is the 'Click' event attribute, and this means we also need a Name attribute, both of which would not be

there for full MVVM - check this :-

===========================================================================================================

Lets move on ............

Further Testing :

I have tried to remove all of the Collection items, and that seems to work without issue, however clicking the

'Remove' button when no more items are present needs to be put right, or handled better ;-) - see below :-

=========================================================

Oh! when I looked deeper, and did more testing, there were a good couple of things that

needed sorting out ;-0)

So here are some visual clues or reminders as to what needs doing :-

===========================================================

Above we keep the selected item 'Null' until chosen from the list in the UI ListBox element.

And now we do not have an initial default selected item, the following code seems to work well and tests a-okay.

Check all the following details quite thoroughly :-

===========================================================================================================

Notice that we are trapping two non-required conditions, on which we effectively cancel the removal request.

Here are some on-screen 'live' displays, first the nothing selected condition :-

========================================================

And now the Collection empty condition :-

=======================================================

Well guys, that's about it. Most things work well enough to get you going with

Collections, their items in a list, and also Adding and Removing items from the ListBox element.

Note that Data Binding seems to work a-okay on all fronts, and in all cases.

Time to move on to the next sub-section, see you there ............................

PHH -17th. & 18th. December 2014.


working script and code

==============================================================================

//----- CollectionChangeViewModel.prg -----

//----- Tuesday 16th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_Lists_01

class CollectionChangeViewModel implements INotifyPropertyChanged

    private _oRegColl as ObservableCollection<Registration>

    private _oRegNew as Registration

    private _oOCsessions as ObservableCollection<SessionsAttending>

    //----- added for selection purposes -----

    private _oselectedReg as Registration

    private _selRegSum as string

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        oRegColl := DataModels.GetRegistrationCollection()

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oRC as ObservableCollection<Registration>)

        super()

        oRegColl := oRC

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:oRegNew := Registration{}

        self:FillSessionsList()

        //self:oSelectedReg := Registration{}

    return

    method ClearInputs() as void

        MessageBox.Show("All data input to properties will GO !","Clear Inputs :")

        self:oRegNew := null

        self:oRegNew := Registration{}

    return

    method FillSessionsList() as void

        self:oOCsessions := ObservableCollection<SessionsAttending>{}

        self:oOCsessions:Add(SessionsAttending.None)

        self:oOCsessions:Add(SessionsAttending.All)

        self:oOCsessions:Add(SessionsAttending.AB)

        self:oOCsessions:Add(SessionsAttending.AC)

        self:oOCsessions:Add(SessionsAttending.BC)

    return

    method Add2Collection() as void

        oRegColl:Add(self:oRegNew)

        MessageBox.Show("Check the listed Collection !","Adding a new item :")

        self:ClearInputs()

    return

    method RemoveFromCollection() as logic

        local lOK := true as logic

        if self:oSelectedReg == null

            MessageBox.Show("Sorry, NO selected item !!??","One Item to Remove :")

            lOK := false

        endif

        if (self:oRegColl:Count < 1 .and. lOK)

                MessageBox.Show("Sorry, the Collection is empty !!??","One Item to Remove :")

                lOK := false

            endif

        //-----------------------------------------------------------------------------------

        if lOK

            MessageBox.Show(MakeSelRegSum(),"One Item to Remove :")

            oRegColl:Remove(self:oSelectedReg)

            MessageBox.Show("Check the listed Collection !","One Item Removed :")

            self:ClearInputs()

        endif

    return lOK

    method MakeSelRegSum() as string

        local cSelRegSum := "" as string

        cSelRegSum += self:oSelectedReg:FirstName + e"\n"

        cSelRegSum += self:oSelectedReg:LastName + e"\n"

        cSelRegSum += self:oSelectedReg:Company + e"\n"

        cSelRegSum += self:oSelectedReg:Country + e"\n"

        cSelRegSum += self:oSelectedReg:RegistrationDate:ToString() + e"\n"

    return cSelRegSum

    //----- Properties -----

    property oSelectedReg as Registration

        get

            return self:_oselectedReg

        end get

        set

            self:_oselectedReg := value

            self:NotifyPropertyChanged("oSelectedReg")

            self:SelRegSum := MakeSelRegSum()

        end set

    end property

    property SelRegSum as string

        get

            return self:_selRegSum

        end get

        set

            self:_selRegSum := value

            self:NotifyPropertyChanged("SelRegSum")

        end set

    end property

    property oOCsessions as ObservableCollection<SessionsAttending>

        get

            return self:_oOCsessions

        end get

        set

            self:_oOCsessions := value

            self:NotifyPropertyChanged("oOCsessions")

        end set

    end property

    property oRegNew as Registration

        get

            return self:_oRegNew

        end get

        set

            self:_oRegNew := value

            self:NotifyPropertyChanged("oRegNew")

        end set

    end property

    property oRegColl as ObservableCollection<Registration>

        get

            return self:_oRegColl

        end get

        set

            self:_oRegColl := value

            self:NotifyPropertyChanged("oReColl")

        end set

    end property

end class

end namespace   //----- VL15_Lists_01

==============================================================================

<Window x:Class="VL15_Lists_Of_All_Sorts.CollectionChangeView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="CollectionChangeView" Height="330" Width="360" Background="Beige">

    <Grid>

        <Grid.Resources>

            <Style TargetType="Button" >

                <Setter Property="VerticalAlignment" Value="Stretch"/>

                <Setter Property="HorizontalAlignment" Value="Stretch"/>

                <!--<Setter Property="Height" Value="Auto"/>-->

                <Setter Property="FontSize" Value="12"/>

                <!--<Setter Property="FontWeight" Value="Bold"/>

                <Setter Property="Background" Value="Yellow" />-->

                <Setter Property="VerticalContentAlignment" Value="Center"/>

                <Setter Property="HorizontalContentAlignment" Value="Center"/>

                <Setter Property="Width" Value="120"/>

                <!--<Setter Property="Height" Value="36"/>-->

            </Style>

            <Style TargetType="ComboBox" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

                <Setter Property="Width" Value="120"/>

            </Style>

        </Grid.Resources>

        <ListBox

                 Margin="10,10,0,0"

                 ItemsSource="{Binding oRegColl}"

                 ItemTemplate="{StaticResource ResourceKey=ThisWillWork}"

                 SelectedItem="{Binding oSelectedReg}" VerticalAlignment="Top" Height="192"/>

        <TextBox Margin="207,13,0,0" Text="{Binding oRegNew.FirstName,

                 UpdateSourceTrigger=PropertyChanged}" ToolTip="Firstname..."/>

        <TextBox Margin="207,41,0,0" Text="{Binding oRegNew.LastName,

                 UpdateSourceTrigger=PropertyChanged}" ToolTip="Lastname..."/>

        <TextBox Margin="207,69,0,0" Text="{Binding oRegNew.Company,

                 UpdateSourceTrigger=PropertyChanged}" ToolTip="Company..."/>

        <TextBox Margin="207,97,0,0" Text="{Binding oRegNew.Country,

                 UpdateSourceTrigger=PropertyChanged}" ToolTip="Country..."/>

        <DatePicker Margin="207,125,0,0"

                    DisplayDate="{Binding oRegNew.RegistrationDate}"

                    SelectedDate="{Binding oRegNew.RegistrationDate}"

                    Height="37" ToolTip="Registration date..."

                    Width="120"/>

        <Button Name="pbAdd" Content="Add" Margin="10,212,289,59"

                Width="53" Background="LightGreen" Click="pbAdd_Click" />

        <Button Name="pbClearInputs" Content="Clear inputs"

                Margin="74,212,182,59" Background="Gold"

                Width="96" Click="pbClearInputs_Click" />

        <CheckBox Content="Has Paid :" Margin="207,167,0,0" IsChecked="{Binding oRegNew.HasPaid}" ToolTip="Has paid..."/>

        <CheckBox Content="Is Alone :" Margin="207,187,0,0" IsChecked="{Binding oRegNew.IsAlone}" ToolTip="Is alone..."/>

        <CheckBox Content="Is newbie :" Margin="207,207,0,0"  IsChecked="{Binding oRegNew.Newbie}" ToolTip="Is a newbie..."/>

        <ComboBox Margin="207,227,0,0" ToolTip="Sessions to attend..."

                  ItemsSource="{Binding oOCsessions}" SelectedIndex="0"/>

        <TextBox Margin="207,267,0,0" Text="{Binding oRegNew.PhotoImage}" ToolTip="Photo image string ..."/>

        <Button Name="pbCloseForm" Content="Close Form" Margin="10,261,278,10"

                Width="64" Background="LightCoral" Click="pbCloseForm_Click" />

        <Button Name="pbRemove" Content="Remove" Margin="93,262,182,9" Background="LightBlue"

                Width="77" Click="pbRemove_Click" />

    </Grid>

</Window>

==============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//-------------------------------------

#using VL15_Lists_01

begin namespace VL15_Lists_Of_All_Sorts

partial class CollectionChangeView inherit Window

    private oCCVMlocal as CollectionChangeViewModel

    constructor()

        super()

        InitializeComponent()

        self:Initialize(CollectionChangeViewModel{})

    return

    constructor(oCCVM as CollectionChangeViewModel)

        super()

        InitializeComponent()

        self:Initialize(oCCVM)

    return

    method Initialize(oCCVM as CollectionChangeViewModel) as void

        self:oCCVMlocal := oCCVM

        self:DataContext := oCCVMlocal

    return

    private method pbAdd_Click( sender as System.Object, ;

                e as System.Windows.RoutedEventArgs ) as System.Void

        try

            self:oCCVMlocal:Add2Collection()

            MessageBox.Show(self:oCCVMlocal:oRegColl:Count:ToString(),"my new Count!")

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end TRY

    return

    private method pbClearInputs_Click( sender as System.Object, ;

                e as System.Windows.RoutedEventArgs ) as System.Void

        try

            self:oCCVMlocal:ClearInputs()

            //----- trick to clear Drop List selection -----

            self:DataContext := null

            self:DataContext := self:oCCVMlocal

            MessageBox.Show("Existing property inputs cleared...","Fresh start :")

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return

    private method pbCloseForm_Click( sender as System.Object, ;

                e as System.Windows.RoutedEventArgs ) as System.Void

        try

            self:oCCVMlocal:ClearInputs()

            MessageBox.Show("Existing property inputs LOST ...","Cleared to finish :")

            self:Close()

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end TRY

    return

    private method pbRemove_Click( sender as System.Object, ;

                e as System.Windows.RoutedEventArgs ) as System.Void

        try

            if self:oCCVMlocal:RemoveFromCollection()

                MessageBox.Show("Existing item LOST !","Item Removal :")

            endif

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end TRY

    return

    end class

end namespace

==============================================================================

==============================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

begin namespace VL15_Lists_Of_All_Sorts

   partial class App inherit Application

   end class

end namespace

==============================================================================

<Application x:Class="VL15_Lists_Of_All_Sorts.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

        <DataTemplate x:Key="MyFirstLB_DT">

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBox Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}"

                                     FontWeight="Bold" Width="Auto"/>

                    <TextBox Text=" " Width="Auto"/>

                    <TextBox Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"

                                     FontStyle="Italic" Width="Auto"/>

                </StackPanel>

                <TextBlock Text="{Binding Path=Country}" Foreground="Red"/>

            </StackPanel>

        </DataTemplate>

        <DataTemplate x:Key="ThisWillWork">

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Width="Auto">

                                <Run Text="{Binding Path=FirstName}" FontStyle="Italic"/>

                                <Run Text=" " />

                                <Run Text="{Binding LastName}" FontWeight="Bold" Foreground="Blue"/>

                    </TextBlock>

                </StackPanel>

                <TextBlock Text="{Binding Path=Company}" Foreground="Green"/>

                <TextBlock Text="{Binding Path=Country}" Foreground="OrangeRed"/>

            </StackPanel>

        </DataTemplate>

        <Style TargetType="ListBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="Width" Value="160"/>

        </Style>

        <Style TargetType="TextBlock" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="RadioButton" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Button" >

            <Setter Property="VerticalAlignment" Value="Stretch"/>

            <Setter Property="HorizontalAlignment" Value="Stretch"/>

            <!--<Setter Property="Height" Value="Auto"/>-->

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Background" Value="Yellow"  />

            <Setter Property="VerticalContentAlignment" Value="Center"/>

            <Setter Property="HorizontalContentAlignment" Value="Center"/>

            <Setter Property="Width" Value="120"/>

            <Setter Property="Height" Value="36"/>

        </Style>

        <Style TargetType="TextBox" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

        </Style>

        <Style TargetType="CheckBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="DatePicker" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Label" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="FontSize" Value="16"/>

        </Style>

    </Application.Resources>

</Application>

==============================================================================

PHH -18th. December 2014.


Designing / Making more complex DataTemplates

PHH -12th. December 2014.


working script and code

PHH - 9th. & 12th. December 2014.


Chapter 6 - Sample six - more complex ViewModels

PHH - 8th. December 2014.


Images and photographs

PHH - 15th. December 2014.


working script and code

PHH - 9th. December 2014.


Chapter 7 - Sample seven, many lists - collections

PHH - 8th. December 2014.


Chapter 8 - Sample eight, collections in 'DataGrid's

Okay guys, lets use our previous application to add to, and develop, the DataGrid 'View' which we placed

in the 'VL15_ListsOf_All_Sorts' solution - some way back in these eNotes.

Here is what the main screen looks like, and we are going to be using the third button option, for 'DataGrid'.

Check this out :-

==============================================

Okay the folks, it seems quite simple, we need to know just what script and code we need to

add behind this main launch form to get some information displayed in a DataGrid.

Let us go the usual 'step at a time', and try to keep things as simple as we can ...............

As simple as start as is possible :

The first, and good, news is that it is extremely easy to bind and display a List<> and/or an

ObservableCollection <> to a 'DataGrid' UI control.

Here is a first result with only a few lines of script and code :-

================================================================================

Yep! - above, in our little window we can see the four Registration objects we have been using previous,

for all of our recent testing.

Also notice that we can select a row by clicking the mouse in any part of that row.

Let us now change the screen display and size on-screen the DataGrid :-

[ .. as an extra feature below, I have clicked the mouse with the pointer in the header of 'FirstName' - see the resulting sort orde A-Z .. ]

====================================================================================================================================

Once again (above) we can see that very little XAML script is required or necessary.

Okay then folks, lets improve the look with some alternating row colours - check below the visual improvement :-

====================================================================================

In the above script image we see lines 9 & 10 are responsible for the row 'colouration' effect.

Now let us try out a few more of the MANY attributes relating to the DataGrid control - study thoroughly the following :-

===========================================================================================================================

Yes, we can do all sorts of things with reordering and resizing of Columns and Rows, as well as binding the item selected, much

as we did in the ListBox sample. In this case an item is a row - one row of the DataGrid is an item within the Collection.

Now the guys, below shows us that without any extra fuss, effort, or bother, we can click in the bottom (empty) row and have the

last row become a default 'Registration' object which we can edit, field by field (or property by property).

Check out the image below in which I am adding information on my son Benjamin (Ben) :-

=============================================================================================================================

[ .. note that above the data binding is done on script line 7 - 'ItemsSource' being bound as we did for ListBox .. ]

If we complete the addition of Ben's row and then order the 'FirstName' column by A-Z order, and clicking in the column header, we see this :-

=======================================================================================================================================

We can now do an interesting check, or test, and with the window open of the grid, open up another from the main launch form, this time one

for a 'ListBox' - the light red form shown below, now has Ben's collection item (Registration) clearly showing. This is simply because both

of the different 'View' are using the same data Model, as well as ViewModel, but it is the Model which is responsible for this behaviour.

Check out more carefully the details shown below :-

===========================================================================================================================================

Okay then, lets move on to see what we can do with 'Sessions' and the enums we are using for them.

As a first step, we can bind our enum public property to a 'DataGridTextColumn' - see below :-

[ .. we can also sort these by a column header click .. ]

==================================================================================================================================

If you are following through this sample in VS then try a few other column sorts for yourself.

Okay then, "so far so good", but what if we wish NOT to use the 'Autogeneration' facility, and instead create and name our own columns ?

Well, this is easy enough, and quite possible even for newbies ;-0)

In the following image we have the 'AutoGen...' attribute set to false, and then we need to add our own data columns in a bunch (or set)

of specified columns - see lines below at 27 through 30, these are all for 'Text' - check out below :-

==================================================================================================================================

Notice above how we can bind each new column to an existing Public property of the item in the Collection.

Dong this this way allows us to specify our own header content as well as ONLY using the properties we wish to

display as columns.

Notice below that row ordering A-Z/Z-A still functions as previously - check this out :-

=========================================================================

And once we get into adding our own DataGrid columns we can easily move on to CheckBoxes, as seen below :-

========================================================================================================================================

Once again these order and reorder by clicking the headers.

Yep! - and the new item entry works just as you would expect - see below :-

========================================================================================================================================

Below we see the 'Ben' new entry has been included and assimilated into the 'DataGrid' sort on 'Company' :-

=============================================================================================================================

Yes, this is all fun and needs us to spend some time learning and try out new stuff etc., etc..

But, when we wish to add a Drop List or ComboBox we had better move to the child sub-section from here.

Lets go and checkout DataGrid 'comboBoxes' ..............

See you there - in the next section.

PHH - 9th. & 18th. December 2014.


Drop Lists / 'ComboBox'es in DataGrid controls

Well guys, if you Google about ComboBox controls within the DataGrid UI element you will get

the idea that data binding is difficult, or impossible, or somewhere in between ! ;-0((

The answer is to NOT use the 'DataGridComboBoxColumn' but stick with the more general '...TemplateColumn'

class - this seems to work just fine.

First lets see how the single 'enum' public property of Registration can be bound and displayed using a Text column.

Checkout the next image :-

==========================================================

But if we do a test and name our test header "My Drop List" then we can get this to show :-

==============================================================================

Yep! - a little too wide for my liking ;-0)

But we can see all of the drop list enum options we require / need.

Before we go into how we make the drop list contents available for show and selection, lets see the script

I have been playing around with to get the above to work OK for us.

Check out the following XAML script details :-

=====================================================================================================

Obviously above shows my trial failures too !

What we need to know is what property is 'eAllSessions' and where does it come from ?

By the way, I am just showing you what I have working, rather than suggesting that this is the best or only way to do it.

Lets see How the new "...TemplateColumn" fits into the existing XAML script - check below :-

=========================================================================================================================

Lines 25 through 32 in the above image are those for the new section.

Lets now see how we can use the Resources section to make things look tidier.

First we need to study the detail of the 'DataTemplate' itself, and note below we are trying to

stop editing of the Drop List details :-

=============================================================================

This does not stop us making screen inputs to change the session enum of a chosen item - see below :-

=================================================================================

Both new items and existing ones allow us to make what looks like changes.

Here is script for both related attributes :-

===================================================================================

And sure enough we can still change the displayed Sessions 'enum' !?

Why is this ? - I suggest that we may be getting mixed up between editing and 'selecting'.

I also think that we are now going outside of our remit and that we should explore this some other place.

The clue I will give you is that if you change the attributes as below - then we can change more than previously :-

=======================================================================================

This at least allows this to happen in editing :-

====================================================

Note that we can at least enter the selected value, whatever that means under these circumstances.

I will throw a little more light on this shortly (below).

Lets see first of all how we can place some script into the Resources section to tidy the body of our script.

We can specify a DataTemplate and place that in the Resources as seen below :-

===============================================================================================================================

Yep! - okay folks, this certainly tidies up the above script on lines 33 through 36.

And to prove that this new script and layout does work, and do as we had previously, then here is a runtime screen capture :-

================================================================================================================================

Okay then guys, "so good so far" but where do we get 'eAllSessions' from ?

Moving on a pace or two ...........

Getting the Collection Item 'right' :

If we are to use a public property to bind to the ComboBox 'ItemsSource' attribute, then we need to add an

extra suitable property to the already defined 'Registration' class.

Here is the private field definition :-

=====================================================================

Which is then used in the normal way to provide a Public property definition as seen below :-

==============================================================

We simply need to make sure that for each Registration object instantiated, that this property is populated

in a suitable manner - see below for this property assignment or list property population.

========================================================

Yes, line 69 above shows the list population, but as well as doing this for the 'empty' Constructor, we

need also do something similar for the main non-empty Constructor - check it out below :-

=================================================================================================================================

In the above code, line 91 is the one we need focus upon.

Now then folks, what does the 'FillSessList' method look like / do ? See the full details in the next image :-

======================================================================

Okay then folks, so this means that each Registration object created has a property called 'eAllSessions'

which is a short list of all of the 'enums' values for 'SessionAttending'.

Think of it in the same ways as it the Registration object had a property which was a list of order numbers, or

a list of products which the person uses.

It would appear that the list property does have to be a property of the list / collection item, and not a property

of the ViewModel itself, I tried that and it did not work.

Lets leave this for now, as we seem to have made good and useful progress.

Next is some suitable reference material for us to follow up at a later date .................

External / Web sources of information :

Here is a good and useful URL / web link :-

http://stackoverflow.com/questions/5409259/binding-itemssource-of-a-comboboxcolumn-in-wpf-datagrid

And here is some of the visual material towards the end of the article :-

========================================================================================================================================

I think it is the 'CellEditingTemplate' which needs most of our attention :-

==========================================================================================================================================

Okay, fine for now, lets move on to the next sub-section.

See you there ..................

PHH - 19th. December 2014.


working script and code

=====================================================================================

//----- Registration.prg -----

//----- Monday December 8th. 2014. copied December 12th. -----

//----- 'as simple as it can get, and work correctly ! -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace VL15_Lists_01

    class Registration implements INotifyPropertyChanged

        //----- Fields -----

        private _registrationId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        private _company as string

        private _registrationDate as System.Nullable<System.DateTime>

        private _hasPaid as System.Nullable<logic>

        private _isAlone as System.Nullable<logic>

        private _newbie as System.Nullable<logic>

        private _eSessions as SessionsAttending

        private _eAllSessions as List<SessionsAttending>

        private _photoImage as string

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            //------- getting a 'NULL' ---------

            local oNDT as Nullable<DateTime>

            oNDT := Nullable<DateTime>{}    //----- without a value ------

            local oNLG as System.Nullable<logic>

            oNLG := Nullable<logic>{}

            //------------------------------------------------------------

            super()

            self:Initialize()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := "..."

            self:LastName := "..."

            self:Country := "..."

            self:Company := "..."

            self:RegistrationDate := oNDT

            //----------------------

            self:HasPaid := oNLG

            self:IsAlone := oNLG

            self:Newbie := oNLG

            //----------------------

            //self:eSessions := eS

            self:PhotoImage := "..."

            self:eAllSessions := self:FillSessList()

        return

        constructor(cF as string, cL as string, cCT as string, cCP as string, dtReg as System.Nullable<System.DateTime>,;

                    lP as System.Nullable<logic>, lA as System.Nullable<logic>, lN as System.Nullable<logic>,;

                    eS as SessionsAttending, cPhotoImg as string)

            super()

            self:Initialize()

            self:RegistrationId := -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            self:Company := cCP

            self:RegistrationDate := dtReg

            //----------------------

            self:HasPaid := lP

            self:IsAlone := lA

            self:Newbie := lN

            //----------------------

            self:eSessions := eS

            self:PhotoImage := cPhotoImg

            self:eAllSessions := self:FillSessList()

        return

        //----- Methods -----

        method Initialize() as void

        return

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return self:FirstName+" "+self:LastName

        method FillSessList() as List<SessionsAttending>

            local implied eAll := List<SessionsAttending>{}

            eAll:Add(SessionsAttending.None)

            eAll:Add(SessionsAttending.All)

            eAll:Add(SessionsAttending.AB)

            eAll:Add(SessionsAttending.AC)

            eAll:Add(SessionsAttending.BC)

        return eAll

        //----- Properties -----

        property eAllSessions as List<SessionsAttending>

            get

                return self:_eAllSessions

            end get

            set

                self:_eAllSessions := value

                self:NotifyPropertyChanged("eAllSessions")

            end set

        end property

        property RegistrationId as long

            get

                return self:_registrationId

            end get

            set

                self:_registrationId := value

                self:NotifyPropertyChanged("RegistrationId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        property Company as string

            get

                return self:_company

            end get

            set

                self:_company := value

                self:NotifyPropertyChanged("Company")

            end set

        end property

        property RegistrationDate as System.Nullable<System.DateTime>

            get

                return self:_registrationDate

            end get

            set

                self:_registrationDate := value

                self:NotifyPropertyChanged("RegistrationDate")

            end set

        end property

        property HasPaid as System.Nullable<logic>

            get

                return self:_hasPaid

            end get

            set

                self:_hasPaid := value

                self:NotifyPropertyChanged("HasPaid")

            end set

        end property

        property IsAlone as System.Nullable<logic>

            get

                return self:_isAlone

            end get

            set

                self:_isAlone := value

                self:NotifyPropertyChanged("IsAlone")

            end set

        end property

        property Newbie as System.Nullable<logic>

            get

                return self:_newbie

            end get

            set

                self:_newbie := value

                self:NotifyPropertyChanged("Newbie")

            end set

        end property

        //-----------------------------------------------

        property eSessions as SessionsAttending

            get

                return self:_eSessions

            end get

            set

                self:_eSessions := value

                self:NotifyPropertyChanged("eSessions")

            end set

        end property

        property PhotoImage as string

            get

                return self:_photoImage

            end get

            set

                self:_photoImage := value

                self:NotifyPropertyChanged("PhotoImage")

            end set

        end property

        //-----------------------------------------------

    end class

end namespace //----- VL15_VM02

=====================================================================================

//----- CollectionChangeViewModel.prg -----

//----- Tuesday 16th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace VL15_Lists_01

class CollectionChangeViewModel implements INotifyPropertyChanged

    private _oRegColl as ObservableCollection<Registration>

    private _oRegNew as Registration

    private _oOCsessions as ObservableCollection<SessionsAttending>

    //----- added for selection purposes -----

    private _oselectedReg as Registration

    private _selRegSum as string

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    constructor()

        super()

        oRegColl := DataModels.GetRegistrationCollection()

        self:Initialize()

    return

    //----- data comes in as 'Registration' object -----

    constructor(oRC as ObservableCollection<Registration>)

        super()

        oRegColl := oRC

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:oRegNew := Registration{}

        self:FillSessionsList()

        //self:oSelectedReg := Registration{}

    return

    method ClearInputs() as void

        MessageBox.Show("All data input to properties will GO !","Clear Inputs :")

        self:oRegNew := null

        self:oRegNew := Registration{}

    return

    method FillSessionsList() as void

        self:oOCsessions := ObservableCollection<SessionsAttending>{}

        self:oOCsessions:Add(SessionsAttending.None)

        self:oOCsessions:Add(SessionsAttending.All)

        self:oOCsessions:Add(SessionsAttending.AB)

        self:oOCsessions:Add(SessionsAttending.AC)

        self:oOCsessions:Add(SessionsAttending.BC)

    return

    method Add2Collection() as void

        oRegColl:Add(self:oRegNew)

        MessageBox.Show("Check the listed Collection !","Adding a new item :")

        self:ClearInputs()

    return

    method RemoveFromCollection() as logic

        local lOK := true as logic

        if self:oSelectedReg == null

            MessageBox.Show("Sorry, NO selected item !!??","One Item to Remove :")

            lOK := false

        endif

        if (self:oRegColl:Count < 1 .and. lOK)

            MessageBox.Show("Sorry, the Collection is empty !!??","One Item to Remove :")

            lOK := false

        endif

        //-----------------------------------------------------------------------------------

        if lOK

            MessageBox.Show(MakeSelRegSum(),"One Item to Remove :")

            oRegColl:Remove(self:oSelectedReg)

            MessageBox.Show("Check the listed Collection !","One Item Removed :")

            self:ClearInputs()

        endif

    return lOK

    method MakeSelRegSum() as string

        local cSelRegSum := "" as string

        cSelRegSum += self:oSelectedReg:FirstName + e"\n"

        cSelRegSum += self:oSelectedReg:LastName + e"\n"

        cSelRegSum += self:oSelectedReg:Company + e"\n"

        cSelRegSum += self:oSelectedReg:Country + e"\n"

        cSelRegSum += self:oSelectedReg:RegistrationDate:ToString() + e"\n"

    return cSelRegSum

    //----- Properties -----

    property oSelectedReg as Registration

        get

            return self:_oselectedReg

        end get

        set

            self:_oselectedReg := value

            self:NotifyPropertyChanged("oSelectedReg")

            self:SelRegSum := MakeSelRegSum()

        end set

    end property

    property SelRegSum as string

        get

            return self:_selRegSum

        end get

        set

            self:_selRegSum := value

            self:NotifyPropertyChanged("SelRegSum")

        end set

    end property

    property oOCsessions as ObservableCollection<SessionsAttending>

        get

            return self:_oOCsessions

        end get

        set

            self:_oOCsessions := value

            self:NotifyPropertyChanged("oOCsessions")

        end set

    end property

    property oRegNew as Registration

        get

            return self:_oRegNew

        end get

        set

            self:_oRegNew := value

            self:NotifyPropertyChanged("oRegNew")

        end set

    end property

    property oRegColl as ObservableCollection<Registration>

        get

            return self:_oRegColl

        end get

        set

            self:_oRegColl := value

            self:NotifyPropertyChanged("oReColl")

        end set

    end property

end class

end namespace   //----- VL15_Lists_01

=====================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

#using VL15_Lists_Of_All_Sorts

begin namespace VL15_Lists_01

    partial class DataGrid_myView inherit Window

        public _LTVM as ListsThreeViewModel

        public _CCVM as CollectionChangeViewModel

        constructor()

            super()

            InitializeComponent()

            self:_LTVM := ListsThreeViewModel{}

            self:Initialize()

        return

        constructor(oLTVM as ListsThreeViewModel)

            super()

            InitializeComponent()

            self:_LTVM := oLTVM

            self:Initialize()

        return

        constructor(oCCVM as CollectionChangeViewModel)

            super()

            InitializeComponent()

            self:_CCVM := oCCVM

            //self:Initialize()

            self:DataContext := self:_CCVM

        return

        method Initialize() as void

            self:DataContext := self:_LTVM

        return

    end class

end namespace

=====================================================================================

<Window x:Class="VL15_Lists_01.DataGrid_myView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="DataGrid_myView" Height="300" Width="540">

    <Grid>

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding eAllSessions}"

                            SelectedItem="{Binding eSessions}"

                            IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid AutoGenerateColumns="False"

                  Background="AliceBlue"

                  Margin="10"

                  ItemsSource="{Binding oRegColl}"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  SelectedItem="{Binding oSelectedReg}"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True">

            <DataGrid.Columns>

                <DataGridTextColumn Header="First" Binding="{Binding FirstName}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Country" Binding="{Binding Country}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="Company" Binding="{Binding Company}" Width="70" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Paid" Binding="{Binding HasPaid}" Width="50" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Alone" Binding="{Binding IsAlone}" Width="50" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Newbie" Binding="{Binding Newbie}" Width="50" CanUserResize="False"/>

                <!--===================================================================================-->

                <DataGridTemplateColumn Header="Sessions"

                                        Width="60"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

                <!--===================================================================================-->

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=====================================================================================

PHH - 19th. December 2014.


Chapter 9 - getting to grips with 'User Controls'

'UserControl' can be many things to many different developers.

They can be used in a way which is far from the standard MVVM pattern 'approach' to coding.

However, they can if used in a certain way, greatly help us guys adopt MVVM.

We can use UserControls to simplify our work with Views, ViewModels, and data binding generally.

UserControls can be coded to return data, but we won't do things that way normally.

We will use a UC like a Window - to show you what is possible.

https://msdn.microsoft.com/en-us/library/system.windows.controls.usercontrol(v=vs.110).aspx

[ .. Remember - UserControls often go 'hand-in-hand' with 'ContentControls' - see later subsections .. ]

=========================================================================

Okay then guys, think of the special feature on your TV set which is called "picture-in-picture".

Well, when we place a UserControl on a Window via a receiving 'ContentControl' we effectively have

a 'window-in-window' type of situation. AND, we get more screen space (real estate) by doing so.

To all intents and purposes our UserControl can be seen as a window, and not even a small one. In fact

a UserControl can appear to be quite a large window - and can also be scrolled in both directions in its

containing UI element, if that is what we want or need.

*** NOTE *** we can't have a 'Window' in a 'Window' - we get an error as the following image shows when I tried

to do just that - check this out :-

=================================================================

Since all windows must be at the root, we need to add a 'UserControl' to the Window tree to get the effect

of 'picture-in-picture'.

Lets take a look at a simple example - one we will see how to create ourselves.

Study the following image carefully :-

[ .. the red bounded area is the UC ..]

================================================================================================================

And now we change the UC to be the green bounded area, simply by clicking the on-screen button.

Check this out below :-

=======================================================================================

The UC can be a simple or as complex as we care to make it, BUT, keep things as simple as possible ;-0)

Below is the XAML script for a new, and so far empty, UserControl called 'ucAttendeeEditExisting' :-

=============================================================================================

And here is the .NET stub code in Vulcan :-

=============================================================================

Obviously, UserControls can be created and used in Vulcan 3 as well as C#. However, at the moment

there are a couple of issues with VN3 that we need to know how to work around.

I will not write much more about this as Willie Moore may come up with a suitable Template, like the one

I am currently using in C#.

In the following image we can see two obvious UC's highlighted - check below :-

==================================================

One other aspect of UserControls we need to explore is that we can create a Library of them.

This "UserControlLibrary" seems to be a standard feature of C# - see below for an illustration of this :-

======================================================================================================================

PHH - 9th. & 24th. December 2014. & February 8th. 2015.


What is a UserControl ('UC') ?

Well folks, this is not a difficult topic to explain BUT we would do best to take and study an analogy.

Normally, I don't like using analogies, simply because usually they are poorly chosen.

In this case my analogy to follow seems well suited to the task.

Think of objects, and how a Custom / Business object is often made up of properties of standard data types.

I often refer to Custom classes as 'Complex Data Types'.

When we have a Custom class we also often provide methods (members) to find, calculate, and return data

from the class of object, which makes it very functional and not just a collection of basic / standard types.

So to summarise the above, we have basic data types and objects which are complex data types, made from

a bunch of standard types. Think of this as a 'User Data Object'.

Okay then folks, lets move our mental attention from data to visual elements - UI elements.

In WPF we have a Toolbox which contains a whole group of basic 'visual' controls.

However, we can build a complex visual control (called a 'UserControl') from a group of standard controls.

As well as defining a bunch of basic controls to be our 'UC' we can also provide code and members to find,

calculate, and return processed data - just as we did for complex data objects.

If you like, think of a UserControl (UC) as a 'Super' control - a 'Complex' control - and on top of this (extra to this)

we can even (also) add UCs to our toolbox.

So guess what !? We can reuse UCs over and over again, just as we do a data object class.

Or even think of a UC as a 'Visual Object', perhaps !?

Once we have a new UC in our project (and SE pane) we can drag this onto our Toolbox and release the mouse

button, so that the new 'tool' shows up for Toolbox use.

Although I have made this clear and seemingly 'simple', I am sure that UserControl technology can get complicated

if we go deep enough. The good news to us is that we can use UCs with MVVM without much of a problem.

Try to keep your use of UserControls as simple as possible. I have copied (from Nick Friend?) a method of use

which is simple, reliable, and quite robust - I will try and show you this during the subsections of this chapter.

Now the other side of a UC is that it is a 'Control' made by a user, and as such can be included in the Toolbox,

and then used directly from there.

Shown below is a short list of some I have made - sorry for the boring names ;-0((

=====================================================================

PHH - 24th. January 2015.


How is a UC used ?

We are going to use our UCs like 'Windows', and swap them in and out of the ContentControl on

another 'Hosting' Window. So that we effectively get "picture-in-picture" or for us "window-in-window".

However, on a general level of understanding, UCs are used over and over, in many places, like .NET

data objects - to save time and coding and scripting.

If we have placed a UC in the general Toolbox then we can drag and use it from there on our XAML

designer surfaces.

We even ought to be able to use a UC on another UC, although as yet I have not tried it. But if this

works for standard Controls then why not !?

PHH - 24th. January 2015.


Making our first UC in Visual Studio

Before we get into the child sections from here, where we see both C# and Vulcan.NET used to code

the files behind the XAML script stuff, lets see two important - and different - ways we can display a UC

(UserControl) on a WPF window (form).

Again we can use a data analogy - that of a constant numeric value and a variable with a value that can be changed

at runtime and determined by coded logic.

We can place a UC directly on a WPF / XAML designer surface, but this will remain fixed at runtime.

However, we can use a 'container' class instead, and this can be assigned any existing UC object at runtime.

Which specific UC is determined by code and business logic.

First lets see an example of the first case - the fixed UC placed directly on the UI surface - check below :-

=======================================================================================================

The script at line 8 in the above image, came from dragging a suitable UC from the Toolbox - see an example

of such a Toolbox entry in the following image :-

=====================================================================

We will see how more UCs get added into the Toolbox, later.

And here we need to see the state of the SE pane - study the full contents :-

[ .. we are in the process of dragging the second UC to the Toolbox pane to join the first one we placed there .. ]

==========================================

Now then, we can place a container element, called a 'ContentControl' on the XAML surface, and at run time

this container can be assigned any UC we have access to - so its like a variable been given any available and allowable

value, determined by business logic.

Here is the situation described above - the larger UC is scrolled in both direction from the smaller container CC

or 'ContentControl' - check below :-

==========================================================================================================

And of course, if the UC is a control (whether it is in the Toolbox or not) we can have it on our WPF forms

more than once, just as any other UI element / control.

Below is a helpful example where we have the same UC (number one) twice on our main window form :-

==================================================================================

As we see things above, we have the same data in both list box instances, but this will not usually

be the case.

Before we see different data inputs, lets just see what we have for the above image display - check below :-

==============================================================

As you can see above we are building the string data list at time of instantiation. So any instance of our

UC will have the same list of names.

Here is the XAML script which goes along with it :-

==============================================================================================================

And because we are effectively dealing with two windows, then we need to see the script for the main window, as we

have already seen above that for the UC itself.

Checkout thoroughly the script details below :-

===============================================================================================================

Okay then guys, that seems good - BUT - what about some different data ?

Let us now change the code such that we supply the data as input (injection?) to the Constructor

of the UC, such that we get the following type of runtime display :-

======================================================================================

In the above image we have two quite different list of string names - people and places.

Here is how the C# code looks :-

====================================================================

Note in particular the lines 42 & 43 where we are instantiating two instances of the UC number one.

We could actually supply as inputs and list of strings we care to use.

Short Summary :

We can have multiple ContentControls on our form showing many different instances of UCs, either

similar or different in nature - UC1+UC1+UC1 or UC2+UC3+UC4 type of situation.

Okay then folks, we have seen how to set-up UCs and use them in some differing ways - BUT - we now

need to look at how we use VS 2013 to create them in the first place - the 'nuts and bolts' as it were ;-0)

See you in the next subsection where we will do just that ..................

PHH - 24th. & 26th. January 2015.


C Sharp - C#

Lets do some exploring and some experimenting ;-0)

Open up VS 2013 and start a completely new solution which is C# based as well as WPF.

Just make our solution/project a standard WPF one - as see below :-

=================================================================================================================

Above we have a new project of type WPF desktop.

After clicking OK we see the following in our SE pane - check these details :-

================================================

So as you can see above, we have a main Window and nothing else - check the XAML below :-

===========================================================================================

And now the .NET code and the runtime display :-

======================================================================

So far so good you guys, but as yet no sign of any UCs !!

Lets now put that to rights and add one, then two, three and four new UserControls.

lets try our first one - highlight the Project node in the SE pane and right click to bring up the

context menu - see the following image details :-

=====================================================================================

Now then folks, at this point we need to take CARE as we can select two different UCs and only

one of them is correct for what we require.

First of all lets see the right one - study the following details VERY carefully :-

================================================================================================================

Above you must recognise the "WPF" in the Template name, as well as the '.xaml' in the Name at the bottom of dialog.

*** WARNING *** do not do this shown next below :-

===================================================================================================

Above we see no "WPF" in the name, and we have '.cs' in the Name and not '.xaml'.

If you do it right then the SE pane contents looks like this below :-

==================================================

And then when we examine the new code and script files we see the following - check these :-

[ .. notice the main tags are 'UserControl' and not 'Window' .. ]

=====================================================================================================

And the corresponding C# .NET code file looks similar to the one shown below :-

=================================================================

Now then guys, while we are at it we may as well add a few more UC 'stubs' ready for use later.

Here is what I have at my end after adding a total of four UCs - check this out below :-

=============================================

And once we have UCs in our SE pane (as part of our solution) we can actually drag them

from the SE pane and drop them into the Toolbox and they 'should' go there if we do it right.

Here is one of my attempts :-

=============================================================

And here also are some images of the DnD process :-

=========================================================================================

=====================================================================

====================================================

==================================================================

===============================

=========================================================================================================================================

======================================================================================================

==================================================================================================================

====================================================================================================

=========================================================================================================================

==============================================================

=====================================================================================================

====================================================================

And that's about it for now - you have seen the further development details in the earlier subsection.

Now in this section you have seen how to create UCs and make them available to both code and visual designer.

Lets move on .............

The working code for this C# sample is in the child subsection from here.

See you in the next section where we can go on to learn more ;-0)

PHH - 25th. & 26th. January 2015.


working script and code

==========================================================================

<Application x:Class="WpfAppTryUCs.App"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             StartupUri="MainWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

==========================================================================

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Threading.Tasks;

using System.Windows;

namespace WpfAppTryUCs

{

    /// <summary>

    /// Interaction logic for App.xaml

    /// </summary>

    public partial class App : Application

    {

    }

}

==========================================================================

<Window

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfAppTryUCs" x:Class="WpfAppTryUCs.MainWindow"

        Title="Main Window - for UserControl tests :" Height="350" Width="525"

        Background="Beige">

    <Grid>

        <Border BorderBrush="Red" BorderThickness="3" Width="190" Height="190"

                Margin="10,10" HorizontalAlignment="Left"

                VerticalAlignment="Top">

            <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">

                <ContentControl ScrollViewer.CanContentScroll="True" Width="Auto" Height="Auto"

                                ScrollViewer.HorizontalScrollBarVisibility="Visible"

                                ScrollViewer.VerticalScrollBarVisibility="Visible"

                                Name="ccTest01" Background="AliceBlue">

                </ContentControl>

            </ScrollViewer>

        </Border>

        <Border BorderBrush="Red" BorderThickness="3" Width="190" Height="190"

                Margin="300,10,0,0" HorizontalAlignment="Left"

                VerticalAlignment="Top">

            <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">

                <ContentControl ScrollViewer.CanContentScroll="True" Width="Auto" Height="Auto"

                                ScrollViewer.HorizontalScrollBarVisibility="Visible"

                                ScrollViewer.VerticalScrollBarVisibility="Visible"

                                x:Name="ccTest02" Background="AliceBlue"/>

            </ScrollViewer>

        </Border>

    </Grid>

</Window>

==========================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfAppTryUCs

{

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

            List<string> aListN;

            aListN = new List<string>();

            aListN.Add("Elizabeth");

            aListN.Add("Valerie");

            aListN.Add("Richard");

            aListN.Add("Henry");

            aListN.Add("William");

            aListN.Add("Margaret");

            //--------------------------

            List<string> aListN2;

            aListN2 = new List<string>();

            aListN2.Add("Sunderland");

            aListN2.Add("Manchester");

            aListN2.Add("London");

            aListN2.Add("Birmingham");

            aListN2.Add("Durham");

            aListN2.Add("Newcastle");

            this.ccTest01.Content = new UserControl1(aListN);

            this.ccTest02.Content = new UserControl1(aListN2);

        }

    }

}

==========================================================================

<UserControl x:Class="WpfAppTryUCs.UserControl1"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             mc:Ignorable="d"

             d:DesignHeight="300" d:DesignWidth="300">

    <Grid>

        <Button Content="Test UC1" HorizontalAlignment="Left" Margin="10,10,0,0"

                VerticalAlignment="Top" Width="75" Background="Coral" Height="26"

                FontSize="13" FontWeight="Bold"/>

        <ListBox HorizontalAlignment="Left" Height="100" Margin="10,52,0,0"

                 VerticalAlignment="Top" Width="140" Background="Lavender"

                 Name="lbxUC01" ItemsSource="{Binding}"/>

        <TextBox HorizontalAlignment="Left" Height="23" Margin="10,178,0,0"

                 TextWrapping="Wrap" Text=".. change me !!" VerticalAlignment="Top" Width="140"/>

    </Grid>

</UserControl>

==========================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfAppTryUCs

{

    public partial class UserControl1 : UserControl

    {

        public UserControl1()

        {

            InitializeComponent();

            this.Initialize();

        }

        public UserControl1(List<string> aList)

        {

            InitializeComponent();

            this.Initialize(aList);

        }

        public void Initialize()

        {

            List<string> aListN;

            aListN = new List<string>();

            aListN.Add("Thomas");

            aListN.Add("Richard");

            aListN.Add("Henry");

            aListN.Add("William");

            aListN.Add("Matthew");

            this.lbxUC01.DataContext = aListN;

        }

        public void Initialize(List<string> aList)

        {

            this.lbxUC01.DataContext = aList;

        }

    }

}

==========================================================================

<UserControl x:Class="WpfAppTryUCs.UserControl2"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             mc:Ignorable="d"

             d:DesignHeight="300" d:DesignWidth="300">

    <Grid>

    </Grid>

</UserControl>

==========================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfAppTryUCs

{

    /// <summary>

    /// Interaction logic for UserControl2.xaml

    /// </summary>

    public partial class UserControl2 : UserControl

    {

        public UserControl2()

        {

            InitializeComponent();

        }

    }

}

==========================================================================

==========================================================================

PHH - 26th. January 2015.


Vulcan - VN3

PHH - 25th. January 2015.


Multiple UCs on one WPF form

What do we mean by 'Multiple UCs on one WPF form' ?

Remember, a "UserControl" (UC) is actually just a bunch of standard Toolbox controls.

[ .. Okay, and it could include another UC if its a bit more complex ! .. ]

Firstly, we could mean that we have two or three (or more) UCs on the WPF window at any one time.

Like in the following image where we have two UC's at once showing on screen (visually) :-

=========================================================================================

Above we have two separate instances of a UC being displayed on the one form.

However, for our MVVM approach purposes I mean having one main 'hosting window, and with one

ContentControl ('CC') on that form / window.

The content of the CC is one of a few different UCs, being swapping in and out by code at runtime.

This situation is a common practise with Tablet and ASP.NET type developers it would seem.

Why use a 'ContentControl' on the form ? :

Well, folks the simple answer is to give us flexibility - with our design, development, and coding.

Although we could place a same UC directly on the hosting form, we would then be stuck with this

at runtime, and without being 'Master' coders, we would need to make any changes at a XAML script

and .NET code level.

This direct placing of a UC on a form is a bit like hard coding values (constants) without taking full

advantage of variables.

=====================================================================================================

We could even place more than one UC of the same type on the 'base' form.

However, we will see how to improve this a lot more by adding a 'container' UI element called a 'ContentControl'.

At runtime we can make loose couplings of UCs to CCs from logic code.................

Checkout the following .NET code from a working solution :-

=====================================================================

The above code display two different instances of the same UC type, one in each CC element.

Also note that a CC can be coupled with any type of UC we care to choose to use. So this approach

is VERY flexible indeed !

It seems to me that we should get used to using 'ContentControl's at ALL times, as they give us the most

amount of flexibility.

PHH - 24th. January 2015.


Flexibility - using 'ContentControl's for UC swap in/out

PHH - 5th. February 2015.


Single but varied - successive

What do we mean by 'Multiple UCs on one WPF form' ?

Well, we could mean that we have two or three (or more) UCs on the WPF window at any one time.

However, for our MVVM approach purposes I mean having one main 'hosting window, and with one

ContentControl ('CC') on that form / window, swapping in and out from code different UCs which are provided

as content to the CC.

This is a common practise with Tablet and ASP.NET type developers it would seem.

In Metro style tablet apps the single (main) Page object can have a number of UCs swapped in / out depending

on user input to other Page elements at runtime.

Here is an example of mine :-

==============================================================================

In the above image the central square area, bounded with a blue line, is actually the 'ContentControl'

with a 'Content' attribute associated with an instance of a Customer UC.

The associated instance can be changed at runtime to also be one of type Product or Supplier.

Here is how the XAML design surface and script text editor looks for the above :-

==================================================================================================================================

So when we use the above approach we usually need to provide a default UC association. I think

mine is set to Customer - of course you could leave it 'blank' or 'null'.

Here is a Product UC association at runtime :-

===========================================================================================

In the above WPF Window a button click changes the association on the ContentControl.

Although we are not doing full MVVM in these eNotes, here is the working code from my application

which changes the association. This is the 'Controller' model approach :- [ .. lines 58, 62, & 66 .. ]

===================================================================================================

In the above code, we have a shell 'View' window and the appropriate UserControl is being loose coupled.

Here is a more clear view of the relevant code text :-

================================================================================================================================

PHH - 5th. February 2015.


Many at once

This is a simple enough scenario, one in which the main window, or hosting form, has a bunch of

different 'UserControl's (UCs) - apparently on the same form 'surface'.

So the UCs can be directly placed on the form like any Toolbox item, "side by side" etc., or indeed

placed in 'ContentControl's at form instantiation / runtime, by setting the 'Content' property of a few

CCs placed on the form from the Toolbox.

So 'Many at Once' means a few UC placed directly on the Window, or as content to CC's, or indeed

a mixture of both approaches.

The following image shows just two adjacent CC's with coupled UCs. Note the coupling takes place in the

code on lines 43 and 45 - check out the full details below :-

==================================================================================================================================

Notice that in the above code the collection data is injected on line 43 into the

constructor of the UC for type 'UserControl1' - sorry for the uninteresting naming !

===================================================================

PHH - 5th. February 2015.


'Nested' UC's and Binding - possible or not !?

By 'Nesting' we mean having one UserControl within another, and being able to bind data from

the hosting form level, through the UC 'layers', one to the other and so on.

Although you may seldom (or never) do this, it is always a good idea to push things to the limit

just to see if 'stuff' works as we think it should.

PHH - 5th. February 2015.


What is a 'ContentControl' and how to use it

When it comes to UI elements (or controls) we are often best advised to start in the Toolbox.

Let us look in the Toolbox for the 'ContentControl' - check below :-

===============================================

Yep! - we can clearly see it in the "All WPF Controls" section.

However, it is missing from the shorter section entitled 'Common' WPF Controls - see the

image shown below :-

=========================================

And if we drag a copy of the 'CC' onto the design surface we end up with something similar to that

seen in the following image - check out thoroughly :-

======================================================================================

We need to be aware that unless we 'populate' the 'Content' attribute / property, we will see absolutely

nothing on the form/window at runtime. This is true even if the Background is suitably defined.

Lets see how using code we can make an association to the 'Content' property :-

========================================================================

So in the above code we are providing two CCs each which have had some data injected into them.

Lets now see what the XAML design and editor surfaces look like - checkout below carefully :-

[ .. note that we often have CCs nested within containing elements like 'Border' and 'ScrollViewer' .. ]

=======================================================================================================================

So how does this all look at runtime ?

Lets run the application and scroll the list data a little - checkout this below :-

=========================================

Let us realise with the above example, that the 'UserControl' screen area may be larger (or smaller) than

the actual screen area allowed by the CC itself.

However, so as not to annoy our users we ought to try and reduce the amount of screen scrolling to as

little as we can - so try and match up the two areas, CC and UC when at all possible.

General Comment on CC and UC use :

It seems from eBook and web learning material that for MVVM type of use (and Metro style as well), we

have 'complex' UCs being swapped in and out of CC's at runtime.

We do not see 'direct' use of a UC on the form surface.

This approach greatly enhances the 'real estate' or screen UI surface available to the developer for form design.

We can also reuse UCs with more than one WPF window / form. So for example a "Customer" UC may be

used on any form where we wish to have access to Customer details. As too a UC for 'Suppliers', and 'Products'.

PHH - 7th. February 2015.


Simple use of 'CC'

Let us do some scripting and coding to explore the simple use of 'ContentControls' in WPF.

Here below is a simple start, two CCs and two associated code assignments.

Study the following details :-

==============================================================================================================================

Lines 23 & 25 above are those related to the two areas on the main form.

However, if we examine the XAML script we see below that we have two other CCs which are not

showing up on the form at runtime - check this out :-

===============================================================================================

Also notice that the three assignments for colour and thickness do not seem to show-up in any way.

So we can simplify further the XAML script required, to that seen below :-

=================================================================================================

And the .NET code to accompany this is seen in the following image :-

======================================================================================================================================

Notice above that we have assigned to all four of the defined CCs - but we do need to make some

improvements by assigning values to attributes on each of these CCs.

The 'GroupBox' needs a title/header and the ComboBox is far too deep (or high).

Making some Code Assignments :

Let us start with the DataGrid and the assignment to CC number one.

First we need at least a simple list collection, then we can make the assignment.

Study the .NET code below and notice what the default column is :-

================================================================================================

In the above image I have sorted the 'Length' field, or column, so that the value for 'Elizabeth' is now

at the bottom - it is '9'.

Obviously, Henry is '5'.

Why we get 'Length' I am not sure, but I am aware that this is the sort of thing we see when we do

not define use our own custom class in a collection.

It would appear that the default 'ToString' method for a data grid item is the Length value to string.

Since this is NOT really the point at issue here, lets leave this for now and move on.

In the above image, note lines 41 through 43, where we create and set the DataGrid attributes.

Now we can move on to the third CC and see how we make a different assignment.

Check below how we create a second list collection, as well as making a suitable ListBox in

which to display it - study the following carefully :-

======================================================================================

Okay then, simple and yet no surprises ;-0)

What about our GroupBox ? Let us try and improve that - check below :-

==================================================

That seems okay for a first start - BUT - we do need more work I feel.

Lets try and add a bunch of 'RadioButton' elements. Here is our first try, seen in the image shown below :-

==================================================================================

Yes, it works nicely - BUT - all four RBs are one on top of the other - in the same place.

An easy way to rectify this problem is to use a 'StackPanel'.

Study the following details carefully :-

========================================================================================

Note that I made the third button selection by clicking with my mouse, it was not done by code or script.

For our RBs to appear 'better' we need to define them separately - HOWEVER - we must not get carried

away as we have to stick to our real purpose in this sub-section, that of CCs and UCs, not their element

details.

Lets move on a pace or two ..............

Improving the ComboBox :

Lets make the ComboBox a suitable size, before we add content to it - check this out :-

===========================================================================================

After making the resize work for us above, lets see how the whole form looks :-

===========================================================

Yes, that is better, now we need to supply some data - it is an easy one line task :-

[ .. two if you include setting the selected list item .. ]

================================================================================================

Lets see if Henry is the fourth collection item, and below I am just hovering the mouse pointer over 'Valerie'.

=================================

Now then folks, we need to remind ourselves that the XAML script has got very little within it, just the

specification of the four 'ContentControl's - revisit the XAML script shown below :-

=================================================================================================

And finally, before we leave this subsection, remember that this is just the easy and simple way to use

CC's, and that we are probably better served every time by using a UserControl to assign to the 'Content'

attribute / property of the CC - using a loose coupling approach.

The loose coupling of UC's (UserControls) is cover in depth in other subsections.

Let move on ........... see you in the next section.

PHH - 7th. & 8th. February 2015.

Addendum :

For some learning opportunities I have made a first effort to tidy up the RadioButtons

within the GroupBox.

Here is what I now display at runtime :-

================================

And here is the .NET code which produces the changes shown above.

I suggest that you try this for yourself, and a few other related changes as well - have a 'play' and experiment !

===========================================================

PHH - 8th. February 2015.


working script and code

==============================================================================

<Window x:Class="WpfAppTryUCs.SideWindowMy1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="SideWindowMy1 - Tesing 1,2,3,4 :" Height="400" Width="500"

        Background="Bisque">

    <Grid>

        <Grid.Resources>

            <Style TargetType="ContentControl">

                <Setter Property="Width" Value="160"/>

                <Setter Property="Height" Value="146"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <ContentControl Name="ccOne" Content="{Binding}" Margin="25,22,0,0"/>

        <ContentControl Name="ccTwo" Content="{Binding}" Margin="258,22,0,0"/>

        <ContentControl Name="ccThree" Content="{Binding}" Margin="25,189,0,0"/>

        <ContentControl Name="ccFour" Content="{Binding}" Margin="258,189,0,0"/>

    </Grid>

</Window>

==============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace WpfAppTryUCs

{

    public partial class SideWindowMy1 : Window

    {

        public SideWindowMy1()

        {

            InitializeComponent();

            List<string> aListN;

            aListN = new List<string>();

            aListN.Add("Elizabeth");

            aListN.Add("Valerie");

            aListN.Add("Richard");

            aListN.Add("Henry");

            aListN.Add("William");

            aListN.Add("Margaret");

            //--------------------------

            List<string> aListN2;

            aListN2 = new List<string>();

            aListN2.Add("Sunderland");

            aListN2.Add("Manchester");

            aListN2.Add("London");

            aListN2.Add("Birmingham");

            aListN2.Add("Durham");

            aListN2.Add("Newcastle");

            //-----------------------------

            DataGrid oDG = new DataGrid();

            oDG.AutoGenerateColumns = true;

            oDG.ItemsSource = aListN;

            this.ccOne.Content = oDG;

            //----------------------------------

            ComboBox oCB = new ComboBox();

            oCB.Height = 26;

            oCB.ItemsSource = aListN;

            oCB.SelectedIndex = 3;

            this.ccTwo.Content = oCB;

            //----------------------------------

            ListBox oLB = new ListBox();

            oLB.ItemsSource = aListN2;

            this.ccThree.Content = oLB;

            //-----------------------------------

            GroupBox oGB = new GroupBox();

            oGB.Header = "Our Test GB : ";

            oGB.BorderThickness = new Thickness(3);

            oGB.BorderBrush = Brushes.Violet;

            RadioButton oRB1 = new RadioButton();

            oRB1.Content = "Fee";

            oRB1.GroupName = "ContentGroup";

            oRB1.Margin = new Thickness(20, 20, 0, 0);

            oRB1.IsThreeState = true;

            oRB1.IsChecked = true;

            StackPanel oSP1 = new StackPanel();

            oSP1.Children.Add(oRB1);

            RadioButton oRB2 = new RadioButton();

            oRB2.Content = "Fi";

            oRB2.GroupName = "ContentGroup";

            oRB2.Margin = new Thickness(20, 0, 0, 0);

            oRB2.IsThreeState = true;

            oSP1.Children.Add(oRB2);

            RadioButton oRB3 = new RadioButton();

            oRB3.Content = "Foe";

            oRB3.GroupName = "ContentGroup";

            oRB3.Margin = new Thickness(20, 0, 0, 0);

            oRB3.IsThreeState = true;

            oSP1.Children.Add(oRB3);

            RadioButton oRB4 = new RadioButton();

            oRB4.Content = "Fumb";

            oRB4.GroupName = "ContentGroup";

            oRB4.Margin = new Thickness(20, 0, 0, 0);

            oRB4.IsThreeState = true;

            oSP1.Children.Add(oRB4);

            Grid oG = new Grid();

            oG.Children.Add(oSP1);

            oGB.Content = oG;

            this.ccFour.Content = oGB;

            //-----------------------------------

        }

    }

}

==============================================================================

<Application x:Class="WpfAppTryUCs.App"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             StartupUri="SideWindowMy1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

==============================================================================

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Threading.Tasks;

using System.Windows;

namespace WpfAppTryUCs

{

    /// <summary>

    /// Interaction logic for App.xaml

    /// </summary>

    public partial class App : Application

    {

    }

}

==============================================================================

PHH - 8th. February 2015.


Solution Explorer pane - grouping UCs and 'View's

This should be a sort sub-section, but one which is worth studying, and the detail being

though about carefully, and clearly.

If we are to use UCs in our MVVM type development pattern, and to fully utilize the use of

UCs like windows, swapping UCs in and out of the 'Content' property of a ContentControl, then

we need to have a way of managing the SE (Solution Explorer) pane to make our lives easier,

and out application both easy to read, as well as easy to edit and maintain.

Here is what I am starting to explore for myself.

Make a folder in the SE pane for each custom class or 'entity', or even both. Then place in this

folder both Window and UserControl classes.

Checkout the example below, where I have started to organise the 'Attendee' related UI screens.

[ .. we need to do the same for the others ... Speaker, Session Presentation etc. .. ]

=====================================================

My future plan, partly shown above, is to have UCs in one specific folder shown on Windows also

in that same specific folder.

However, there will be times where we may wish to display a UC fron one entity folder on a Window from another.

For example we may have a form called 'General Information' on which we display UC's for Attendee, Speaker, Session,

and LectureRoom. In which case this may limit functions on each UC to just be 'Display' and no changes. So we

may have a UC called 'ucAttendeeDisplay' and others similar for Speakers etc., etc..

I need to do some more work on this project / solution to see how the work unfolds.

May I STRONGLY suggest that we try at all times to keep out SE pane as clean, clear, and organised as possible.

Doing so definitely makes coding and scripting a lot easier, and more successful.

PHH - 24th. January 2015.


UCs - single purpose use or varied target use

PHH - 24th. January 2015.


UC - a Control or a Window !?

One simple way of looking at using UserControls (UCs) in our WPF applications is that it effectively

gives us an infinite surface on which to place other UI elements and controls.

In American 'speak' it increase the "Real Estate" - or makes our window surface larger.

So the basic idea is to only display in the 'ContentControl', that UC which is appropriate to the task in hand.

We saw a good example of that in an earlier sub-section when we had Customers, Products and Suppliers

UCs being swapped in and out.

So I suppose I have been using my UCs as Windows when we look at my coding for MVVM style apps.

Other developers may wish to focus on the 'Complex Control' aspect of this, and even process and return data

from the defined UC.

Also folks, don't forget that define UCs will also be able to have Dependency Properties defined, such that these

may then be bound to our ViewModel public properties, if required to do so.

I did warn you that there was 'simple' and there was 'complex'.

We need to see how to create and use such a UC as described above.

PHH - 24th. & 26th. January 2015.


UC with 'Dependency Properties', and binding

Don't panic about this, we will sort it out !!!

There is a lot of web confusion as usual ;-0)

http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html

http://stackoverflow.com/questions/16471876/binding-on-dependencyproperty-of-custom-user-control-not-updating-on-change

http://www.scottlogic.com/blog/2012/02/06/a-simple-pattern-for-creating-re-useable-usercontrols-in-wpf-silverlight.html

PHH - 26th. January 2015.


We should use UCs more widely in our apps

Over the years I have seen some amazing screens / forms for user inputting of data.

The one common error developers make is that they make their input forms to busy, they

try to do too much. The screen is 'cluttered', and their is more than one obvious focus.

Some of us even took pride in our complicated screens - and often far too much data was

on show as well.

Basically, all of our forms were far too 'flat', we did not nest functionality enough at all.

Here is one of my earliest WPF input forms, I would not do it like this today ;-0))

=========================================================================================

In the above Invoice window we can see four group boxes and these could all be moved onto a UC

and displayed separately, one after another.

What we need to take SERIOUSLY on-board is that after using smart-phones and tablets the

vast majority of us are more than used to clear clean, and in many ways 'simple' input screens.

It is NOT fashionable to be messing around on detailed forms.

So lets take advantage of swapping in / out 'UserControl's, which does two things for us - keeps

the screen clear by only showing what is being done at the time, as well as giving us far more

space (real estate) for out screen size.

This approach also takes into account that we need to develop apps which can be 'touch driven',

whether we like it or not.

It may even be a useful exercise for me to redesign the above screen in a more modern way, using

UC's where I can, and keeping every level more clean and tidy.

Here is a possible 'new' structure - see the next three images :-

[ .. the larger centre element is a ContentControl bounded by Border and ScrollViewer .. ]

============================================================================================

Above we see a UserControl ('ucFrontScreen') assigned to the CC's Content attribute / property.

When the 'Customer' button is pressed we get a different UC assigned to the CC - check this :-

===========================================================================================

Wow ! - now we have another ('nested') CC with UC - assigned below after clicking the 'Select' button.

[ .. below is a red bounded CC within a blue bounded UC .. ]

======================================================================

Okay folks, as yet we have no data in the Customer list box, but you get the idea !?

If you now look back to the top of the sub-section you will see that we now have a VERY different

looking application screen and main window - yet it will eventually do the exact same job.

It also looks much more 'touch aware' (touchable?) - and can be expanded / contracted to fit the

various formats of the different UCs assigned.

Lets now add some data to this, just for the Customers, so that you can get a flavour of the final

application - if it ever gets finished ;-0)

Lets look at the working code for the Customer class - check below :-

=================================================================================

As usual (seen above) we have a bunch of private fields matched up with a bunch of public properties.

Each time a public property is changed (or given a value) it sends notification to the system keeping

track of things in the background.

Here are the necessary members for the 'INotificationPropertyChanged' interface to be implemented :-

=================================================================================

Lets now move on to see part of the STATIC method to provide for hard coded suitable Customer

data - check fully below :-

=======================================================================

I chose the above approach to populating the properties, since a long or complex 'Constructor' may

well have caused more problems than it solved.

We now have four entries to the Customer data table, virtual though it is right now ;-0)

Lets now populate the list box with the first three of these (I did this before adding the fourth item) :-

====================================================================================

Okay then folks, we get three list entries but they look pretty poor as 'CustomerCS' !

Before we improve this, lets see how the item list was bound to the UI element - check below :-

===================================================================================================================

In order to get the improved output (display) shown below, all we need is an new 'ToString' method - study this :-

==================================================================================================================================

Obviously, we can make the new ToString method almost whatever we like, or choose.

And now we can see the fourth Customer entry I talked of earlier :-

[ .. it is Ben and not the highlighted item .. ]

=====================================================================================

So far we have placed the Customer class in a new folder in our SE pane. We now have the

folder named 'OurClasses' as seen below :-

===============================================

The class is called 'CustomerCS' simply because it is the C# version of Customer, and there

will be a Vulcan version as well.

Now then guys, what of a better format for the list items in the collection ? Study the details shown beneath :-

=======================================================================================

The second list item is selected in the above image.

So we need to view and study the template for the item data.

In the following image we see the 'DataTemplate' used, and easily can pick out the text and font

formatting - bold, italic, colour etc.

===============================================================================================================

And there is no pint having a data template without some relevant XAML script to apply it to our list box data items.

Study the next image carefully :-

=================================================================================================================

Okay then folks, you have probably seen enough in this subsection to suggest ways of using CCs and UCs in a

productive fashion.

Lets see if we can make more use of these controls in our WPF / XAML in future.

See you in the next section ..............

PHH - 24th. January & 10th. February 2015.


working script and code

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//---------------------------------------

using WpfUCsInvoices.UserControls;

namespace WpfUCsInvoices

{

    public partial class MainWindow : Window

    {

        private ucFrontScreen ucFS;

        private ucCustomer ucCust;

        private ucInvoice ucInv;

        public MainWindow()

        {

            InitializeComponent();

            this.Initialize();

        }

        public void Initialize()

        {

            this.ucFS = new ucFrontScreen("BEST Invoices - Front Screen !!");

            this.ccInvoices.Content = this.ucFS;

            this.ucCust = new ucCustomer();

            this.ucInv = new ucInvoice();

        }

        private void pbCustomer_Click(object sender, RoutedEventArgs e)

        {

            this.ccInvoices.Content = new ucCustomer();

        }

        private void pbInvoice_Click(object sender, RoutedEventArgs e)

        {

            this.ccInvoices.Content = new ucInvoice();

        }

        private void pbViewDetails_Click(object sender, RoutedEventArgs e)

        {

        }

        private void pbSave_Click(object sender, RoutedEventArgs e)

        {

        }

        private void pbPrint_Click(object sender, RoutedEventArgs e)

        {

        }

        private void pbSettings_Click(object sender, RoutedEventArgs e)

        {

        }

        private void pbExit_Click(object sender, RoutedEventArgs e)

        {

            this.ccInvoices.Content = new ucFrontScreen("Application closing - BEST Invoices :");

        }

    }

}

===============================================================================

<Window x:Class="WpfUCsInvoices.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Best Invoices :" Height="450" Width="600" Background="Bisque">

    <Grid>

        <Grid.Resources>

        </Grid.Resources>

        <!--==========================================================-->

        <Grid.RowDefinitions>

            <RowDefinition Height=".5*"/>

            <RowDefinition Height="1*"/>

            <RowDefinition Height=".5*"/>

            <RowDefinition Height="8*"/>

            <RowDefinition Height=".5*"/>

            <RowDefinition Height="1*"/>

            <RowDefinition Height=".5*"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

        </Grid.ColumnDefinitions>

        <Button Grid.ColumnSpan="2" Content="Customer" Grid.Column="1"

                Grid.Row="1" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbCustomer" Background="LightGreen"

                Click="pbCustomer_Click"/>

        <Button Grid.ColumnSpan="2" Content="Invoice" Grid.Column="4"

                Grid.Row="1" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbInvoice" Background="LightBlue" Click="pbInvoice_Click"/>

        <Button Grid.ColumnSpan="2" Content="View Details" Grid.Column="7"

                Grid.Row="1" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbViewDetails" Background="Gold" Click="pbViewDetails_Click"/>

        <Button Grid.ColumnSpan="2" Content="Save" Grid.Column="10"

                Grid.Row="1" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbSave" Background="LightCoral" Click="pbSave_Click"/>

        <Button Grid.ColumnSpan="2" Content="Print" Grid.Column="13"

                Grid.Row="1" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbPrint" Background="BurlyWood" Click="pbPrint_Click"/>

        <!--===========================================================================-->

        <Button Grid.ColumnSpan="2" Content="Settings" Grid.Column="1"

                Grid.Row="5" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbSettings" Background="Orange" Click="pbSettings_Click"/>

        <Button Grid.ColumnSpan="2" Content="Exit Form" Grid.Column="13"

                Grid.Row="5" VerticalAlignment="Stretch"  HorizontalAlignment="Stretch"

                Name="pbExit" Background="Red" Foreground="Gold" Click="pbExit_Click"/>

        <!--===========================================================================-->

        <Border BorderBrush="Blue" BorderThickness="2" Grid.Column="0" Grid.Row="3"

                Grid.ColumnSpan="16" Grid.RowSpan="2"

                Margin="10,10" HorizontalAlignment="Stretch"

                VerticalAlignment="Stretch">

            <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">

                <ContentControl ScrollViewer.CanContentScroll="True" Width="Auto" Height="Auto"

                                ScrollViewer.HorizontalScrollBarVisibility="Auto"

                                ScrollViewer.VerticalScrollBarVisibility="Auto"

                                Name="ccInvoices" >

                </ContentControl>

            </ScrollViewer>

        </Border>

        <!--===========================================================================-->

    </Grid>

</Window>

===============================================================================

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Threading.Tasks;

using System.Windows;

namespace WpfUCsInvoices

{

    /// <summary>

    /// Interaction logic for App.xaml

    /// </summary>

    public partial class App : Application

    {

    }

}

===============================================================================

<Application x:Class="WpfUCsInvoices.App"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             StartupUri="MainWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

===============================================================================

//----- Customer -----

//----- PHH - 10th. February 2015. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

//==================================

using System.ComponentModel;

public class CustomerCS : INotifyPropertyChanged

{

    //----- fields -----

    private int _custrefno;

    private string _person;

    private string _company;

    private string _add1;

    #region {.. collapsed for eNotes display ..}

    private string _add2;

    private string _add3;

    private string _postcode;

    private string _phone;

    private string _web;

    #endregion

    private string _email;

    private string _fax;

    private string _details1;

    private string _details2;

    //----- events -----

    public event PropertyChangedEventHandler PropertyChanged;

    //----- constructors -----

    public CustomerCS()

    {

        this.Initialize();

    }

    public CustomerCS(int nRef)

    {

        this.Initialize();

        //----- must be after Initialize ! -----

        this._custrefno = nRef;

    }

    //----- methods -----

    protected void Initialize()

    {

        this._custrefno = 0;

        this._person = "";

        this._company = "";

        this._add1 = "";

        this._add2 = "";

        this._add3 = "";

        this._postcode = "";

        this._phone = "";

        this._web = "";

        this._email = "";

        this._fax = "";

        this._details1 = "";

        this._details2 = "";

    }

    //----- Create the OnPropertyChanged method to raise the event -----

    protected void OnPropertyChanged(string name)

    {

        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)

        {

            handler(this, new PropertyChangedEventArgs(name));

        }

    }

    //=================================================================

    //----- properties -----

    public int CustRefNo

    {

        get { return _custrefno; }

        set { _custrefno = value; OnPropertyChanged("CustRefNo"); }

    }

    public string Contact

    {

        get { return _person; }

        set { _person = value; OnPropertyChanged("Contact"); }

    }

    public string Company

    {

        get { return _company; }

        set { _company = value; OnPropertyChanged("Company"); }

    }

    #region {.. collapsed for eNotes display ..}

    public string Add1

    {

        get { return _add1; }

        set { _add1 = value; OnPropertyChanged("Add1"); }

    }

    public string Add2

    {

        get { return _add2; }

        set { _add2 = value; OnPropertyChanged("Add2"); }

    }

    public string Add3

    {

        get { return _add3; }

        set { _add3 = value; OnPropertyChanged("Add3"); }

    }

    public string PostCode

    {

        get { return _postcode; }

        set { _postcode = value; OnPropertyChanged("PostCode"); }

    }

    public string Phone

    {

        get { return _phone; }

        set { _phone = value; OnPropertyChanged("Phone"); }

    }

    public string Web

    {

        get { return _web; }

        set { _web = value; OnPropertyChanged("Web"); }

    }

    public string Email

    {

        get { return _email; }

        set { _email = value; OnPropertyChanged("Email"); }

    }

    #endregion

    public string Fax

    {

        get { return _fax; }

        set { _fax = value; OnPropertyChanged("Fax"); }

    }

    public string Details1

    {

        get { return _details1; }

        set { _details1 = value; OnPropertyChanged("Details1"); }

    }

    public string Details2

    {

        get { return _details2; }

        set { _details2 = value; OnPropertyChanged("Details2"); }

    }

    public static List<CustomerCS> GetListCustomers()

    {

        List<CustomerCS> aList = new List<CustomerCS>();

        CustomerCS oC = new CustomerCS(1);

        oC.Contact = "John (boy) Parker";

        oC.Company = "GTS (UK)";

        oC.Add1 = "22, Greenbank View";

        oC.Add2 = "Eastville";

        oC.Add3 = "Bristol";

        oC.PostCode = "BS5 6LG";

        oC.Phone = "0117 902 1708";

        oC.Web = "";

        oC.Email = "support@ukgts.com";

        oC.Fax = "";

        oC.Details1 = "VO support and eTutor";

        oC.Details2 = "";

        aList.Add(oC);

        //------------------------------------

        oC = new CustomerCS(9);

        oC.Contact = "Andrew Gething";

        oC.Company = "personal";

        oC.Add1 = "c/o 'Westlea'";

        oC.Add2 = "10, Shakespeare Street";

        oC.Add3 = "Houghton-le-Spring, Tyne & Wear";

        oC.PostCode = "DH5 8JH";

        oC.Phone = "01915 844994";

        oC.Web = "";

        oC.Email = "Andy.Gething@tesco.net";

        oC.Fax = "";

        oC.Details1 = "18, Teresa Street";

        oC.Details2 = "";

        aList.Add(oC);

        //------------------------------------

        oC = new CustomerCS(31);

        oC.Contact = "";

        oC.Company = "Lee Perkis";

        oC.Add1 = "19, Hatfield Grove";

        oC.Add2 = "Chelmsford";

        oC.Add3 = "Essex";

        oC.PostCode = "CM1 3DF";

        oC.Phone = "01245 604659";

        oC.Web = "";

        oC.Email = "kategething@hotmail.com";

        oC.Fax = "";

        oC.Details1 = "";

        oC.Details2 = "";

        aList.Add(oC);

        //------------------------------------

        oC = new CustomerCS(780);

        oC.Contact = "Benjamin Hepburn";

        oC.Company = "personal contact / customer";

        oC.Add1 = "19, Firbank Crescent";

        oC.Add2 = "Newport";

        oC.Add3 = "South Wales";

        oC.PostCode = "NP19 7QR";

        oC.Phone = "01633 243057";

        oC.Web = "";

        oC.Email = "HepburnBD@cardiff.ac.uk";

        oC.Fax = "";

        oC.Details1 = "";

        oC.Details2 = "";

        aList.Add(oC);

        //------------------------------------

        return aList;

    }

    public override string ToString()

    {

        string cText = CustRefNo.ToString() + " " + Contact.Trim() + " " + Company.Trim() + " " + Add1.Trim();

        return cText;

    }

}

===============================================================================

<UserControl x:Class="WpfUCsInvoices.UserControls.ucCustomer"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             mc:Ignorable="d"

             d:DesignHeight="500" d:DesignWidth="400" Background="LightGreen">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="36*"/>

            <RowDefinition Height="17*"/>

            <RowDefinition Height="197*"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="1*"/>

        </Grid.ColumnDefinitions>

         <!--======================================================================================-->

        <TextBlock HorizontalAlignment="Left" Margin="19,20,0,0"

                   TextWrapping="Wrap" Text="Customer - Options :" VerticalAlignment="Top" Width="272"

                   Height="36"  FontSize="26" Foreground="BlueViolet" Grid.ColumnSpan="3"/>

        <Button Content="Select" HorizontalAlignment="Stretch" Grid.Row="1" VerticalAlignment="Stretch"

                Name="pbSelect" Grid.Column="0" Background="Yellow" FontSize="22" Click="pbSelect_Click"/>

        <Button Content="Add" HorizontalAlignment="Stretch" Grid.Row="1" VerticalAlignment="Stretch"

                Name="pbAdd" Grid.Column="1" Background="Coral" FontSize="22" Click="pbAdd_Click"/>

        <Button Content="Edit" HorizontalAlignment="Stretch" Grid.Row="1" VerticalAlignment="Stretch"

                Name="pbEdit" Grid.Column="2" Background="Blue" FontSize="22" Foreground="LightBlue" Click="pbEdit_Click"/>

        <!--===========================================================================-->

        <Border BorderBrush="OrangeRed" BorderThickness="2" Grid.Column="0" Grid.Row="2"

                Grid.ColumnSpan="3"

                Margin="10,10" HorizontalAlignment="Stretch"

                VerticalAlignment="Stretch">

            <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">

                <ContentControl ScrollViewer.CanContentScroll="True" Width="Auto" Height="Auto"

                                ScrollViewer.HorizontalScrollBarVisibility="Auto"

                                ScrollViewer.VerticalScrollBarVisibility="Auto"

                                Name="ccCustomers" >

                </ContentControl>

            </ScrollViewer>

        </Border>

        <!--===========================================================================-->

    </Grid>

</UserControl>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfUCsInvoices.UserControls

{

    public partial class ucCustomer : UserControl

    {

        public ucCustomer()

        {

            InitializeComponent();

        }

        private void pbSelect_Click(object sender, RoutedEventArgs e)

        {

            this.ccCustomers.Content = new ucCustomerSelect();

        }

        private void pbAdd_Click(object sender, RoutedEventArgs e)

        {

        }

        private void pbEdit_Click(object sender, RoutedEventArgs e)

        {

        }

    }

}

===============================================================================

<UserControl x:Class="WpfUCsInvoices.UserControls.ucCustomerSelect"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             mc:Ignorable="d"

             d:DesignHeight="400" d:DesignWidth="300" Background="LightGray">

    <Grid>

        <Grid.Resources>

            <DataTemplate x:Key="ourCustomersView">

                <Border BorderBrush="Blue" BorderThickness="1" Width="260">

                    <StackPanel Orientation="Vertical">

                        <TextBlock Text="{Binding Contact}" FontSize="16"/>

                        <TextBlock Text="{Binding Company}" FontWeight="Bold"/>

                        <TextBlock Text="{Binding Add1}" FontStyle="Italic" Foreground="OrangeRed"/>

                        <TextBlock Text="{Binding PostCode}"/>

                    </StackPanel>

                </Border>

            </DataTemplate>

        </Grid.Resources>

        <ListBox HorizontalAlignment="Left" Height="331" Margin="10,59,0,0" VerticalAlignment="Top"

                 Name="lbxCustomers" Width="280"

                 ItemsSource="{Binding}"

                 ItemTemplate="{StaticResource ResourceKey=ourCustomersView}"/>

        <TextBlock HorizontalAlignment="Left" Margin="10,7,0,0"

                   TextWrapping="Wrap" Text="Select a Customer :" VerticalAlignment="Top" Width="227"

                   Height="36"  FontSize="26" Foreground="BlueViolet"/>

        <Button Content="OK" HorizontalAlignment="Left" Height="46" Margin="242,8,0,0"

                Name="pbOK" VerticalAlignment="Top" Width="48" FontSize="24" Click="pbOK_Click" />

    </Grid>

</UserControl>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfUCsInvoices.UserControls

{

    public partial class ucCustomerSelect : UserControl

    {

        public ucCustomerSelect()

        {

            InitializeComponent();

            this.lbxCustomers.DataContext = CustomerCS.GetListCustomers();

        }

        private void pbOK_Click(object sender, RoutedEventArgs e)

        {

        }

    }

}

===============================================================================

<UserControl x:Class="WpfUCsInvoices.UserControls.ucFrontScreen"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             mc:Ignorable="d"

             d:DesignHeight="400" d:DesignWidth="460" Background="CadetBlue">

    <Grid>

        <TextBlock HorizontalAlignment="Left" Margin="10,53,0,0" TextWrapping="Wrap"

                   Text="Front Screen - BEST Invoices :" VerticalAlignment="Top" Width="440"

                   Name="txblkFrontScreen_01" Height="36" FontSize="26" Foreground="PeachPuff"/>

    </Grid>

</UserControl>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfUCsInvoices.UserControls

{

    /// <summary>

    /// Interaction logic for ucFrontScreen.xaml

    /// </summary>

    public partial class ucFrontScreen : UserControl

    {

        public ucFrontScreen()

        {

            InitializeComponent();

        }

        public ucFrontScreen(string cMainHeader)

        {

            InitializeComponent();

            this.txblkFrontScreen_01.Text = cMainHeader;

        }

    }

}

===============================================================================

<UserControl x:Class="WpfUCsInvoices.UserControls.ucCustomerAdd"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             mc:Ignorable="d"

             d:DesignHeight="300" d:DesignWidth="300">

    <Grid>

    </Grid>

</UserControl>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace WpfUCsInvoices.UserControls

{

    /// <summary>

    /// Interaction logic for ucCustomerAdd.xaml

    /// </summary>

    public partial class ucCustomerAdd : UserControl

    {

        public ucCustomerAdd()

        {

            InitializeComponent();

        }

    }

}

===============================================================================

PHH - 10th. February 2015.


Chapter 10 - getting our Classes right

What do I mean by 'getting our classes right' ?

Well quite simply we need most or all of our classes to be capable of being 'Data Bound' and

for all of the expected functionality to be seen, and available.

The biggest problem standard developer guys have with XAML / WPF and data binding, is that

they do not define their business / custom classes so that they handle the "property change"

notification correctly.

If we are to define a class for us with Entity Framework as well as data binding, then we have to

similarly handle the property changes.

On top of getting business / custom classes right in this respect, we also need to realise that

most public properties we declare and define in classes for Models and ViewModels, also need to

track changes in properties.

I have personally found that if I implement the 'INotificationPropertyChanged' interface at all classes

between reading data (the Model) and then binding VM properties to the View element attributes, then

all my binding works well - both in multiple forms as well as from code changes to values.

First without EF6 capability :

================================================================================

====================================================================

=====================================================================================

Secondly, with EF6 capability :

The extra 'bits and bobs' of information required for classes to be used with EF6 (plus) are all to do with

the SQL Tables and Columns.

The modern (current) way of doing this is to add these bits into an extra 'configuration' class.

However, as we shall see, this was possible using 'attributes' in the main class.

First a simple config. class - check below :-

================================================================================================

If we place the table and column details into a configuration class then the main class looks as

simple as the normal ones above in the non-EF6 classes.

Here is a working EF 'Attendee' class definition :-

=================================================================================================

However, we must not get the idea that all, or even many, of the standard config. classes are so

simple and straight forward.

Here is one from the 'Olympic2012' application I developed, well over two years ago to date.

Although is is more complex that the simple one we saw above, it is by no means complicated.

I am quite sure that there are many more examples from other developer's applications which indeed

make this sample look trivial and simple.

Checkout the full details below :-

==========================================================================================

Now then guys, we do need to know that there is another approach to coding this table / column detail

which we may come across, possibly mainly to do with 'Linq to SQL'.

Note that table and column properties are set directly in the class definition, and held within square braces

as we see in the next image :-

=====================================================================================================

And a second example is below :-

======================================================================================================

You will notice that there is a 100% similarity between the two approaches, however, we may all prefer

to have a config. file as it keeps things clear between .NET class code and SQL table specifications.

Summarising, we can see that property changes in both approaches is all present and correct, and it is

these lines of code which will track the values changes of public properties, and make data binding work !!

Lets move on, see you in the next sub-section ..................

PHH - 8th. December 2014 & 10th. February 2015.


Chapter 11 - getting our ViewModels right

Try to keep your 'ViewModels' (VM) as simple as possible, obviously this depends on your Views

which therefore need to be kept simple too ;-0)

*** NOTE *** Most /many good eBooks recommend we keep both the Views and the 'VMs' as simple as

possible, and also as "one-to-one" as we can make them.

What I mean by "one-to-one" is that the Public properties of the 'VM' correspond 100% with the

UI element attributes to which we bind the properties - in a 'Data Binding' fashion.

Keep all of the logic and complexity in the ViewModel - and nothing at all but binding specifications

in the View script itself.

The logic I refer to is that for the functioning of the VM, and not really business logic at all.

Keep all data values in the Models which are injected into the VMs. And also any or all your business

logic in the Models, or various 'layers' of Models themselves.

The details and support logic in the VM code should be totally focused on the functioning and support of the View.

Remember how refreshing it is to use mobile devices with Android and WinRT apps that in some ways

seem simple and naive.

I feel that we all got sucked into over complicating our WinForms and VO forms - I know that I did, and

confess to it. I had one or two wonderful forms which had oodles of business logic rolled into the 'Code Behind'

and not separated out elsewhere. Yuck !!!

Yes, the afore mentioned form worked, looked nice, BUT was a nightmare to maintain in the end. Making changes

that the client and my customer required, was VERY time consuming indeed.

Did the form need to be that complex ? - answer is no ! There were other ways to design a solution.

Now I recall it, I think I went along with the above form design because the customer Data Manager came

up with the original design concept - never a good idea in my books ;-0)

I thought it gave him a sense of ownership of the working application, so went along with it for those sorts of reason.

*** NOTE *** If we get our VMs right then we can apply 'Unit Testing' quite easily (or as easily as possible) because

we have 'layered' our solution, and not got 'entanglement' - we have separation of issues, and a bunch more stuff

which means we have discrete code files, and classes, to which Unit Testing applies directly.

What does 'getting or VMs' right' mean to the developer ? :

We are going to base this next sub-section on a working application, one which actually uses MVVM (Galadosft Light)

as well as a 'Controller' class to provide an 'Executive' to the application.

The code is in Vulcan and the specific View / ViewModel we will study is the one for Products - check below :-

==================================================================================

Above we see the central area is a CC (ContentControl) and within it a UC (UserControl).

The UC is for Products (acts like a window) and this is loosely coupled to an associated VM.

As response to the buttons being pushed, different UCs get loosely coupled - or as I prefer to

think of it, UCs get swapped in and out of the display.

Okay then, when the UC is for products, this 'View' is coupled to the ViewModel shown below.

The Product VM was obviously designed to go with the Product 'View', which just happens to

be a UC and not a Window.

Checkout thoroughly and carefully the details of the partly collapsed VM shown below :-

[ .. note the members, fields, properties, methods etc. .. ]

=========================================================================

Yes, in many ways the class structure resembles that we use for Business / Custom classes.

We are still tracking property change of all public properties.

"It's better to track a property which does not need tracking, than to NOT track a property which

we find at a later stage DOES need tracking."

This is in some ways 'belt and braces' - BUT - it is success that we are after, and 100% success at that.

Now then, lets look into the details of the Constructor, where we have data injection taking place.

Study the full details below, and try and work out why I have highlighted the three lines 44 through 46 :-

=======================================================================================

In the data injection 'set-up' phase, we are firstly associating the private fields with 'passed-in'

data property values. So anything to do with 'DataSource' is injected and will therefore be

pointers and not values.

Notice that lines 44 through 46 are related to public properties which originate in the VM itself.

The obvious public property is 'SelectedProduct' which gets/sets the field of similar name.

Checkout this property in the next image :-

====================================================================

It is very handy (useful) to have a VM property called 'SelectedProduct' as this means we can handle in the

VM code and logic, changes to related members and variables associated with the selected list item.

Lets now look at the ComboBox data binding note below that the XAML script shows three bindings and a

'DataTemplate' association / assignment :-

[ .. also note that we do not need to name the UI element .. ]

=================================================================================================

In the above image we see 'OurIndex' which is another VM only public property. So we automatically

get the number in the list that the selected item is, as well as the item itself.

Going back to line 179 in the image two above, what does the method called "ConcatFullDetails" do

for us and our application ?

Lets first take a close look at it - see the following image :-

===================================================================================================================================

Well, its much simpler than it first looks, the method makes a suitable string from Product object properties, if

there is indeed an object in focus.

However, we do need to look more closely at how we need to handle the date, if any - check below :-

===============================================================================================================

And now we see the TextBlock UI element which has its Text attribute bound to the 'FullDetails' public property

of the VM itself - this has not been passed into the VM by data injection. See the details below :-

========================================================

And now we need to look at the XAML script which holds the binding :-

=======================================================================================

Before we study any more code or script, lets take a look at the full list of items, and study

the data template which has been used for displaying the collection items - check this below :-

=========================================================

Yep ! - that looks okay above ...........

So what does the XAML design surface look like for the 'DataTemplate' ? Check this out :-

==================================================================================================

Above we use TextBlock elements and so the items will be Read/Only.

If we used TextBox elements instead we could set them to be editable - Read/Write - and

so we could edit data directly in the ListBox.

Finally, for this part of things, lets check the code behind for the 'View'. Remember that if we

are doing things the MVVM way (even if we are not actually using an MVVM framework) then the

code behind should be virtually nil.

Check this out ;-0) ......... :-

====================================================================

Yep! - above we see the minimum code ;-0)

Finally, "thinking a little outside of the box" ! :

Okay, I know we said we were not doing standard MVVM, and that includes using a 'Controller' system,

however, the working application we have seen used above for illustrating ViewModels is a full MVVM approach

application.

As such we can see how we apply our VMs to user controls (equivalent to windows) and also how we provide

data to the VM by injection.

So to finish this sub-section, below we will see both 'loose coupling' as well as data injection.

Lets first of all start with some .NET code which lays out the 'Controller'. Line 80 is the one in particular that

we need to study, as it is where the association takes place of the 'View' (Product UserControl) to the main (shell) screen

'ContentControl'.

Check this out in the next image :-

============================================================================================================================

So we will get the Product View showing in the shell screen.

How do we set-up the 'View' to be ready for on-screen work ?

Lines 51 through 54 are where we set-up the VM for Product by injecting data into the Constructor of the Product VM.

Note that below we see all four Views and their VMs being initialised at the start of the app launch - line 53 is where

we see data injection - check out below :-

================================================================================================================

So to put it simply - above we have code to create and set-up all the Views the application will use.

However, the main shell View has a CC on it which is used by the Controller code to swap in and out

the UCs (Views) we require for the actions to be undertaken.

This will mean that data edited / changed in any of the Views will persist from one swap-in to another, as

re-instantiation is not taking place.

So although we are focusing in these eNotes on the View / ViewModel boundary, we must consider the Model as

well, and even the structure of the Business data classes, if we are to get our data binding correct 100% of the time.

Short Summary - for Success, 100% :

From your business class definitions, through Models and into ViewModels, try to make all the Public

properties be tracked using 'INotificationPropertyChanged' - force value changes to be tracked and to send

notification.

Add extra public properties to the VM definition so that UI element attributes other than just basic input data can be

kept in the VM itself. Usually this 'support' information is not required outside of the VM itself, BUT, you could pass it back

within the object which is used as the data injection object, if you so wish and structure your data related objects correctly.

Good Luck !!!

PHH - 8th. December 2014 & 11th. February 2015.


Chapter 12 - getting our Views right

In order to fit the needs of the modern design patterns, specifically those of the 'MVVM' approach,

we need to keep our 'View' design as simple and as clean as possible.

It is quite modern to have user input screen clear, clean and simple - that is what Tablet software is

all about.

Most often we need to consider both View and ViewModel as a 'pair' - like "hand and glove".

Many times the activity that the View is required to perform (or support) will dictate most of the design

and content of the 'View'.

However, there are times when we may need to consider the Model (data) as well as the ViewModel data

structure when we are making bindings in our View.

Personally, I think of designing View / VM / Model as a "life skill" its an 'art form' and an art which needs

a lot of experience and practise.

This last statement does not mean that we can't be given a few tips and tricks, just that the more we do

it the better we are likely to get at this 'life skill' stuff !

For WPF the Views are written in XAML script.

The problem with this is that there are many, many, ways to script the UI, but these days of MVVM a lot

of XAML approach is not needed.

In order to write in a script style which matches up to the MVVM pattern, we need to keep things SIMPLE.

The simpler the better, certainly as far as code maintenance is concerned.

No data goes into the XAML script, only data bindings.

Attributes on UI elements are bound to Public Properties of the ViewModel (VM).

So the View knows (or has knowledge of) the VM, but not the other way around.

The View is usually either a 'Window' class object or a 'UserControl' type object.

In fact the VM should know nothing of the View, and that includes elements names.

Do not use EVENTS if using MVVM, and only use button click events if trying to copy the MVVM approach

without actually using a suitable MVVM framework.

The code behind the View should be almost non-existent : clean ,simple, hardly any !

Business logic should be placed in Model objects and not the VM.

All code lines in the VM should have the purpose of supporting the View and its operation, as far as the

UI controls are concerned.

Some VM public properties originate in the VM and are not there deeper in the Model layer. These are the

properties which support the View operations.

View to VM should be almost a 100% correspondence.

If a View UI element has a name defined it should ONLY be for the use of self binding or similar.

Usually, we can replace the need for self binding with extra Public Properties in the VM which are then bound

to the attributes where self binding would have been applied.

There are many Dependency Property attribute which can be used for binding, often we only use the obvious. Try

looking for those others, the interesting ones ;-0)

Above I refer to DPs (Dependency Properties) as these are what all 'bindable' properties are.

If we get it right then only one simple line of .NET code is required to associate the VM with the View we are using.

This association is called 'coupling'.

"Disentanglement" and 'loose coupling' :

We hear the term 'loose coupling' when we associate the ViewModel with its View object.

We also talk of 'disentanglement' when we code our V and VM in this fashion.

Here are some examples for both Windows and UCs :-

================================================================================

====================================================================

For the above CC / UC the loose coupling takes place on line 54.

Now for a Window example (with a little twist !) - check this out below :-

=======================================================================================================

The above code shows the VM object being passed into the Constructor as an input parameter.

However, when we look at the details of the Constructor code (seen below) we see that line 31 is doing

just as we saw in an earlier example - associating the VM with the 'DataContext' attribute - check this :-

========================================================================

Now we need to follow through the making of the VM from the data Model.

Study the next two small images very carefully :-

==========================================================================================

As well as these being defined :-

===================================================

We now need to look at some XAML script and how we set-up the binding from View to VM

public properties.

See you in the child sub-section ................

PHH - 8th. & 10th. December 2014 & 12th. February 2015.


Views - getting the bindings done right !?

Okay then guys, roll your sleeves up for this one ;-0)

This sub-section on Data Bindings in XAML and WPF is really quite large, or extensive.

However, we need to tackle it both thoroughly and with an aim of getting our head around all the

details that we need to know.

If we get data binding right then our applications will run like a dream - and without errors, we hope !

BUT - like everything else, there is so much to cover that we can actually lose sight of where we are

headed ;-0)

If we are doing things right for the MVVM pattern of development (even if we have no framework) we

should be using LOTS of bindings to the attributes in our UI elements.

Look at the simple Customer screen I use in a working application to allow property changes and edits.

Guess how many data bindings we have in place !? :-

=========================================================

Command bindings : 5 (MVVM equivalent of events to handler)

Data bindings : 16 - of which 2 are in a 'DataTemplate'.

Just to make things 'interesting', we have two alternative syntax versions to define a binding.

Here below is the first, line 91 shows 'Binding Header', where in fact "Header" is the name of a string public property.

Checkout the following details :-

===================================================================================================

And now for the other 'flavour' of possible syntax - see line 105 where we have an extra "Path=" placed before

the property name :-

===============================================================================

You will see both of these versions in script that you study from elsewhere, so get equally used to both.

And now we need to see an example of a typical working UI list element, where we usually see lots of bindings,

as well as resources used for templates and the likes - check out these details :-

=========================================================================================

In the above image we see that line 87 is for the basic main data object - in this case an 'ObservableCollection' -

but others ion lines 88 and 89 are to VM properties used to aid the general performance of the View and its

UI elements.

Below we see yet another support binding, a binding of a logic property to the attribute 'IsEnabled'.

This simply means that the VM public property 'HasOneSaveBeenMade' will contain whether the button is

enabled, or not.

Notice that we will use the VM property in any code, and not the value of the attribute gained from a direct

access to the 'IsEnabled' property of the named Button.

======================================================================================================

So the lesson is, do NOT use direct attribute/property values of the UI elements, bind to a VM public

property instead - keep the V to VM layers as decoupled and disentangled as possible ;-0)

Okay then folks, time to move on, lets go to the next subsection - see you there .................

PHH - 12th. & 13th. February 2015.


main Data bindings

Main Data - what is this ? :

By main data bindings we really mean that we are looking at the Business data objects, and how they

are bound to dependency properties (DPs) on the various UI elements and controls. remember, only DP's

support data binding.

So collections get bound to the 'ItemsSource' attribute of ListBox, ComboBox and DataGrid, whereas a

string object gets bound to the 'Text' attribute on TextBox and TextBlock.

A range of standard data types can be bound to the Text attribute of TextBlock and TextBox - integer, double,

datetime, Boolean etc. and so on.

Here are examples of a few - from a working application of mine :-

================================================================================

And now you can check-up on their data types from the list of private fields in the VM definition :-

==========================================================================

Remember there is a public property to accompany each of these private fields.

It is the public properties which get bound in the XAML script.

Other data bindings - those over and above the main Business ones :

Okay then folks, this bunch of bindings must not be overlooked, and although has little to do with our

Business logic is crucial to the look and feel of the UI itself.

We have stuff like numerical height and width of controls, thumb positions of Sliders, and a whole host

of Font related attributes which can be bound, for size, style, weight, family etc..

And don't forget colours as well, we have Foreground and Background, but also 'BorderBrushes' too.

I tend to think of all of these as 'display' or 'decoration' bindings - all to make the look feel better.

There is still yet another important type of binding, and that is to do with list or row selection.

Data Choice - or 'Item Selection' :

Okay then folks, this to my mind is the exciting part of XAML and its data binding - how we can display

collections of complex items, and then easily select ones and display their property values.

Selected items and their index can easily be tracked and used.

Here is a pretty standard type of 'ComboBox' - check out the XAML script below :-

================================================================================================

Yep! - the standard bindings are as expected (lines 113, 115, and 116) but we can also see two

further bindings in the defined 'DataTemplate' - check below :-

================================================================================================

The above 'DataTemplate' specification is applied to the 'ItemTemplate' attribute.

So the properties specified on lines 18 and 19 are properties of the collection item class being used,

in our case Product - as the source for the ComboBox is a list of Products (see line 113).

Moving on .......................

Take a look at the following image in which we have lots of binding BUT no main data from Business logic.

Below we see five drop list controls which provide bound values for the item display in the main ListBox.

Check it out carefully, read the labels and check their selected values :-

========================================================

And now we can enjoy a VERY interesting 'Style' which is to be applied to the 'ListBoxItem' - check this out for bindings ;-0) :-

===============================================================================================================================

Yep! we have on binding from each of the five drop list controls (ComboBoxes), as well as an 'internal' binding.

Line 11 shows the internal binding, and by 'internal' I mean that the value of one attribute on the ListBoxItem is bound

to another attribute of the same ListBoxItem.

We could I suppose call this 'intra' binding, or 'self' binding.

Out of interest, the lists for the UI list elements are just hard coded in this demo sample.

Lets move on, see you in the next subsection .....................

PHH - 12th. & 13th. February 2015.

Addendum :

Instead of using a Style for the 'ListBoxItem', lets re-work our code and script to get the same sort of display

at runtime but with a 'DataTemplate'.

Here are the results of such a restructuring, but the AliceBlue background may not have been added at this stage !?

Check this out below :-

========================================================

Take my word for it that this works as expected.

And now the new 'DataTemplate' which is not using ListBoxItems but items of a collection of 'MyColour' objects.

There are a couple of major changes from the earlier approach, see if you can spot them.

==========================================================================================================

And here is how we apply and use the template - check below :-

========================================================================

Okay then guys, we are now using a newly defined class called 'MyColour' and we need to check this out.

In the following image we can see the main parts (un-collapsed) of this class. Remember it is a Public Property

which is required for binding with a DP (dependency property) attribute.

=====================================================================================

We can't just have a list of string values, you can waste endless hours trying to do it that way ;-0((

This may need some tidying but it works very similarly to the way the previous approach did using the 'Style'.

Time to move on, see you in the next subsection ..................

PHH - 13th. February 2015.


Single objects

PHH - 12th. February 2015.


Collections

==============================================================================================================

==================================================================================================

=========================================================================================

PHH - 12th. February 2015.


Adding to and Changing Collections

PHH - 12th. February 2015.


bindings to support Extra VM properties

======================================================================================================

=================================================================================

=================================================================================================

PHH - 12th. February 2015.


'Read / Only' vs 'Read / Write'

Lets get a few simple facts straight about users interacting with the data presented on screen.

All data will be presented because of data bindings set up by the developer to public properties of the VM.

The data shown can be as R/O or R/W depending on both the UI element used, and / or the setting of

an attribute to allow editing.

Generally speaking, a 'TextBox' allows edit changes and a 'TextBlock' does not. However, the change

facility on the TextBox may be turned on/off (toggled) by setting an attribute called 'IsReadOnly'.

Below is shown a working sample :-

============================================================================

However, the TextBlock control does not have such an attribute - see the following images :-

========================================================================================================

And also the next screen on of the choices :-

========================================================

So wherever we use a TextBlock the data is Read/Only (R/O).

Wherever we use a TextBlock we can toggle the ability to edit.

Below is and example from a working sample - check the UI elements :-

========================================================

The data template for the list box is shown below, and it only uses TextBlock elements. So it must always

be R/O - this means we can't edit in the list box items themselves - check out below :-

================================================================================================

So in my example I have changed the XAML script to allow such list box editing - check this out :-

========================================================

Now the data template is comprised of two TextBoxes in place of the TextBlocks.

In the above image we see results of my editing, using the list box item fields.

Below is the new script, and the default setting (not shown) must be that 'IsReadOnly' is false.

Check the following details :-

===============================================================================================

Notice that in order to use the newly scripted data template we need to change the script line 97

shown below :-

[ .. note the added 'RW' .. ]

=======================================================================================

Lets move on ..............

When we have lists, or collections of items, we often wish to be able to create an extra item at the end of

the existing list.

Although we can mentally see this as item editing, and item property value change, it is best for us to deal

with this particular situation in another subsection (about five below) where we are looking at 'Collections' as

a complete 'whole'.

We are actually adding an extra item to an already existing Collection.

See you in the next subsection where we will compare the behaviour of UI elements which can hold lists

or collections.

PHH - 12th. February 2015.


DataTemplate - binding within

PHH - 12th. February 2015.


UI element DPs other than main Data

PHH - 12th. February 2015.


cross-Element, intra-Element - attribute binding

PHH - 12th. February 2015.


editing listed collection items - tips and tricks

Okay you guys, this subsection contains a perfect example of how possible best to use WPF and

XAML data binding.

We will be dealing with a collection of Customers, where a 'Customer' object is a pretty standard

complex Business class / type.

We have our collection items in a typed list (or 'ObservableCollection' ( 'OC' ) ) and displayed in either a list

UI element or a DataGrid one.

Below we study a working sample application which uses a ListBox and an OC. Checkout the list on the

left and the single item on the right, which is displayed a property at a time :-

=========================================================

In the above image we have R/O items in the ListBox and R/W fields on the right hand side.

The RHS is actually a bunch of TextBoxes, each with their Text attribute being bound to a different

property of the Customer item to be edited / changed.

Here below is an example of the second TextBox in the editing 'area' :-

==================================================================================================

You will notice on line 105 above, that the object being edited is of type 'Customer' but is also a property

of the ViewModel called 'CustomerEdit'. This was NOT passed into the VM from a Model data injection.

Since the object is NOT the highlighted one in the list of items, when we do edit text it will not show up

in the list until we execute some other and extra code.

So until we 'say so', by pressing a button (or similar) the two areas of information are not connected.

How is this so ?

Well, to understand what is going on we need to start by looking at the XAML script for the ListBox element.

Checkout below the lines 95 and 96 where we have binding set to two properties of the ViewModel object :-

=======================================================================================

Both 'SelectedCustomer' and 'nOurIndex' are properties of the VM which we have defined. They do

not come from anywhere else, and so are really there to support the performance of the VM and View.

Now then, we next need to look back to the Customer class itself, to see what we have available to help us

with the above separated functionality. Check the following code and look in particular at 'Clone' - anything

with the word 'Clone' within it :-

=============================================================================================================================

By making our Customer class implement the 'IClonable' interface, we will easily be able to take

a selected Customer item and clone it to another object instance. This will be shown very shortly.

First of all we now need to look at the properties of the VM itself. To see which are effectively properties

which are passed through from Models and which are new to the VM, and for performance behaviour reasons only.

Check out this bunch :-

==================================================================

We will be particularly interested in those on lines 28 through 34.

Since these properties are new to the VM we will expect many to be initialized in a Constructor, but

NOT assigned from injected data, coming in as parameters to the Constructor.

Check this next image out thoroughly :-

==================================================================================

The above Constructor overload shows lines 43 through 46 which are local only to the VM.

Properties on line 40 and 41 are having data 'passed-through'.

Lets now see some other code lines from the VM, stuff which support the above design.

Here is a very important one :-

==============================================================

Note above that the file is one for customer VM.

And now the moment we have been waiting for ;-0) - below we see the bound SelectedCustomer being

used to create a clone object called 'CustomerEdit' - check this out :-

===========================================================================================

Remember that 'CustomerEdit' has properties bound to the editing section / area of the View (UC).

Here is a reminder (visually) :-

=======================================================================================================

And now to finish off ...................

Lets look at a scenario in which we have selected a customer, then carried out a series of changes or edits.

Check this out below :-

==================================================

The save button is now active, so what happens when we press it ?

In the following image we see how I have coded a method which in MVVM is a command, we would normally

think of it as an event handler. They both do a similar job, but the Command code in within the VM code file.

Study the following code thoroughly :-

============================================================================================================

Line 134 shown above does all of the hard work - basically the correct item in the collection

is over-written with the new one from the RHS of our View screen.

If we get our code correct then we should see that we can force any new changes into the back-end

database source - usually an SQL database.

======================================================

In my existing demo application the Force Changes button has no affect on anything - its just a dummy entry.

Addendum :

By doing things this way (see above) we can protect some data fields by making the TextBoxes R/O.

In the next image we have set 'CustomerId' and 'FirstOrder' to be Read / Only (R/O) :-

============================================================================

I can't show you much visually to prove that this works - you will just have to take my word for it that

it does work okay.

Time to move on, good luck with your screen editing ;-0)

See you in the next subsection .............................

PHH - 13th. February 2015.


changing collections - add, replace/edit, and delete items

Collections play a BIG part in many (if not most) applications which use WPF/XAML to data bind

lists to UI elements.

There are a few UI controls which are designed specifically for Collections, and these are ComboBox

drop list, the ListBox element, ListView, and the very important DataGrid.

Having said that, it is soon made apparent that only one of these allows us to directly create a new

item of the Collection on-screen and within the UI control itself.

Lets look a the Intellisense drop lists for those UI elements listed above. Check these out below,

first we will view the 'DataGrid' control :-

==============================================================================================================

If we use a standard 'DataGrid' element we see that this control has a set of attributes to define what the

user will be able to do at runtime.

In the above portion of the intellisense list we see that it is possible to allow the user to add rows. Or more

specifically add one extra row at a time - one by one.

Notice also that we can set things so that a row can be deleted, and we need to carry out an experiment to

see if we can delete multiple rows, by first highlighting more than one row.

ListBox :-

=====================================================================================================================

ComboBox :-

===================================================================================================

ListView :-

=======================================================================================================

=============================================================================================

============================================================================================

===============================================================================================

PHH - 15th. February 2015.


using DataGrid to add / create new items

We are going to see how we can use the properties of a DataGrid UI element (control) to help us add

(or create) new items to an existing Collection of items.

By now we should be aware that the 'DataGrid' class in WPF is rather a special one for handling Collections.

Below we see that we can specify if new rows (items) can be added, and also if rows can be removed,

or deleted - checkout these details :-

==============================================================================================

If we have 'AutoGenerateColumns' set as true then we can bind any Collection and have the columns

displayed reflect all the public properties of the item class within the Collection.

So we can prevent item addition as well as allowing it, and can allow (quite separately) items to be

removed or not. Some other useful options are shown above.

The beauty of doing things like this (with a DataGrid) is that the class type can be 'agnostic' simply

because the DG control looks at the item type and provides the suitable column headers and cell types.

We can bind Collections of quite different item class types to the same WPF screen DG control.

Using this approach we can add one or more new items to the displayed Collection.

Before we go into any further detail of XAML script and .NET code, let us have a quick look at the

different data bindings we can easily make, with Customer items, Products and Suppliers :-

Product :

=======================================================================================

Supplier :

=========================================================================================

Customer :

===============================================================================================

In the above image the column headers for Customer has been scrolled up out of sight.

However, we can see at the bottom of the list that we are currently in a edit mode of the extra row

being added - a new Customer in other words.

Now then, when we are talking of adding extra rows simply by clicking in the last (empty) row, we

need to be aware of just what the DG control does for us when the last line is clicked.

There must be a empty Constructor for the class being used, that is a Constructor which takes zero

or no input parameters - lets move on and see ............

A brief word about the 'empty' Constructors required :

Let us first look at a default type empty Constructor - check this below :-

==========================================================================

It is probably not a great idea to just leave this as it is, without us as developers taking charge

of what properties are set, with which default values etc.

Let us now change and update the empty Constructor - check this out :-

===============================================================================

And now we can see a new Customer being created before we updated the Constructor - check below :-

==============================================================================================

After the change of Constructor :-

But now when we try to add a new Customer (create a new Customer item) we see the following

default values, before they are edited by the user :-

=============================================================================================

We need to talk further about setting default values for 'DateTime' and possibly Boolean properties.

But for now lets prove to ourselves that a zero/empty Constructor is requited for DG row addition.

Checkout these details :-

===============================================================================================

The error in line one points to this small section of code shown below :-

==========================================================================

Note that we are trying to instantiate three Customer objects, this needs an empty Constructor, as indeed

does the action wherein we just click the last line of a DG set of rows.

And now I need to uncomment the code to get the application to build and run once again.

Below is shown the DG when bound to the collection of three empty Customer items :-

===========================================================================================================

We can go back and edit (or delete) each of the above rows (an item is one row).

Lets move on ...............

Nulls and 'Nullable' Types - how and why ! :

When we set default values for collection item properties, in the class Constructor or Initialize method, we often

need to deal with 'DateTime' and Boolean types.

Regularly developers like to provide a 'Null' to such types rather than a standard default value, as the latter is

also often INCORRECT.

Take 'IsLocal' as an example, I don't wish to have True or False until the value is set, so this means I will need

to use a 'Nullable' type.

Lets see the details for the working example for 'FirstOrder' before we edit code to change the IsLocal Boolean

field / property.

======================================================================

And here is how to set it during the initialise process :-

==========================================================================

And of course the type has to be correctly defined everywhere it is used .............

=============================================================

So when the row is displayed in a DG and it contains a DateTime, the cell will appear empty, it has

no content - study the following :-

======================

Now lets try and change the 'IsLocal' to be similar ................

When we use 'Logic' as a type we get the following default visual display :-

=====================

But when we change this to Nullable<Logic> as a type we see this as default :-

=====================

Making a couple of edits we see this :-

===============

We can type in 'True' or 'False' (case not important), but not just 't' of 'f' - see below :-

=====================================

The above images show the red validation border - as standard for default validation checking.

Okay, unfortunately we lose the checkbox icon ! I won't worry about that as I get so much other

stuff back in its place - without needing to write code.

Lets move on .............

Swapping over Collections of different types :

Okay then folks, I have said how easy it is to use one 'ContentControl' on a form to display more

than one item collection - more that one different item class making up the Collection.

Lets see how we can simply set things up so we can have on display in the DG either a populated

list of Customers, Products or Suppliers, or indeed a short list of empty items for these three types

as well.

First we need an 'Enum' - check below :-

=================================================

And now we need to use each of our new 'Enums' as a switch value.

Here is how we pass it into the constructor of 'ucPHH1' :-

==========================================================================================

Notice above how we assign the Content attribute / property of the 'ContentControl' element.

And then finally, we can see how this input parameter is used at initialisation of a ucPHH1 object :-

=================================================================================

And that is how easy it is ;-0)

Time to move on and see how to edit and/or replace an existing item in a collection, directly

in a DG row itself.

See you in the next subsection ...................

PHH - 15th. & 18th. February 2015.


using DataGrid to remove / delete items

Okay guys, lets start off by saying that using a DataGrid UI control to remove and delete collection items

is VERY easy indeed.

However, the relevant attribute / property needs to be set to 'True' before we can delete any rows.

And remember a whole row is a complete item in the Collection - check this out :-

[ .. remove a row and an item is deleted .. ]

================================================================================================

In the above image it is line 16 which determines the 'Delete' functionality of the 'DataGrid' control.

Once any Collection is bound to a DG element we can quickly remove items by a click and a press.

A mouse click and a key press is all it takes to highlight and delete a row from the DG display. And

of course we can do one after another, until we empty the Collection - if we so wished !?

Lets see a couple of images relating to this process.

We can start with a collection of 5 empty Supplier items - the last one is highlighted :-

=============================================================================================

Take it from me that I pressed the Delete key on my keyboard and repeated the highlighting

and removing process another three times, to leave one row as seen below :-

=============================================================================================

And now we can see a collection of empty Customer items, three in all.

Notice in the image shown below that we have all three highlighted, by a multi-selection action :-

==============================================================================================

When we press the delete key for multiple selection, we see each and every highlighted row gets

removed from the DG and hence deleted from the Collection objects itself - see the result below :-

=============================================================================================

The above image shows just one line, the bottom line, which when clicked in becomes the new

line to be added. So the above DG is showing a zero length Collection.

Tweaking the attribute settings :

In order to be able to remove only one row at a time we need to have our attributes set correctly on the DG.

See below where 'SelectionMode' is being chosen from the intellisense drop list :-

====================================================================================================

Before we can remove ONLY one row, we need the 'IsReadOnly' attribute to be set to 'False' (see line 15) as

well as the above line 16 set to 'Single'.

If we wish to be able to multiple select then we need line 16 to be set to 'Extended'.

Multiple selection works in the usual way with the modifier key 'Ctrl', and the Shifty key as well. The usual

two modes we are used to.

Time to move on, see you in the next sub-section.

PHH - 15th. & 18th. & 19th. February 2015.


using DataGrid to edit / replace items

Now the folks, editing the content of cells in a DG displaying a Collection is easy enough.

However, we do need to consider a few things if we are to script / code this in our applications.

First of all we can protect the bound Collection by making the DG Read / Only (R/O). The attribute

for this is seen below :-

===================================================================================================

Now then, it is also possible to restrict editing at a column level, cell by cell within the data row.

However, for the 'flexible' way we are using one DataGrid to display different types of Collection, we

do need to have the attribute 'AutoGenerateColumns' set to 'True'.

This does mean that identity columns can have their contents protected as when we define a set of

specific columns with headers and other column attributes set.

Checking out the Alternative manual way to specify column details :

Just in case you need to do it the harder way - meaning we have to do a lot more XAML scripting, then

the following details may come in handy (useful) for you.

For the Conference application I have added a first column to the working example I had in my VS 2013

system. check it out below :-

============================================================================================================================

Line 26 through 28 above have added a new first column for 'Identity' and this is Read / Only.

So in the next image we see that we can see the '-1' values of the identities (yes, this is correct)

by we can't edit then by clicking into any of the cells in column one - see below :-

===============================================================================

However, one good way to stop editing is also to NOT display the column in the first place.

Here we do just that :-

=================================================================================================================

And this now display as shown in the following image :-

==================================================================================

Okay then folks, I think we have enough information to be successful at making our DataGrid elements

allow us to edit the property values.

Lets move on to see how we can use DGs to create new item objects.

See you in the next subsection ..............

PHH - 16th. February 2015.


using a DataGrid to easily create a new Business object

=====================================================================================================================

=================================================================================================================

=================================================================================================

====================================================================================================================

===============================================

=====================================

=================================================================================================

==============================================================================================

==========================================================================================

=====================================================================================================

=======================================================================================================

==============================================================================================

PHH - 16th. February 2015.


View - finding more space (real estate) with CCs and UCs

For many years now, developers and UI designers have been trying to get more space available

in their on-screen forms.

Today with WPF we have an easy way to make as much extra space as we wish, or choose.

Lets think of the similar situation of seeing pages in a PDF file or eBook. We do not try and

force all the pages onto the screen at once. Instead, we effectively 'stack' one page behind

another - only reading one at a time as we bring the next page forward.

We can do the same sort of thing with WPF / XAML using a 'ContentControl' and a series of

UserControls.

Effectively the CC is the space for each page, and the UCs are the pages themselves.

All we need extra to a single CC and a bunch of UCs, is some way to trigger the UCs to

swap in and swap out.

There are a number of sections and subsections in these eNotes which show in detail how to

use CCs and UCs.

Go off and study Chapter 9 to get the full story on how to do this.

See you in the next subsection ..............

PHH - 12th. & 19th. February 2015.


Views with RBs - binding using a UC to solve the problem

PHH - 12th. February 2015.


Chapter 13 - what of the Models ?

Simple Summary :

To put it simply, to most of us standard developers, 'Models' are data objects.

One or more 'Models' are provided to the ViewModel at instantiation - this can be called 'Data Injection',

or a few other similar titles / names.

Models can quite often be a collection of Custom/Business objects - each object is an item in the collection.

Models are used for ... "keeping data and GUI well separated ".

So we pass data as 'Model' objects into ViewModels, and hence into Views.

When a Model is passed as a parameter into the Constructor of a VM, the first thing we do with our coding is

to associate the appropriate public properties of the VM with those of the Models passed-in.

There are different structures to Models, depending on the data involved.

One Model can be composed of other Models - if you like we can say we can make up 'complex' Models, this

then simplifies the way we need to inject the data - one complex Model rather than a set of simpler Models.

No data at all should be in View GUI element properties, and only a few special data objects are in the

VM itself - and these stay there after the use of the VM, they are supporting properties, they support the

operation of the View / VM.

In the VM, the rest (real business data) is passed through from the 'Model layers, and once assigned to the

VM public properties, this data is what is seen on the View UI elements after binding takes place.

We talk of 'layers' - Model, VM and View. However, one 'Model' may be made up (composed of) other Models.

It is easier to pass into a constructor one complex Model than half a dozen simpler Models.

*** Remember *** a Model can (and often is) shared between many different VMs. So a collection of Customer

objects (returned by a LINQ query on the SQL database) can be passed into many Views by their attendant

VMs, simply as input parameters to the instantiation process.

So the same Customer collection data can be seen and edited on many Views at once - 'Sales', 'Products',

and 'Customer History' for example.

This is actually much easier to understand than you may a first THINK !

Try NOT to move data values from 'Object to Object' unnecessarily - so don't be an 'AutoMapper' junkie ! ;-0)

In today's .NET world for coding and application design, Models will VERY often have a lot to do with LINQ.

And also Models will have a lot to do with 'Linq to Entity', or at least 'Linq to SQL'.

At the point that we pass Models into VMs we very often have in-memory collections.

So, we could say that most often Models are in-memory collections, and when processed by LINQ it is said to

be 'Linq to Objects' software technology.

Lets move on and do some testing and experimentation .............

PHH - 8th. December 2014.


'Models' are all about Data (objects)

Basically, the vast majority of data in a ViewModel (VM) is actually supplied by the Model, or Models,

passed into it at time of instantiation.

When the constructor of the VM then assigns Model properties to public properties on the VM, no actual

data values move around, we quite simply have 'pointers' doing all the work - property to property, and

one layer to the next.

Complex objects in Models must be responsible for handling and notifying their own changes. So for

example a Customer object has a class code which implements the 'INotifyPropertyChanged' interface.

Lets start at a simple level ..............

Here is some code which can act as a Model, even though we can improve its 'look'.

=====================================================================================

The above static method returns a collection of 'Speaker' objects. 'Speaker' being a person who delivers

a presentation session at a conference - like Dieter, Frank, Fabrice and Meinhard.

Lets add some structure to our SE pane to facilitate (help) us make this a tidy job :-

=======================================

So what does the file look like which we called 'SpeakersModel' ?

Well folks, we just need study the image shown below :-

===================================================================================================

Notice that in the above image code we are using the static method 'ReturnAllSpeakers()' from our C#

Class Library.

Also notice that we have created two options of static method for the class 'SpeakersModel'.

One returns a List<T> and the other an ObservableCollection<T> (where 'T' is Speaker).

Now study the following image and details carefully :-

=======================================================================================================

And as you would expect it to be, we get '12' as an answer to each display (above and below) simply because

it is the same collection.

Check this out too :-

========================================================================================================

Okay then guys, I think you get the idea about simple Models.

We have started simple enough, but in fact if we are sensible, it does not need to get that much more

complex, or complicated.

We do need to know about designing and constructing a 'complex' Model, by this we mean one based

on more that one object, type of object, or even many collections.

It is now possible for us to do a quick and easy test, to see if we can display the Model data, without the

direct need of a VM.

Although we should never miss out using a ViewModel, when we have both a Model and a View, we can

under special circumstances do a trial of Model to View, or UI element on a View, as seen below :-

===========================================================================

Yeh! - okay ! - sorry about the repeated data items, these are just duplicate rows inserted into

out Speakers table by the Entity Framework code - more on that later.

Lets move on a few steps, or three ..............

Making a 'Complex' data Model : (How and Why)

Suppose our View needs to have available to its UI elements, three collections of Business items,

and a couple of single Custom objects - all to be bound in some way.

The easiest way to do this - which is also a commonly reused approach, is to create an object we

call a ViewModel, with public properties of the types required above.

We then supply 'as data injection' a Model object which has public properties of the collections and

single types.

Then we simply instantiate the VM with a single input parameter to the Constructor of the VM, and

code the associates of property to property, from Model to ViewModel.

A single "loose coupling" of the VM to the View then completes the task.

Lets move on a pace or two and add three more 'Model' code files to our Vulcan application - check

below :-

==========================================

And also we need to create suitable code within the files, each is now similar to that shown below for

the Attendee class and data - check this out :-

================================================================================================

Yep! - similar to what we had previously for Speakers.

Now we are going to make a new code file entry in the folder for 'ViewModels'. Here is my SE pane content :-

==============================================

So we are now to 'flesh-out' the VM file called "PeopleSessionsViewModel", in which we will incorporate

four basic Models.

In the following image we see the collapsed view of the new VM - check the full details carefully :-

==============================================================================================

=================================================================

==========================================================================================

==================================================================================================

===============================================================================================

PHH - 9th. December 2014 .& mainly 9th./10th. January 2015.


Testing - the upgraded Table classes

Before we can have a good, careful, and proper look at Models, and how these are used with VMs

and Views, as well as retrieving data from the back-end data source using the Entity Framework

technology, we first need to create and improve the Table classes we have been coding up till now.

We need to design and make a set of Table classes which are more 'Entity' based than those previously

used, which were more on the 'Linq to SQL' style of Table to Object relationship.

We need to see for our Conference example, just how we can vastly improve our classes by moving then

much more towards the EF style of design and use.

Let us now see just how our 'Speakers' table looks when created by Code First with the new class definition.

Check this out - simple as it is :-

==============================================

Yep! - we have a foreign key to the Registrations table.

But what does our code look like for the class definition ? It has to be more complex than the above !?

Study the following image thoroughly, and carefully :-

===================================================================================

You may have noticed line 93 above, for a property in the custom object class of 'Sessions' - which

is a List of type 'Session'. Where has this gotten to ?

Well guys, we need to look at the Sessions table, as for each of the Session items in the list the

entries into the Sessions table points back to the generating 'Speaker' row.

So we are likely to get one or more rows in the Sessions table related to the Speaker by the foreign

key shown below - check the details thoroughly :-

===============================================

Above you will also see that we have another (second) relationship with a foreign key pointing back to the

'LectureRooms' table, so one or many Session rows point back to the same lecture room in which they

are to be delivered.

You will see other instances in our Conference database in which we get FK relationships due to our code

used to define our .NET table classes.

However, there is at least one special case where we have a 'many to many' relationship. Look in the SSOE

pane to see the following Table in the general 'dbo' schema - title is 'SessionAttendees :-

========================================================

The above is present because we have a 'many to many' relationship between Session and Attendees.

One Attendee will visit and enjoy a number of sessions, but on the other side of things one specific session

will hopefully have a few (many) attendee guys going along to listen and learn.

Since this level of complexity in EF6 is beyond the scope of these eNotes, lets just say that this was all

created in the database 'schema' for us by EF from our coded class definitions - nice and easy, if we code

our classes according to the straightforward approach shown in my sample code.

Lets move on ..................

Remember that when we make code changes to our Code First 'stuff' we will need to delete the existing (older)

database and let the code re-create it - this means we need to keep using the SSOE to delete and refresh.

Below we are seen to be trying to Refresh - check it out :-

=============================================================================

Refreshing brought back the DB into the list which is entitled "ClassLibLinqEF6_CS.ConfContent".

Previously, the DB had be removed form the list using a right click and the context menu on the DB node

in the SSOE pane.

Here is the newly created entry :-

===========================================================

And the newly created Tables can be seen below as well :-

==============================================

Notice the couple above which are of the general schema 'dbo' type.

All of my Code First tables should be 'VL15'.

Now then, expanding one more level we see the details shown below - column details :-

==================================================

Notice above the foreign key relating a hotel booking with a person registered for the conference.

Now let us examine the following image, one which shows some test output as well as the class code

for 'HotelReservation' - study thoroughly :-

================================================================================================================================

Actually, the above runtime display and the underlying code (visually) are not that well 'linked' ;-0)

But if we study the following 'test code' we can get a much better idea of what is going on when we run the application as it is.

Check the details carefully :-

============================================================================================================

Above we need to instantiate a couple of Registrations before we can use them to further instantiate a couple

of Speaker objects.

We then save both lots of objects, and the use LINQ to get a return of two lists, one for Speakers and the other

for Registrations.

Now then, we need to see that at the moment our 'Configuration' class for 'HotelReservation' is VERY basic, and

as can be seen below simply sets the schema to be 'VL15' instead of 'dbo', the default value.

========================================================================================================

I suspect that we may need to add some other specifications for columns representing our object properties.

More of this later.

Lets do some more 'Testing', with some other sorts and types of data ............

Carrying out Further Tests - (what is required ?) :

Well folks, as you may well know and appreciate, if we are to do more thorough checks and tests on our application

and the data it moves back and forth, we do need to have a reasonable set of entries made into each and every Table

in our SQL database.

We do NOT wish to do such a task manually, or with poorly structured hard coding. We need to think and plan. before

we rush at the task.

Terminology :

Lets get a couple of things clear, so that we know what we are talking about. If we populate a new and empty Table

at application runtime, we can call this action 'Seeding'.

Yes, 'Seeding' is really populating the Table with sample data, just after the Table has been created.

We can 'populate' a table with added rows at any time I suppose. Do 'Seeding' can be thought of as pre-population.

So when developers are still developing (and making changes to) an application we often need to set the code up

so that the whole Database is removed and re-built, and then the Tables seeded. I have been doing this myself a lot

of late, while writing these eNotes.

What do we require for 'Seeding' ? :

Well then, lets keep it simple shall we ? How about we have a single method for seeding each separate Table ?!

We could then group our calls to the seeding methods into a 'super' method.

Lets work backwards to see what this is all about ................

Checkout in detail the following image :-

===================================================================================================================================

In the above image line 66 shows the code call to the static member 'SeeTables.SeeAllTables'.

And now here below we can see the code for this static member :-

============================================================================

And obviously, now we to look at one of these 'single' seeding members.

Checkout the one below for 'Attendees' :-

=============================================================================

Yes, this is simply getting a collection (list) and adding it to the Table by saving the changes form the

new list compared to the existing table rows.

Each single seed member has the same format.

So finally for the 'seeding' process we need to checkout the hard coded data specification - see the following details :-

=========================================================================================================================

And obviously, we need to remind ourselves as to how the particular Constructor works for Attendee,

so I have listed in below :-

=====================================================================

Okay then folks, we are doing just fine - now lets see the code to read back the seeded data

and have this data bound to list UI elements - so that we / users can see the information / values.

==========================================================================================

This is what produces the type of output in the next image :-

================================================================================

Refresh, refresh, REFRESH !!!

====================================================================================================================================================================

=============================================================

=================================================================================

===================================================================================================================

=======================================================================================================

PHH - 11th. January 2015.


Testing demo applications - 'in-memory' data

I used to do this a LOT - before EF6 and Code First was available to me.

Now that it is so easy to put data into a SQL database and return the query sets, I must admit

I have moved over much more to using the Table data for testing.

Having said all that I still think that it is important for us developer guys to know how to use data

hard coded into our testing static members so that we can have a choice of in-memory collections,

or returned set collections, for our application testing.

Simple Overview :

To put it simply, we create in code a static method (or few) which contains the hard coded data values.

When we use these members they return either a List<T> or an ObservableCollection<T>.

I usually make two members one which does the List and the other the OC. The OC can be easily

made (instantiated) from the typed List.

At any time we need the collection data we just use the static member - as easy as that.

Obviously, as we developer further, we can gradually add to, or improve / update our data items.

This approach is really for collections of Business / Custom items - objects which are themselves

complex in type.

What are the Benefits ? :

Simplicity and control !

It is easy to code, the hardware platform is taken out of the equation completely, and we have total

control over what data we leave in the test set or comment out of it.

We also do not need any SQL server installations on the local machine, and don't need to worry about

connections and strings - even though EF6 and 'Code First' has made things much easier.

Let us now look at some working coded examples .........

Working Examples :

The following details are from a fully working demo application employing the MVVM pattern, and

using MVVMLight (from GalaSoft) and also employing a 'Controller'.

At the time I coded this I used to include the test data 'static' members in the class definition, but

now I tend to keep then in the Model folders within the SE pane.

Belwo we can see the collapsed 'shape' of the class definition, and the data members are highlighted :-

=============================================================================================

If we now expand the particular sections we can see the two static members in full detail below - note lines

85 & 86 are all that is needed for the 'ObservableCollection' (OC) since it uses the List object and hence the

same data as the more voluminous List definition - lines 64 & 74 may also be of real interest to you :-

=====================================================================================================================

And while we are at it, we may as well see the pair of members for the Products - check below :-

================================================================================================================================================

Okay then guys, lets move on a pace or two ............

How do we use these data providing static members ?

In the following image we see that there has been a wrapper put around the call to the data member

for Customers in an 'OC'.

The 'Model' class has a private field for the data collection, which then is returned from an appropriate

virtual method - check out the main details, particularly line 16 :-

=========================================================================================================================

Please note there are other, and similar ways of doing exactly the same thing as shown above.

However, the general approach stays the same for application hard coded data provision.

Before we leave this section we need to see how this Customer test data looks when bound to the

View, via the ViewModel - check this out below :-

=======================================================

Lets move on, see you in the next sub-section ........................

PHH - 9th. & 13th. December 2014.


Layering our 'Models' ?

What exactly does this mean ?

What are Models 'layers' ? and why do we need to use them ?

Well guys, the answer is simple really, its about keeping our code and design as simple and as

clean as possible.

As you will know by now, in all but a simple or trivial application example, the ViewModel object

needs to be instantiated by us injecting data into the Constructor for the VM.

Some VMs may need more than one (or a few) data objects to be provided for 'injection', so this

requires us to take Models based on a data source and combine them in some way into a more

complex data Model - which is then provided to the VM's Constructor.

The whole aim of this is to create a VM (View support data object) which is as simple as possible,

and which corresponds to the View 100% - one to one - as we would say.

What we are NOT doing with layering :

It may be easier to say what we are NOT doing when we carry out Model 'layering'.

We are not moving data items and values around in memory. So we are NOT mapping and moving

data, but designing extra data classes which then have their Public Properties populated from existing

objects - so we are dealing in memory pointers.

The higher level Model properties point to existing lower level Model properties, and so on, till we get

eventually to a data object of some sort - this could be a Collection of items.

So layering is all about pointers.

'ViewModels' themselves should contain many properties which are just pointers. Few VM properties

should normally be for 'local support' of the VM and View.

Models and their layering is a concept for developers to keep tidy design and code sections - not for

movement of data across layer 'boundaries'.

Remember we should be keeping data movement within our running application to a minimum ;-0)

To my mind the above ideas and concepts are at the heart of Data Binding and the MVVM 'pattern'.

See Chapter 4 - Basic four sample.

PHH - 9th. December 2014.


Data from 'SQL Server' databases into Models

These days (2014 and onwards) when we develop a .NET application and need some SQL data

returning from a back-end database, we tend to use either 'Linq to SQL' (L2S) or 'Linq to Entity' (L2E) technology

which is built into the design surface of Visual Studio.

*** When using in-memory Collections we use 'Linq to Objects' ***

LINQ is built into the C# compiler, but Entity Framework is as it says, its part of a Framework.

As yet, LINQ is not built into the Vulcan compiler, but that in itself is not a big issue - we can get around

the problem quite easily and we will see this done in other sections.

We can easily integrate any necessary C# code with the rest of our Vulcan.NET code by employing

what I call a 'thin data layer' which is a C# Class Library which we then reference from our Vulcan projects.

Usually, we employ a STATIC member of such a supporting Class Library to return a Collection of items.

The item type in such a Collection will often be things like 'Customer', 'Sale', 'Product' and so forth.

With EF6 we tend to get more complex item types in our Collection, but we still get Collections returned.

These days .NET data is all about Collections and using LINQ on collections in memory, as well as with

queries on the technologies of 'L2S' and 'L2E'.

If we use either of these two technologies we can also use a 'Code First' approach which allows us as

developers to define in .NET code the classes of our objects which are then used by the system to create and

maintain the necessary SQL tables.

When we use 'Code First' we do not need to bother ourselves over the special data types for SQL data columns,

and much more stuff happening in the SQL database. This is a BIG step forward !

Before we get into details of the two technologies (L2S and L2E), remember that both 'ViewModels' and 'Models' are

just data class objects - with Public Properties.

And as such we can use either when we make a loose coupling to a form object (Window or 'UserControl').

So for simple applications we can often see that a Model is coupled, missing out the middle object of the

VM type. This is sufficient when things are simple and uncomplicated.

When I use Model and ViewModel in a class name in these eNotes it is simply convention and not some

sort of a framework necessity ! It is important to remember this.

"Linq 2 SQL" :

Below we will be using a working example that I first made some time ago (years?). Here is an image of what

the main screen looks like after the small application is built and run :-

=======================================================

Simple enough !

All of the above data has been read in from a SQL database using 'L2S' technology.

We have had returned from our query, a collection of 'Customer' items.

Let us look at the first few lines of the initialisation code of the main window :-

=======================================================================================

Lines 42 - 45 make sure a new database is created, from scratch, from our .NET code.

Also above we see that once the existence of a database is assured, we run the method called

'GetBackCustomers' on line 47 - this does as its name suggests.

This method is where the LINQ query is formed and caused to act, or be applied. Remember that

data is only found and provided when our code tries to use the data to be returned.

Check out the full details shown in the following image :-

[ .. line 68 is where our returned SQL data object (as a collection of items) is coupled to the form .. ]

================================================================================================

The SE pane details shows the Model being used 'directly' in the coupling, missing out a ViewModel :-

=============================================================

We had now better see and study the XAML script for the 'DataGrid' and the Window :-

================================================================================================

We don't really need to give the above UI element a name, as we don't use it in the code behind.

We couple to the Window and not the 'DataGrid' element itself.

And so we need to finish things off by looking in detail at the 'CustomersModel' - see below :-

=============================================================================================

Although the above uses L2S technology we can do similar things with the EF and L2E, by using

just simple table objects in place of the more complex Entity ones.

'Linq2SQL' was released to the public by Microsoft before 'Linq2Entity'.

Now we can use L2E for everything if we so wish - have one way to design and structure each and all

of our applications.

We will see quite often Models that are based on returning single table row object data. However, quite

often this will be filtered in some way or another to reduce the number of items / rows.

For example ... "Customers not ordering last month" .....

Finally, we need to see that if we use 'L2S' we will have our references section similar to that shown below,

and notice the lack of any 'Entity' reference entries :-

===========================================

So having seen a Model made from SQL data used in a simple example, lets move on to SQL data

from an application using "Entity Framework 6".

"Linq 2 Entity" :

[ .. we will do a more in-depth of what EF6 is soon .. ]

First of all guys, if we are working on an application using Entity Framework and 'L2E' technology

then there will be entries in the SE pane similar to those see below, in highlight :-

================================================

And now we have a good indication that it is 'L2E' that we are using, lets see a typical GUI from the

working application - check below :-

====================================================================================================

Yes, in the above image we see three Speakers and 'Sessions' would suggest an 'Entity' as this property

is actually another Collection item for each row and Speaker item.

Lets now see the C# code for the 'ReturnAllSpeakers' static member which is within the 'thin data layer' :-

============================================================================================================

You can now see the LINQ ClassLibrary project in the following image,

=================================================

And now we can use the Model by coupling it either to the 'DataGrid' or the more general Window itself.

Check the code details shown below :-

==============================================================================================

Lines 31 through 33 show gradual improvements in the style of coding and 'pattern' application.

And below are the visible results of this improvement :-

===============================================================================================

Of course the 'SpeakerView' needs to be called from an event handler in this simple example.

But first lets examine in detail the XAML script with its binding settings :-

==========================================================================================================================

Make sure you study all the bindings in lines 11 and then 21 through 28.

Line 8 above is rather special as it binds a collection in the Speaker item itself.

Now then, as promised, we can see how the event handler calls the View to be displayed - check below :-

=========================================================================================

Notice for this simple example we have not used data injection on line 86, but rather we have left

the coupling to be done on line 33 in the image 4 above, in the Initialise method of the View for Speakers.

Finally, lets consider and study the 'SpeakersModel' as when it is dressed up nicely for our use :-

====================================================================================================

And that's it folks.

Nothing particularly special, BUT, it helps us while coding in the future if we try to apply one type of approach.

I am going to stick with Model injection into the ViewModels, whenever I have a SQL collection returned.

Time to move on, see you in the next subsection..............................

PHH - 9th. December 2014 & 24th. & 25th. February 2015.

Addendum - the 'ConfContext' class :

You may wish to see the following code as it is used to access the data in every query we send to the database.

However, there is much more detail to follow if you go and look in the next two or three chapters.

==============================================================================================================

See you in the next section.


'Towards' EF6 - what is it all about ?

Older eNotes publication - for EF 4.3 is to be found at :-

http://www.winclickstartvulcan2.net/WebNotes/ClickStartEF/ClickStartEF.html

In these eNotes we will be using EF6 ('Entity Framework 6') as that is the current version.

However, I see that version 7 is already talked about in the web search 'hits'.

Before we get to use EF fully, we need to do some preparatory work with 'Link to SQL' and also 'Code First'.

When we are familiar with that approach then we can move on to the EF (framework) where we get to use 'entities'.

So the five subsections of the remaining part of this chapter (chapter 13) will be based on Code First 'Linq to SQL'.

It would appear that Microsoft developed (historically) "Linq to Objects", then "Linq to SQL", and then "Linq to Entities", as

the later technologies tend to depend on the earlier 'stuff'.

On the other hand 'Code First' and 'Database First', seems to have been done with the earlier technologies, and only when EF

came into being did we see 'Model First' and the likes.

'Code First' will play a big part in what we are doing in these eNotes !

Once you get to use and have success with EF and CodeFirst, or even 'Linq to SQL' you will not want to stop using it.

It's GREAT ;-0)

Here is some visual 'stimulus' to get us going - two Collections displayed :-

==========================================================================================================================

The above detail is part of a test and development example I found on the web, and which I developed further.

Its as good a place to start as any.

Here is my SQL 'Object Explorer' in my Visual Studio IDE :-

===============================================================

And further down the pane we the entry for the DVDs sample we are using - check this :-

============================================

[ .. as seen from Management Studio .. ]

Yes, we have three Tables, all seen above. Soon we will see how to create these from our .NET code.

First of all we need to see where we specify our file path for our SQL database 'to be' :-

========================================================================================

We will need to use the above quite often as we code our application. 'cConnect' is what we will use.

Okay folks, lets define our new database - doesn't take many lines for a simple application - check below :-

===================================================================================

Line 111 is a Constructor.

We now have to be CAREFUL when reading the image detail above - it says make a database called 'ourDBname'

and give it three Tables based on custom classes 'DVD', 'Customer', and 'Sale'.

We must be very careful not to get mixed up, as the .NET class 'MyDVDs' will has public properties which are Tables,

and these properties will be named 'DVDs', 'myCustomers' and 'ourDVDsales'. These will not usually be the Table

names within the SQL database.

So where do the SQL Tables get their names from ?

When we see the results in the explorer pane we see something like this - check below :-

========================================

[ .. as seen from Visual Studio - SQL Server Object Explorer .. ]

Lets look in detail at the Table to be named 'DVD_Customer' - here shown below, we have specified

the name of the Table in SQL to be "DVD_Customer" - that is how we name it for the DB - check it out below :-

===========================================================================

Now then guys, in the code shown above we can see both how we name the SQL Table object as well as

how we may name each Column object in the database.

Unfortunately, our example does not change ant column name from its default, so lets check out another

Table - see below for that for 'Sale' :-

=================================================================================================

Yep! - we have tried to supply three different column names in the code seen above.

So what we now need to do is look inside the database with VS 'SSOE' (SQL Server Object Explorer).

=======================================================================

Okay then folks, lets now do a test with the .NET code we have. Let us use intellisense to help us examine

the members of an instantiated object of type 'MyDVDs', and note their names - check below :-

============================================================================

And then further down the drop list we see this :-

==============================================

Well yes, we have success, as we can clearly see 'myCustomers', 'ourDVDsales', and also 'DVDs'.

So in our public .NET classes for Database and Tables, we have specified both SQL Server end of

things as well as .NET object end of things. A complete mapping.

Notice how that in lines 81, 84 & 87 above we can specify other attributes which come though into the

created Table - the following image helps explain this - check it out carefully :-

==========================================================================================================================================================

Okay then guys, our last point before we move on is that the term 'Entity' comes from when

we have defined code and Table mapping so that it is more complex than a 'one to one' relationship.

If we define a class of object such that one or more properties relate to other Tables, then we get

a complex class - such an item can be termed an 'entity'. So we often get returned from a query a

collection of entities.

Unfortunately, the simple example based on the DVD sales shown above, does not have an entity definition.

So we need to move to my own sample based on the Vulcan.Live.15 conference.

Check out the following image, particularly where we have a 'virtual' entry like lines 191 & 192.

So a Speaker object is likely to have data from the 'Registration' Table as well as a data Collection

based on entries in the 'Session' Table.

So a Speaker .NET object maps to three tables, Speaker, Session and Registration.

I am reasonably sure that an Entity is the instantiated object of such a complex mapping.

Anyway, once we get into coding these things, they get easier and easier to use and handle, so in one

sense it does not matter if we really know what an 'Entity' actually is !!!

Time to move on ...............

In the following few parts of this chapter we will see how to design and code such EF applications so that

they build and run quite smoothly, as well as have the related data carry out Data Binding in a 100% successful

manner.

Roll your sleeves up and we will get going ....................

PHH - 9th. & 27th. December 2014 & 25th. February 2015.


First simple example in C#

Hi there guys, the good news is that this EF6 stuff can be quite easy and straightforward if we

are not expecting to do anything too complex or complicated.

We can do some nice things quite quickly and easily ;-0)

We are going to do pretty much what most folks will do with a standard SQL application.

Our first two sample applications will be coded in C# and XAML script, simply because some of

what we require is built-in to the C# compiler and not as yet the Vulcan compiler.

It is the LINQ capability which is missing from VN3 at the moment. This means that we will structure

our solution in the SE pane so that we can at a later stage have a 'thin data layer' class library

written in C#, and call this from our Vulcan main .NET application code.

In preparation for this 'future' structure, we will separate out most of our 'Data Source' members into

the class called 'OurData' which is seen below to be in the code file entitled 'DataToAndFrom.cs' which

actually refers to the back-end SQL server and database.

Check out thoroughly the following application solution structure :-

=====================================================================

And here is a collapsed view of the new code file - check carefully below :-

=================================================================================================

[ .. note above that we are still missing static members for 'DVD' .. but these would be VERY similar .. ]

[ .. to those for Customer and Sale .. ]

In fact, thinking ahead, it is a good idea to have a new folder and code file for the classes which

are needed to define the Tables, and also the Database itself.

Below we have added the new folder highlighted, and the code file just below it - check them out :-

====================================================

Here is a collapsed view of the new code file into which I have moved the

existing classes, as discussed above :-

================================================================

Note that Table and Database classes have attributes defined for Database, Table, and Column.

Below I will display a small handful of 'hover tips' - check them carefully and thoroughly :-

=================================================================================================

===================================================================================

================================================================================================================================

When we are coding with LINQ and for Entity Framework we do need to have a few extra namespaces

included in our directives at the top of our code - here are a few useful 'usings' :-

=============================================================================================

And when we hover over 'DataContext' we see that the Tooltip tells us it is for 'LINQ to SQL'.

Check these details :-

======================================================================

*** Tip *** "DataContext" is for when we are using 'LINQ to SQL' and "DbContext" is when we are using 'LINQ to Entity'.

*** Tip 2 *** 'Data' for simple Tables (SQL) and 'DataBase' for Entity.

Check this from a EF sample :-

============================================================================================================================================================================================

So for now we will continue to use 'DataContext' and the 'Linq2SQL' technology. However, a lot of what

we do is part of a common approach to both technologies, and moving on to L2E (Linq to Entity) later

will be quite straightforward.

Lets have a look at how many Code First applications start up - check this out :-

============================================================================================

Yep! - we always see a method related to creating a database, and then usually a method or two to

retrieve data from a LINQ query.

Before we look at making (or creating) a database, lets look at a string which we will need to make

a connection to the database - many times from within our code.

Check this out - a useful static property :-

=====================================================================================

So now we can hopefully connect to our DB we need to see the class we need to use along

with the input connection string to its Constructor.

Checkout what Initialize does - in thorough detail :-

=============================================================================

Notice the lines and places where 'Sales' are referred to - lines 50/51 and 80.

Lets now move on .............

Here is the application DVD class which is sub-classed from 'DataContext' :-

[ .. we have defined three Tables .. ]

============================================================================================================

Yes, we have two Collections returned from a LINQ query, or two.

The right hand side collection is based on the 'Sale' class, and so we need to look more thoroughly at 'Sale'.

Here are a few useful STATIC members :-

============================================================================================

And for one of these members, here is the working code :-

========================================================================================

Yes, we have hard-coded the original data so that we can repeatedly delete and create the SQL database.

In order to complete the Creation process we need a member to populate the Sales Table - try this for size ;-0)

===================================================================================

By now the code should have populated the SQL Sales Table object within the database,

and to prove it here is what we see from within Management Studio :-

================================================================================================================

If we now wish to get this information back from the DB and into our running application code, then we

need a STATIC member to do the reading - check this out :-

================================================================================

Yes, the above is a piece of LINQ query code, and basically it gets returned all existing rows from

the Sales Table which is called 'DVD_Sale' in the SQL database - see the image two above.

So all we need to see now is how we couple the returned data Collection to the 'DataGrid' element.

===============================================================================================

Line second to last is where the coupling takes place - the second 'DataGrid' is coupled with the

returned collection.

If you wish to see, copy and use the working code for this - and XAML script - then look in detail

at the child section from here.

Lets now move on to the second simple example, see you there ............................

PHH - 28th. December 2014 & 25th. February 2015.


working script and code

====================================================

=====================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS1

{

    public partial class MainWindow : Window

    {

        //----- constructors -----

        public MainWindow()

        {

            InitializeComponent();

            this.Initialise();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessage.Text = "information will be displayed ...";

            try

            {

                MyDVDs db = new MyDVDs(OurData.cConnect);

                if (db.DatabaseExists())

                { db.DeleteDatabase(); }

                //-----------------------------------------------

                this.CreateDatabase();

                OurData.FillTableWithBunchCustomers();

                this.GetBackCustomers();

                //---------------------------------

                OurData.FillTableWithBunchSales();

                this.GetBackSales();

            }

            catch (SystemException oEX)

            {

                this.tblkMessage.Text = oEX.Message;

            }

        }

        public void CreateDatabase()

        {

            MyDVDs db = new MyDVDs(OurData.cConnect);

            if (db.DatabaseExists())

            {

                string cMessage = "Deleting old database...\n";

                cMessage += "now we have TWO tables ...";

                this.tblkMessage.Text = cMessage;

                db.DeleteDatabase();

            }

            db.CreateDatabase();

            this.tblkMessage.Text = "database made / re-made ....";

        }

        //-------------------------------------------

        public void GetBackCustomers()

        {

            List<Customer> aList = OurData.ReturnAllSQLcustomers(OurData.cConnect);

            this.dgL2QcodeFirst.DataContext = aList;

            this.tblkMessage.Text = "Object count :- "+aList.Count.ToString();

        }

        public void GetBackSales()

        {

            List<Sale> aList = OurData.ReturnAllSQLsales(OurData.cConnect);

            this.dgL2QcodeFirst2.DataContext = aList;

            this.tblkMessage2.Text = "Object count :- "+aList.Count.ToString();

        }

        //-------------------------------------------

    }

    [Database(Name="OurDBname")]

    public class MyDVDs : DataContext

    {

        public Table<DVD> DVDs;

        public Table<Customer> myCustomers;

        public Table<Sale> ourDVDsales;

        public MyDVDs(string connection) : base(connection)

        {

        }

    }

    //=========================================================

    [Table(Name = "DVD_DVD")]

    public class DVD

    {

        [Column(IsPrimaryKey = true)]

        public string Title;

        [Column]

        public string Rating;

        public DVD() { }

        public DVD(string cT, string cR) { }

    }

    //=========================================================

    [Table(Name = "DVD_Customer")]

    public class Customer

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int CustID { get; set; }

        [Column]

        public string Name { get; set; }

        [Column]

        public string Address { get; set; }

        //----- Constructors -----

        public Customer() { }

        public Customer(string cN, string cA)

        {

            this.Name = cN;

            this.Address = cA;

        }

    }

    //=========================================================

    [Table(Name = "DVD_Sale")]

    public class Sale

    {

        [Column(Name = "DVD_SaleId",IsPrimaryKey = true, IsDbGenerated = true)]

        public int SaleID { get; set; }

        [Column(Name = "DVD_SalesPerson", CanBeNull=false)]

        public string SalesPerson{ get; set; }

        [Column(Name = "DVD_SaleWhenMade", CanBeNull = false)]

        public DateTime DateMade { get; set; }

        public Sale() { }

        public Sale(string cSP, DateTime dtWM)

        {

            this.SalesPerson = cSP;

            this.DateMade = dtWM;

        }

    }

}

=====================================================================================

<Window x:Class="VL15_CodeFirst_CS1.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Code First - Start !" Height="350" Width="725">

    <Grid>

        <TextBlock HorizontalAlignment="Left" Height="87" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"

                   Name="tblkMessage" Width="285"/>

        <DataGrid GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  HorizontalAlignment="Left" Margin="10,52,0,0"

                  VerticalAlignment="Top" Height="241"

                  Name="dgL2QcodeFirst" Width="285"

                  AutoGenerateColumns="True"  />

        <TextBlock HorizontalAlignment="Left" Height="87" Margin="384,10,0,0"

                   TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"

                   Name="tblkMessage2" Width="285"/>

        <DataGrid GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  HorizontalAlignment="Left" Margin="384,52,0,0"

                  VerticalAlignment="Top" Height="241"

                  Name="dgL2QcodeFirst2" Width="285"

                  AutoGenerateColumns="True"  />

    </Grid>

</Window>

=====================================================================================

//----- DataToANdFrom.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS1

{

    public class OurData

    {

        //----- alternative Static Field -----

        //public static string cConnect = @"c:\Users\ourDvds13B.mdf";

        //----- properties -----

        public static string cConnect

        {

            get

            {

                return  @"c:\Users\ourDvds13B.mdf";

            }

        }

        //----- CARE can get deadly embrace for 'removal' after -----

        //----- using Management Studio -----

        //----- Customer -----

        //-------------------------------------------------------------

        public static List<Customer> MakeBunchOfCustomers()

        {

            List<Customer> aList = new List<Customer>();

            aList.Add(new Customer("James Bolam","Sunderland, N.E."));

            aList.Add(new Customer("Mary Malone","New York, USA"));

            aList.Add(new Customer("Dan Logan","Romania, Europe"));

            aList.Add(new Customer("Paul Piko","Australia"));

            aList.Add(new Customer("Julie Kift","Durham, UK"));

            aList.Add(new Customer("Ben Hepburn","Newport, S.Wales"));

            aList.Add(new Customer("Michael Stein","Seven Oaks, UK"));

            aList.Add(new Customer("Jimmy Joule","Ireland"));

            return aList;

        }

        public static void FillTableWithBunchCustomers()

        {

            MyDVDs db = new MyDVDs(OurData.cConnect);

            if (db.DatabaseExists())

            {

                Table<Customer> OurCustomers = db.GetTable<Customer>();

                OurCustomers.InsertAllOnSubmit(OurData.MakeBunchOfCustomers());

                db.SubmitChanges();

            }

        }

        public static List<Customer> ReturnAllSQLcustomers(string cConnect)

        {

            MyDVDs db = new MyDVDs(cConnect);

            if (db.DatabaseExists())

            {

                Table<Customer> OurCustomers = db.GetTable<Customer>();

                var query =

                    from c in OurCustomers

                    select c;

                var aList = query.ToList();

                return aList;

            }

            return new List<Customer>();

        }

        //-------------------------------------------------------------

        //----- Sale -----

        public static List<Sale> MakeBunchOfSales()

        {

            List<Sale> aList = new List<Sale>();

            aList.Add(new Sale("Micky Most", new DateTime(2002, 02, 02)));

            aList.Add(new Sale("Alan Lender", new DateTime(2005, 05, 25)));

            aList.Add(new Sale("Sally Smith", new DateTime(2007, 12, 22)));

            aList.Add(new Sale("Jenny Gin", new DateTime(2012, 11, 29)));

            aList.Add(new Sale("Julie Kift", new DateTime(2013, 04, 21)));

            return aList;

        }

        public static void FillTableWithBunchSales()

        {

            MyDVDs db = new MyDVDs(OurData.cConnect);

            if (db.DatabaseExists())

            {

                Table<Sale> OurSales = db.GetTable<Sale>();

                OurSales.InsertAllOnSubmit(OurData.MakeBunchOfSales());

                db.SubmitChanges();

            }

        }

        public static List<Sale> ReturnAllSQLsales(string cConnect)

        {

            MyDVDs db = new MyDVDs(cConnect);

            if (db.DatabaseExists())

            {

                Table<Sale> OurSales = db.GetTable<Sale>();

                var query =

                    from s in OurSales

                    select s;

                var aList = query.ToList();

                return aList;

            }

            return new List<Sale>();

        }

        //-------------------------------------------------------------

    }

}

=====================================================================================

<Application x:Class="VL15_CodeFirst_CS1.App"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             StartupUri="MainWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

=====================================================================================

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Threading.Tasks;

using System.Windows;

namespace VL15_CodeFirst_CS1

{

    /// <summary>

    /// Interaction logic for App.xaml

    /// </summary>

    public partial class App : Application

    {

    }

}

=====================================================================================

PHH - 28th. December 2014.


Second simple example in C#

Okay then folks, since we have seen a working example 'in action', we can now move on to

design and create our own working applet, and one based on the 'Registration' class for the

2015 Vulcan.Live software conference in Cologne, Germany.

As with the previous example, we will use the 'Code First' approach, where we define classes

for Tables and the Database, and then use these to create from the running code, the SQL

database itself.

We will also provide some STATIC members to populate the new DB tables.

As with most things in these eNotes, we will end up with data being bound from public properties

on the 'ViewModel', to suitable attributes on the UI elements of the 'View'. The views will be Window

objects and the ViewModels our own data objects.

Our data Models will always come directly from SQL tables, as returned collections to SQL queries.

We will not transform the data objects themselves (at all), but use them directly when instantiating

ViewModel objects - by the 'data injection' approach.

In the previous example we left out the ViewModel, as we were in fact following a coding approach

from either an eBook, or suitable articles, on 'Linq2SQL' / Entity Framework and the 'Code First' pattern of working.

So in the application associated with this subsection, we will put the two approaches together - CF and MVVM, but

without the supporting framework.

Let us make a start by looking at the working finished applet study the following image carefully.

You should see a main screen and three sub-screens each with a bound collection returned from the SQL database :-

==============================================================================================================================================

Lets expand the green 'Sessions' window to see all the collection item columns in the 'DataGrid' UI element :-

=======================================================================================================================================================

Although the display works just fine, it is not the best way to couple data to the View bindings.

Lets have a look at what we have in our code at the moment - check line 26 in the following image :-

============================================================================================

If we apply the MVVM 'pattern' we should NOT be naming UI elements and using these names in .NET code.

We should also be making one ONLY coupling, and that should be to the form itself - whether it is a Window or

a UserControl.

This means that lines 26 & 27 should be replaced by a single line of code to associate a single data object which

is a ViewModel object. This would then be termed 'loose coupling'. More on this later.

For now, lets study the existing XAML script to see the data binding for the 'DataGrid' on line 9 :-

========================================================================================================================

Since we have only one binding, we could change the code as seen in line 27 below.

Note the TextBlock element is having text data directly assigned, another 'No-No' from the MVVM point of view.

Checkout below :-

============================================================================================

We will revisit this aspect of data binding in the Conference application when we come to the next

subsection.

For now, lets see how we have gone about making a new WPF / XAML / L2S / CF project.

Making a Start - a new Project :

Lets take a look at our existing application Project, as it looks when all major nodes are collapsed.

Here is what I see on my development platform :-

===================================================

Now close our last project right down to just the Project node level - see below :-

==========================================================

Okay then folks, we can now choose to add a new Project, a second one to our solution.

Highlight the Solution node and then click the right mouse button to get the context menu :-

========================================================================================================

Choose to add a new project of type WPF application - below is my dialogue screen:-

===========================================================================================================================

And immediately you should see something like the following in your SE pane :-

==========================================================

Now we need to set the new project up as the 'Start' project - once again use the Context Menu,

but this time highlight the second project node in the SE pane. Check the image shown below :-

=================================================================

Once you change the 'StartUp' project the bold type will appear over the second project node.

Below we see the newly sight bold of the second project, as well as the expanded 'References' node :-

=====================================================

We need to add a single reference, one for the 'LINQ' we require, soon.

However, lets add it now :-

=====================================================================================================================

If you have been following me, and using the 'walk-through' type approach, you may also have the

'System.Data.Ling' in the 'Recent' tab.

Find the correct reference and add it - by checking it first and then clicking 'OK' :-

==============================================================================================================

If you do things right you will get the following as a result of your efforts :-

===================================================

Change the Title of the main window and then build and run the new project - see below :-

=================================================================

In the following image you will see where to change the Title for the Window :-

==================================================================================

What we now need is a bunch of new 'Folders' in the SE pane - for our new project.

===================================================================================

The required five folders are shown along with their names in the following image :-

======================================================

At the moment we may not use them all, as we gradually develop our EF6 and 'Code First' skills.

And now we will examine a preview example of what we are trying to achieve, or create :-

==================================================================================

Notice above that we have three push buttons, one for displaying each of the three Tables

we will put into our new database.

Since it is the 'Code First' and View/ViewModel data binding that we are needing to focus on then

we will not type in a whole heap of data / information - just enough for testing and demonstration.

Below is some detail to keep us interested - relating to Registration :-

===================================================================================================================================================

Above we have hard-coded a few Registration objects which will be used to populate the new SQL Table for Registrations.

There will be two others like above which provide hard-coded data for Sessions and HotelReservations.

Firstly, we need to study what our Conference sample application does when it is launched.

Study the following details :-

==============================================================================================

The above code shows that before any buttons are pressed all that happens is that the new SQL database

is created (more on that later) and the main window is initialised and displayed.

Here is the main display form :-

===========================================================

But behind the scenes we have had our SQL database made quite silently and quickly, and successfully.

Here is what just happened :-

==========================================

Yes, the DB has three correctly named Tables.

And if we drill down deeper we see that the originally hard-coded data has populated these Tables.

Here is proof of one, the Registrations Table :-

========================================================================================================================================

The above details (and the image above that) have been copied from Management Studio.

Now then folks, lets see the code line which provides the file-path information.

Here below is what we used just there now :-

============================================================================

And yes, I confess it, I had previously made an error and left line 39 as it had previously been for an earlier

example, and now I have corrected it to read 'Conf01' for the first conference DB.

If we look at my file explorer we see all the evidence to support what I have just confessed - check this out :-

===========================================================================================================

Okay then folks, so we get a new database on application launch, so what does our code look like ?

Study these details quite thoroughly :-

=====================================================================================

Lines 33 through 42 are VERY important to our application.

They are about removing any previous database and creating a fresh and new one. This new DB

is then populated with some sample data for testing purposes. And that's it - done!

Okay then guys, line 39 above calls on the following static method for removal and creation - check it out :-

===========================================================================

Just so you remember, it is the code on line 52 above which cause the following DB structure to

be created on line 60 above - check below :-

===========================================================================

Lines 70 - 72 specify the three Tables to be made.

Obviously, the class specifications for Session, HotelReservation, and Registration are very

much involved in how the new tables look, their column details and more.

We need to examine these three class definitions in some details - here they are set out below :-

Session :

================================================================================================================================

and now .......

HotelReservation :

============================================================================================

and finally .........

Registration :

====================================================================================

Because we are still using Linq2SQL with our Code First, we will get flat Tables, meaning a one-to-one correspondence

of class definition to Table structure.

When we move on to EF6 in later sections this will be different, and more complex.

Notice how in the following small image we can set an attribute to allow a column value to be set to 'null'.

================================================================

We need to define 'Nullable' types if we do do this. I have given a few examples of 'Nullable' types in the

examples in these eNotes.

Lets now move on a pace or two ..............

Let us examine the STATIC members of our class called 'OurData' - these are all related to activities which

send data to populate the SQL tables, as well as those to query the database and have collections of items

returned to our application.

Checkout the names of these STATIC members shown below :-

==================================================================================================================

And now we should pick out a member or two from the above list and see the full details.

Let us examine the three STATIC members to deal with 'RegistrationsFull', a class we will study soon.

[ .. hard-code data, population, and read back .. ]

=======================================================================================================

We need to know that the 'Registration_full' class is an earlier 'Registration' class which has had the whole

'INotifyPropertyChanged' approach applied to it, so that it will do data binding 100%.

Here is a part collapsed view of this class :-

==========================================================================================

And one property expanded below, will be similar to the rest - here is a typical one :-

==========================================================================================

Okay then folks, lets see how the View for 'Registrations' does what it has to - study below thoroughly :-

==================================================================================================================

The way we have the code set out for this first attempt at a Conference application, shows that we

read back the Registration data and couple it, all within the "GetBackRegistrations" method shown above.

As we said at the top of the subsection, the coupling shown on line 45 can be done in a better way, with a VM object

as well as coupling to the form (or Window) itself, rather than a UI element by name.

However, this subsection has been a step forward, and we have data in SQL tables, and can display it after a query

to the DataGrid on form. So we are getting somewhere I feel.

Oh! I should have said, the reason we scope the returned collection lists as we do in the MainWindow is

so that we can have multiple Registration screens open and data binding and edit changes will work and

show up nicely.

Check the next two images shown below :-

======================================================================================================

Let us take the name of our friend Willie Moore and change it to 'William' :-

======================================================================================================================================

Note that as soon as the focus changes the change shows up in the other two screens.

Time to more on and see how we can improve our Conference application.

We need to employ a proper ViewModel for each View, as well as inject SQL collection data into the VM.

Finally, in a further section, we can create Entities so that we can have more complex Business classes.

See you in the next subsection .........................

PHH - 28th. & 29th. December 2014 & 26th. February 2015.


working script and code

==========================================================

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//----------------------------------

using VL15_CodeFirst_CS2.a_Views;

namespace VL15_CodeFirst_CS2

{

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

            this.Initialize();

        }

        public void Initialize()

        {

            //----- need to Create DB at the highest level ! -----

            //----- not in the code behind the 'View's -----

            try

            {

                OurGlobals.OurCreateDB();

            }

            catch(SystemException oEX)

            {

                MessageBox.Show(oEX.Message,"my Error HIGHest! :");

            }

        }

        private void pbRegistration_Click(object sender, RoutedEventArgs e)

        {

            RegistrationsView oRV = new RegistrationsView();

            oRV.Show();

        }

        private void pbSessions_Click(object sender, RoutedEventArgs e)

        {

            SessionsView oSV = new SessionsView();

            oSV.Show();

        }

        private void pbHotelReservations_Click(object sender, RoutedEventArgs e)

        {

            HotelReservationsView oHRV = new HotelReservationsView();

            oHRV.Show();

        }

    }

}

===============================================================================

<Window x:Class="VL15_CodeFirst_CS2.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Code First - C# app two :" Height="350" Width="525"

        Background="Beige">

    <Grid>

        <Button Content="Registrations" HorizontalAlignment="Left" Margin="50,44,0,0"

                Name="pbRegistration" VerticalAlignment="Top" Width="103"

                Click="pbRegistration_Click" Background="LightCoral"/>

        <Button Content="Sessions" HorizontalAlignment="Left" Margin="50,74,0,0"

                Name="pbSessions" VerticalAlignment="Top" Width="103"

                Click="pbSessions_Click" Background="LightGreen"/>

        <Button Content="Hotel Reservations" HorizontalAlignment="Left" Margin="50,104,0,0"

                Name="pbHotelReservations" VerticalAlignment="Top" Width="152"

                Click="pbHotelReservations_Click" Background="LightBlue"/>

        <TextBlock Name="txblkMessageM" HorizontalAlignment="Left" Margin="10,151,0,0" TextWrapping="Wrap"

                   Text=".. will change .." VerticalAlignment="Top" Height="27" Width="192"/>

    </Grid>

</Window>

===============================================================================

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Threading.Tasks;

using System.Windows;

namespace VL15_CodeFirst_CS2

{

    /// <summary>

    /// Interaction logic for App.xaml

    /// </summary>

    public partial class App : Application

    {

    }

}

===============================================================================

<Application x:Class="VL15_CodeFirst_CS2.App"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             StartupUri="MainWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

===============================================================================

//----- MyEnums.prg -----

//----- PHH - 1th. December 2014. -----

using System;

namespace VL15_CodeFirst_CS2{

    public enum FoodPreference

    {

        Vegan,

        Vegetarian,

        Carnivore,

        FishOnly,

        NoneAsYet,

    }

    public enum HotelAccommodation

    {

        Single,

        Double,

        Suite,

        None,

        NoneAsYet,

    }

    public enum TransportMode

    {

        Bicycle,

        Motorbike,

        Coach,

        Train,

        Metro,

        Airplane,

        None,

        NoneAsYet,

    }

}

===============================================================================

//----- DataBasesAndTables.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS2

{

    public class OurGlobals

    {

        public static void OurCreateDB()

        {

            try

            {

                VL15_demo db = new VL15_demo(OurData.cConnect);

                if (db.DatabaseExists())

                { db.DeleteDatabase(); }

                //-----------------------------------------------

                OurGlobals.CreateDatabase();

                OurData.FillTableWithBunchRegistrations();

                OurData.FillTableWithBunchSessions();

                OurData.FillTableWithBunchHotelReservations();

            }

            catch (SystemException oEX)

            {

                MessageBox.Show(oEX.Message,"my Errors :");

            }

        }

        //=========================================================

        public static string CreateDatabase()

        {

            VL15_demo db = new VL15_demo(OurData.cConnect);

            if (db.DatabaseExists())

            {

                string cMessage = "Deleting old database...\n";

                cMessage += "now we have THREE tables ...";

                db.DeleteDatabase();

                return cMessage;

            }

            db.CreateDatabase();

            return "database made / re-made ....";

        }

    }

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    //=========================================================

    [Database(Name = "Our_VL15_DB1")]

    public class VL15_demo : DataContext

    {

        public Table<Registration> Registrations;

        public Table<Session> Sessions;

        public Table<HotelReservation> HotelReservations;

        public VL15_demo(string connection) : base(connection)

        {

        }

    }

    //=========================================================

    [Table(Name = "Registrations")]

    public class Registration

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int RegistrationID { get; set; }

        [Column]

        public string Firstname { get; set; }

        [Column]

        public string Lastname { get; set; }

        [Column]

        public string Country { get; set; }

        [Column]

        public string Company { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<double> Cost { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<Boolean> HasPaid { get; set; }

        //----- Constructors -----

        public Registration() { }

        public Registration(string cF, string cL, string cCT, string cCP, Nullable<double> nC, Nullable<Boolean> lHP)

        {

            this.Firstname = cF;

            this.Lastname = cL;

            this.Country = cCT;

            this.Company = cCP;

            this.Cost = nC;

            this.HasPaid = lHP;

        }

    }

    //=========================================================

    [Table(Name = "Sessions")]

    public class Session

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int SessionID { get; set; }

        [Column]

        public string Title { get; set; }

        [Column]

        public string Resume { get; set; }

        [Column]

        public string Speaker { get; set; }

        [Column]

        public string Language { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<DateTime> StartDateTime { get; set; }

        [Column]

        public Boolean Repeat { get; set; }

        [Column(Name="RoomNo")]

        public int RoomNumber { get; set; }

        //----- Constructors -----

        public Session() { }

        public Session(string cT, string cR, string cS, string cL, Nullable<DateTime> dtSDT, Boolean lR, int nRN)

        {

            this.Title = cT;

            this.Resume = cR;

            this.Speaker = cS;

            this.Language = cL;

            this.StartDateTime = dtSDT;

            this.Repeat = lR;

            this.RoomNumber = nRN;

        }

    }

    //=========================================================

    [Table(Name = "HotelReservations")]

    public class HotelReservation

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int ReservationID { get; set; }

        [Column]

        public int RegistrationID { get; set; }

        [Column]

        public string BookingName { get; set; }

        [Column]

        public int NoOfNights { get; set; }

        [Column(CanBeNull=true, Name="RoomNum")]

        public Nullable<int> Room { get; set; }

        [Column]

        public FoodPreference eFood { get; set; }

        [Column]

        public HotelAccommodation eHotel { get; set; }

        [Column]

        public TransportMode eTrans { get; set; }

        //----- Constructors -----

        public HotelReservation() { }

        public HotelReservation(int nR, string cBN, int nN, Nullable<int> nRM,

                FoodPreference eF, HotelAccommodation eH, TransportMode eT)

        {

            this.RegistrationID = nR;

            this.BookingName = cBN;

            this.NoOfNights = nN;

            this.Room = nRM;

            this.eFood = eF;

            this.eHotel = eH;

            this.eTrans = eT;

        }

    }

    //=========================================================

}

===============================================================================

//----- DataToAndFromServer.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS2

{

    public class OurData

    {

        //----- alternative Static Field -----

        //public static string cConnect = @"c:\Users\ourDvds13B.mdf";

        //----- properties -----

        public static string cConnect

        {

            get

            {

                return @"c:\Users\ourDvds13C.mdf";

            }

        }

        //----- CARE can get deadly embrace for 'removal' after -----

        //----- using Management Studio -----

        //----- Registration -----

        //-------------------------------------------------------------

        public static List<Registration> MakeBunchOfRegistrations()

        {

            Nullable<double> oND = new Nullable<double>();

            Nullable<Boolean> oNB = new Nullable<Boolean>();

            //--------------------------------------------

            List<Registration> aList = new List<Registration>();

            aList.Add(new Registration("Dan","Logan","Romania","Super Fly",139.31, true));

            aList.Add(new Registration("Ben","Hepburn","Wales","Fleasy Finance", oND, oNB));

            aList.Add(new Registration("Willie","Moore","USA","ATnT",235.79, false));

            return aList;

        }

        public static void FillTableWithBunchRegistrations()

        {

            VL15_demo db = new VL15_demo(OurData.cConnect);

            if (db.DatabaseExists())

            {

                Table<Registration> OurRegistrations = db.GetTable<Registration>();

                OurRegistrations.InsertAllOnSubmit(OurData.MakeBunchOfRegistrations());

                db.SubmitChanges();

            }

        }

        public static List<Registration> ReturnAllSQLregistrations(string cConnect)

        {

            VL15_demo db = new VL15_demo(cConnect);

            if (db.DatabaseExists())

            {

                Table<Registration> OurRegistrations = db.GetTable<Registration>();

                var query =

                    from r in OurRegistrations

                    select r;

                var aList = query.ToList();

                return aList;

            }

            return new List<Registration>();

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        //-------------------------------------------------------------

        //----- Session -----

        public static List<Session> MakeBunchOfSessions()

        {

            Nullable<DateTime> oNDT = new Nullable<DateTime>();

            //--------------------------------------------

            List<Session> aList = new List<Session>();

            aList.Add(new Session("Survey Flights", "using a hexacopter to gather survey data, then processing it.",

                "Frank Maraite", "German", DateTime.Now, false, 12));

            aList.Add(new Session("Advanced VN3", "Structuring the SE pane to aid good design.",

                "Dieter Crispien", "German", oNDT, true, 17));

            aList.Add(new Session("Views & VMs", "Designing ViewModels to work best with Views.",

                "Phil Hepburn", "English", new DateTime(2015,4,20,15,00,00), true, 39));

            return aList;

        }

        public static void FillTableWithBunchSessions()

        {

            VL15_demo db = new VL15_demo(OurData.cConnect);

            if (db.DatabaseExists())

            {

                Table<Session> OurSessions = db.GetTable<Session>();

                OurSessions.InsertAllOnSubmit(OurData.MakeBunchOfSessions());

                db.SubmitChanges();

            }

        }

        public static List<Session> ReturnAllSQLsessions(string cConnect)

        {

            VL15_demo db = new VL15_demo(cConnect);

            if (db.DatabaseExists())

            {

                Table<Session> OurSessions = db.GetTable<Session>();

                var query =

                    from s in OurSessions

                    select s;

                var aList = query.ToList();

                return aList;

            }

            return new List<Session>();

        }

        //-------------------------------------------------------------

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        //-------------------------------------------------------------

        //----- Hotel Accommodation -----

        public static List<HotelReservation> MakeBunchOfHotelReservations()

        {

            Nullable<int> oNI = new Nullable<int>();

            //--------------------------------------------

            List<HotelReservation> aList = new List<HotelReservation>();

            aList.Add(new HotelReservation(15, "Dan Logan", 3, 112,

                    FoodPreference.Carnivore, HotelAccommodation.Single, TransportMode.Airplane));

            aList.Add(new HotelReservation(17, "Ben Hepburn", 2, 213,

                    FoodPreference.FishOnly, HotelAccommodation.None, TransportMode.Bicycle));

            aList.Add(new HotelReservation(11, "Willie Moore", 4, 97,

                    FoodPreference.Vegetarian, HotelAccommodation.Suite, TransportMode.Train));

            aList.Add(new HotelReservation(01, "Michael Fischer", 5, oNI,

                    FoodPreference.NoneAsYet, HotelAccommodation.None, TransportMode.Metro));

            return aList;

        }

        public static void FillTableWithBunchHotelReservations()

        {

            VL15_demo db = new VL15_demo(OurData.cConnect);

            if (db.DatabaseExists())

            {

                Table<HotelReservation> OurHotelReservations = db.GetTable<HotelReservation>();

                OurHotelReservations.InsertAllOnSubmit(OurData.MakeBunchOfHotelReservations());

                db.SubmitChanges();

            }

        }

        //---------------------------------------------------------------------------------------

        public static List<HotelReservation> ReturnAllSQLhotelReservations(string cConnect)

        {

            VL15_demo db = new VL15_demo(cConnect);

            if (db.DatabaseExists())

            {

                Table<HotelReservation> OurHotelReservations = db.GetTable<HotelReservation>();

                var query =

                    from hr in OurHotelReservations

                    select hr;

                var aList = query.ToList();

                return aList;

            }

            return new List<HotelReservation>();

        }

        //-------------------------------------------------------------

    }

}

===============================================================================

//----- OurDataModels.cs -----

//----- PHH - 28th. December 2014. -----

namespace   VL15_CodeFirst_CS2

{

    class OurDataModels

    {

         //----- Registrations -----

         //----- Sessions -----

         //----- HotelReservations -----

    }

}

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace VL15_CodeFirst_CS2.a_Views

{

    public partial class SessionsView : Window

    {

        public SessionsView()

        {

            InitializeComponent();

            this.Initialise();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessageS.Text = "information will be displayed ...";

            try

            {

                this.GetBackSessions();

            }

            catch (SystemException oEX)

            {

                this.tblkMessageS.Text = oEX.Message;

            }

        }

        //-------------------------------------------

        public void GetBackSessions()

        {

            List<Session> aList = OurData.ReturnAllSQLsessions(OurData.cConnect);

            this.dgL2Qcf_Sess.DataContext = aList;

            this.tblkMessageS.Text = "Object count :- " + aList.Count.ToString();

        }

        //-------------------------------------------------------------

    }

}

===============================================================================

<Window x:Class="VL15_CodeFirst_CS2.a_Views.SessionsView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Sessions - View :" Height="300" Width="500" Background="LightGreen">

    <Grid>

        <DataGrid Margin="10,40,10,10"

           GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  AutoGenerateColumns="True"

                  Name="dgL2Qcf_Sess"/>

        <TextBlock Name="tblkMessageS" HorizontalAlignment="Left" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="163" Height="25"/>

    </Grid>

</Window>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace VL15_CodeFirst_CS2.a_Views

{

    public partial class RegistrationsView : Window

    {

        public RegistrationsView()

        {

            InitializeComponent();

            this.Initialise();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessage.Text = "information will be displayed ...";

            try

            {

                this.GetBackRegistrations();

            }

            catch (SystemException oEX)

            {

                this.tblkMessage.Text = oEX.Message;

            }

        }

        //-------------------------------------------

        public void GetBackRegistrations()

        {

            List<Registration> aList = OurData.ReturnAllSQLregistrations(OurData.cConnect);

            this.dgL2Qcf_Reg.DataContext = aList;

            this.tblkMessage.Text = "Object count :- " + aList.Count.ToString();

        }

    }

}

===============================================================================

<Window x:Class="VL15_CodeFirst_CS2.a_Views.RegistrationsView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Registration - View :" Height="300" Width="500" Background="LightCoral">

    <Grid>

        <DataGrid Name="dgL2Qcf_Reg" Margin="10,40,10,10"

                  GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  AutoGenerateColumns="True"  />

        <TextBlock Name="tblkMessage" HorizontalAlignment="Left" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text=".. will change .." VerticalAlignment="Top" Width="230" Height="25"/>

    </Grid>

</Window>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace VL15_CodeFirst_CS2.a_Views

{

    public partial class HotelReservationsView : Window

    {

        public HotelReservationsView()

        {

            InitializeComponent();

            this.Initialise();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessageH.Text = "information will be displayed ...";

            try

            {

                this.GetBackHotelReservations();

            }

            catch (SystemException oEX)

            {

                this.tblkMessageH.Text = oEX.Message;

            }

        }

        //----------------------------------------------------------

        public void GetBackHotelReservations()

        {

            List<HotelReservation> aList = OurData.ReturnAllSQLhotelReservations(OurData.cConnect);

            this.dgL2Qcf_Hotel.DataContext = aList;

            this.tblkMessageH.Text = "Object count :- " + aList.Count.ToString();

        }

        //-----------------------------------------------------------------------

    }

}

===============================================================================

<Window x:Class="VL15_CodeFirst_CS2.a_Views.HotelReservationsView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Hotel Reservations - View :" Height="300" Width="500" Background="LightBlue">

    <Grid>

        <DataGrid Name="dgL2Qcf_Hotel" Margin="10,40,10,10"

                  GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  AutoGenerateColumns="True"  />

        <TextBlock Name="tblkMessageH" HorizontalAlignment="Left" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Height="25" Width="200"/>

    </Grid>

</Window>

===============================================================================

PHH - 28th. December 2014.


Updating the 'Second' example - changing SQL data

I suggest you first study the child sub-section from here, it looks at a general case of editing a returned

data collection and saving all the changes back to the SQL database with 'SubmitChanges()'.

PHH - 29th. December 2014.


Updating the DB with 'LINQ to SQL' - various approaches

This short subsection will look specifically at updating a back-end SQL Table from within the .NET code.

We will be using 'LINQ to SQL' of 'L2S' technology based on the class called 'DataContext'.

Here is the class we will be using as a test / demonstration.

=========================================================================

It would appear that the 'DataContext' gives us an easy way to have our 'Enities' or collection items,

tracked for changes, and mapped over a connection to the database.

However, we must be careful and also ;exact' in the way we use it in our code, and particularly with

the MVVM approach when we need to design ViewModels and Models with data public properties.

Here is what MSDN says about 'DataContext' :-

==============================================================================================================

And this is what we see in Help Viewer 2.0 :-

=========================================================================================================================================================

And here is some more information about the Constructors :-

======================================================================================================

Now that we know some more about 'DataContext', we need to make some experiments on how it can be used

by us in our different ways of coding with the MVVM 'pattern' approach.

In the next image we can the method which will help us handle our collection item changes, changes in all sorts

of different ways - when we edit a collection in a 'DataGrid' UI element - check the following :-

==========================================================================================================

So it would appear that this is the member of the DataContext class we need to use if we wish to make our

own developer lives easy ;-0)

Lets move on to set up a few experiments using our 'VL15_demo' class and see how its works for us.

To get us going lets make a new View in our application for this purpose - check this out :-

===============================================

And if we code things correctly we can get the new window to show at the same time as the MainWindow

form shows on screen.

Here is my results at launch time, before we add any extra functionality to the code behind.

===========================================================================

And now that we can get our new test window launched, we can add some suitable code behind.

Remember in the MVVM pattern we will not work with code behind, Windows and UserControls, but while

we are testing and learning about L2S this will be okay I feel ;-0)

You will need to study the following image VERY thoroughly, it contains some extremely useful 'stuff' :-

=======================================================================================================

The member called 'ReadInData2' is one of the most important sections of the code.

It reads the existing data from the SQL database at any time it is called and used.

If the returning collection is coupled with (or bound to) a DataGrid UI element, then all changes made by the

user can easily be saved back to the SQL database, in this case the Table called 'HotelReservation'.

Code line 53 is what causes the changes to be saved - yes, its as easy as that.

Code starting at line 61 allows us to see clearly the existing Table data by opening a 'nested' window and

showing the current Table rows within the DataGrid.

We can tidy up the above code slightly, or improve it by adding a Public Property which can be used for

Data Binding at a later stage of our coding and development.

Check out the new code changes in lines 3 through 49 below :-

=================================================================================================

If you are wondering where the type 'IQueryable' came from then checkout the image below and the

information coming from intellisense :-

=====================================================================================

So when we try out the new Test screen we can open it multiple times in a nested fashion (although

it is NOT really 'nested') - we are making changes in one screen, then forcing a save and then opening another

from the blue nested button.

Checkout rows (items) that go missing, and new rows appearing :-

================================================================================================================================================================

Remember that in order to save the changes in the SQL database, the red button MUST be pressed or clicked.

The green 'Fresh Read' button re-reads the existing SQL Table data by sending a fresh query to produce a

new returned collection.

Since the new and extra Window has to connect to the DB in order to show any data, then this is a useful check

that the details have been queried, and are not just there from a previous occasion !!

And now some cells which change, check Willie and Michael :-

============================================================================================================

Okay then guys, some good success, I think you will agree ;-0)

The above coding 'approach' will prove useful to us, as long as we are careful about types and scope in our code

design.

Time to move on ..................

PHH - 27th. February 2015.


working script and code

=======================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

//-----------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS2

{

    public partial class TestDataContextView : Window

    {

        public VL15_demo odcVL { get; set; }

        public IQueryable<HotelReservation_full> query3 { get; set; }

        public TestDataContextView()

        {

            InitializeComponent();

            this.SetCoupling();

        }

        public void ReadInData3()

        {

            odcVL = new VL15_demo(OurData.cConnect);

            Table<HotelReservation_full> OurHotelReservations =

                                odcVL.GetTable<HotelReservation_full>();

            this.query3 =

                from hr in OurHotelReservations

                select hr;

        }

        private void SetCoupling()

        {

            this.ReadInData3();

            this.dgTestDC.DataContext = this.query3;

        }

        private void pbForceSaveChanges_Click(object sender, RoutedEventArgs e)

        {

            this.odcVL.SubmitChanges();

        }

        private void pbFreshReadIn_Click(object sender, RoutedEventArgs e)

        {

            this.SetCoupling();

        }

        private void pbNestedWindow_Click(object sender, RoutedEventArgs e)

        {

            TestDataContextView oTDCV2 = new TestDataContextView();

            oTDCV2.Show();

        }

    }

}

=======================================================================================

<Window x:Class="VL15_CodeFirst_CS2.TestDataContextView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Test DataContext View :" Height="300" Width="500">

    <Grid>

        <DataGrid Name="dgTestDC" Height="164" Margin="10,35,10,0"

                  VerticalAlignment="Top" ItemsSource="{Binding}"/>

        <Button Content="Fresh Read In" HorizontalAlignment="Left" Margin="11,223,0,0"

                Name="pbFreshReadIn" VerticalAlignment="Top" Width="102"

                Background="LightGreen" Click="pbFreshReadIn_Click"/>

        <Button Content="Force Save Changes" HorizontalAlignment="Left" Margin="358,223,0,0"

                Name="pbForceSaveChanges" VerticalAlignment="Top" Width="124"

                Background="LightCoral" Click="pbForceSaveChanges_Click"/>

        <Button Content="NestedWindow" HorizontalAlignment="Left" Margin="190,239,0,0"

                Name="pbNestedWindow" VerticalAlignment="Top" Width="113"

                Click="pbNestedWindow_Click" Background="LightBlue" />

    </Grid>

</Window>

=======================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//----------------------------------

using VL15_CodeFirst_CS2.a_Views;

namespace VL15_CodeFirst_CS2

{

    public partial class MainWindow : Window

    {

        //----- fields -----

        private List<HotelReservation_full> aListHF;

        private List<Session_full> aListSF;

        private List<Registration_full> aListRF;

        //----- constructors -----

        public MainWindow()

        {

            InitializeComponent();

            this.Initialize();

            this.DisplayTestDCwindow();

        }

        //----- methods -----

        public void DisplayTestDCwindow()

        {

            TestDataContextView oTDCV = new TestDataContextView();

            oTDCV.Show();

        }

        public void Initialize()

        {

            //----- need to Create DB at the highest app level ! -----

            //----- not in the code behind the 'View's -----

            try

            {

                OurGlobals.OurCreateDB();

                //------------------------

                this.aListHF = OurData.ReturnAllSQLhotelReservationsFull(OurData.cConnect);

                this.aListRF = OurData.ReturnAllSQLregistrationsFull(OurData.cConnect);

                this.aListSF = OurData.ReturnAllSQLsessionsFull(OurData.cConnect);

                this.txblkMessageM.Text = "New DB created, and 3 tables filled.";

            }

            catch(SystemException oEX)

            {

                MessageBox.Show(oEX.Message,"my Error HIGHest! :");

            }

        }

        //----- event handlers -----

        private void pbRegistration_Click(object sender, RoutedEventArgs e)

        {

            RegistrationsView oRV = new RegistrationsView(this.aListRF);

            oRV.Show();

        }

        private void pbSessions_Click(object sender, RoutedEventArgs e)

        {

            SessionsView oSV = new SessionsView(this.aListSF);

            oSV.Show();

        }

        private void pbHotelReservations_Click(object sender, RoutedEventArgs e)

        {

            HotelReservationsView oHRV = new HotelReservationsView(aListHF);

            oHRV.Show();

        }

    }

}

=======================================================================================

<Window x:Class="VL15_CodeFirst_CS2.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Code First - C# app two :" Height="350" Width="525"

        Background="Beige">

    <Grid>

        <Button Content="Registrations" HorizontalAlignment="Left" Margin="50,44,0,0"

                Name="pbRegistration" VerticalAlignment="Top" Width="103"

                Click="pbRegistration_Click" Background="LightCoral"/>

        <Button Content="Sessions" HorizontalAlignment="Left" Margin="50,74,0,0"

                Name="pbSessions" VerticalAlignment="Top" Width="103"

                Click="pbSessions_Click" Background="LightGreen"/>

        <Button Content="Hotel Reservations" HorizontalAlignment="Left" Margin="50,104,0,0"

                Name="pbHotelReservations" VerticalAlignment="Top" Width="152"

                Click="pbHotelReservations_Click" Background="LightBlue"/>

        <TextBlock Name="txblkMessageM" HorizontalAlignment="Left" Margin="10,151,0,0" TextWrapping="Wrap"

                   Text=".. will change .." VerticalAlignment="Top" Height="27" Width="192"/>

    </Grid>

</Window>

=======================================================================================

//----- DataBasesAndTables.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS2

{

    public class OurGlobals

    {

        public static void OurCreateDB()

        {

            try

            {

                VL15_demo db = new VL15_demo(OurData.cConnect);

                if (db.DatabaseExists())

                { db.DeleteDatabase(); }

                //-----------------------------------------------

                OurGlobals.CreateDatabase();

                OurData.FillTableWithBunchRegistrationsFull();

                OurData.FillTableWithBunchSessionsFull();

                OurData.FillTableWithBunchHotelReservationsFull();

            }

            catch (SystemException oEX)

            {

                MessageBox.Show(oEX.Message,"my Errors :");

            }

        }

        //=========================================================

        public static string CreateDatabase()

        {

            VL15_demo db = new VL15_demo(OurData.cConnect);

            if (db.DatabaseExists())

            {

                string cMessage = "Deleting old database...\n";

                cMessage += "now we have THREE tables ...";

                db.DeleteDatabase();

                return cMessage;

            }

            db.CreateDatabase();

            return "database made / re-made ....";

        }

    }

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    //=========================================================

    [Database(Name = "Our_VL15_DB1")]

    public class VL15_demo : DataContext

    {

        public Table<Registration> Registrations;

        public Table<Session> Sessions;

        public Table<HotelReservation> HotelReservations;

        public VL15_demo(string connection) : base(connection)

        {

        }

    }

    //=========================================================

    [Table(Name = "Registrations")]

    public class Registration

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int RegistrationID { get; set; }

        [Column]

        public string Firstname { get; set; }

        [Column]

        public string Lastname { get; set; }

        [Column]

        public string Country { get; set; }

        [Column]

        public string Company { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<double> Cost { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<Boolean> HasPaid { get; set; }

        //----- Constructors -----

        public Registration() { }

        public Registration(string cF, string cL, string cCT, string cCP,

                Nullable<double> nC, Nullable<Boolean> lHP)

        {

            this.Firstname = cF;

            this.Lastname = cL;

            this.Country = cCT;

            this.Company = cCP;

            this.Cost = nC;

            this.HasPaid = lHP;

        }

    }

    //=========================================================

    [Table(Name = "Sessions")]

    public class Session

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int SessionID { get; set; }

        [Column]

        public string Title { get; set; }

        [Column]

        public string Resume { get; set; }

        [Column]

        public string Speaker { get; set; }

        [Column]

        public string Language { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<DateTime> StartDateTime { get; set; }

        [Column]

        public Boolean Repeat { get; set; }

        [Column(Name="RoomNo")]

        public int RoomNumber { get; set; }

        //----- Constructors -----

        public Session() { }

        public Session(string cT, string cR, string cS, string cL, Nullable<DateTime> dtSDT, Boolean lR, int nRN)

        {

            this.Title = cT;

            this.Resume = cR;

            this.Speaker = cS;

            this.Language = cL;

            this.StartDateTime = dtSDT;

            this.Repeat = lR;

            this.RoomNumber = nRN;

        }

    }

    //=========================================================

    [Table(Name = "HotelReservations")]

    public class HotelReservation

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int ReservationID { get; set; }

        [Column]

        public int RegistrationID { get; set; }

        [Column]

        public string BookingName { get; set; }

        [Column]

        public int NoOfNights { get; set; }

        [Column(CanBeNull=true, Name="RoomNum")]

        public Nullable<int> Room { get; set; }

        [Column]

        public FoodPreference eFood { get; set; }

        [Column]

        public HotelAccommodation eHotel { get; set; }

        [Column]

        public TransportMode eTrans { get; set; }

        //----- Constructors -----

        public HotelReservation() { }

        public HotelReservation(int nR, string cBN, int nN, Nullable<int> nRM,

                FoodPreference eF, HotelAccommodation eH, TransportMode eT)

        {

            this.RegistrationID = nR;

            this.BookingName = cBN;

            this.NoOfNights = nN;

            this.Room = nRM;

            this.eFood = eF;

            this.eHotel = eH;

            this.eTrans = eT;

        }

    }

    //=========================================================

}

=======================================================================================

=======================================================================================

=======================================================================================

=======================================================================================

=======================================================================================

=======================================================================================

=======================================================================================

PHH - 27th. February 2015.


Improving the 'Second' example - better binding

For the moment, lets stick with "Linq to SQL" (L2S) in our Conference example.

Lets focus on a main issue, that of getting our "Views / ViewModels / Models" created and

structured correctly.

We wish to make each data coupling a single one to each View. So we will need a ViewModel

designed for each View, with suitable public properties.

PHH - 29th. December 2014 & 26th. February 2015.


General - handling 'change notification' and Table creation

PHH - 29th. December 2014.


LINQ - to query the SQL database

LINQ is a technology from Microsoft, and it is to be found in the C# compiler (and no doubt VB.net as well).

At the moment LINQ is not fully implemented in Vulcan.NET, although some of the necessary precursors are

apparently in place.

We can use a 'thin' Data Layer in C# (class library) to allow us VN3 guys to still write our preferred syntax ;-0)

In which case our Vulcan.NET code calls on LINQ related classes in the C# library.

In the child section from here we will examine Vulcan using LINQ in more detail. For now, lets first look at an

example of a simple SQL query statement which is being sent to the SQL Server directly from Management

Studio - the Microsoft tool.

Check this out below :-

=================================================================================

The line of text (characters) making up the query is seen in full below - check it carefully :-

"SELECT TOP 1000 [CustID],[Name],[Address] FROM [c:\Users\ourDvds13A.mdf].[dbo].[DVD_Customer]"

*** Remember *** we can put square brackets around any groups of character we wish to keep together.

Here is the returned data set for the query :-

===============================================

Instead of using the Customer related table, lets now use the 'Sale' related table :-

================================================================================

The query looks like the text string below :-

"SELECT TOP 1000 [DVD_SaleId],[DVD_SalesPerson],[DVD_SaleWhenMade] FROM [c:\Users\ourDvds13A.mdf].[dbo].[DVD_Sale]"

Lets now move on to the same sort of query created and sent by LINQ technology, from within our compiled

and syntax check code - study the following details :-

========================================================================================================

Effectively lines 66 - 68 are the query itself, the rest is just Entity Framework, or LINQ to SQL.

LINQ to SQL is a simpler (and earlier) form of EF, in that only separate Tables can be used as the 'entity' and

also the Server is limited to that of Microsoft.

EF6 as it is currently, is much more powerful and flexible than the earlier LINQ to SQL, even though this can be

quite useful to us.

Let us now more on a step or two, and see just how easy it is to write-back edited data into the existing

database - check out the following details, very thoroughly :-

=====================================================================================================

Basically, in the above code, we supply a collection of 'Customer' objects to EF and ask the EF system to

insert all changes from the collection provided to the specific rows already existing or otherwise.

For any guys have done some basic SQL stuff this is an 'amazing' simplicity, and one of a few that will

cause me never to go back to the ADO.NET way of doing 'all things SQL'.

Short Summary :

By using LINQ technology we can bring all our previous query statements from external strings into .NET

code and have our code 'syntax checked' at compile time.

It also means we do all our development work on the .NET side of things, so we don't have to fight or

wrestle with different (and extra) data types.

Even our creation of DB and Tables can be done neatly from code and business classes.

So even without Vulcan support for LINQ, the benefits are too good for me NOT to use LINQ with C# and

all collections of business / custom types.

YES ! - LINQ is for querying any and all collections, even those in memory.

PHH - 9th. & 27th. December 2014.


Vulcan and LINQ

==============================================

==============================================

=============================================

========================================================================================================

==========================================================

===================================================================================================================

=========================================================================================

Querying any Collection with LINQ :

PHH - 27th. & 30th. December 2014.


'Code First' - with 'Linq to SQL' and 'EF6'

To anyone having done a reasonable amount of SQL stuff, the idea of doing everything in .NET code

seems utterly amazing !

I am sure that like me you have gotten tired and fed up of 'query' long strings which are meaningless to

the .NET compiler (mostly C#) and which can go wrong at runtime.

Now we can do a lot in .NET code, the whole thing in fact, without even opening Management Studio.

Yes, even defining the DB itself, and the Tables of which it comprises - all done in .NET code. I will use C#

until we have the facility within VN3 or VN4.

[ .. if it were a matter of just using a 'Framework', then we could do that in VN3 .. ]

So before we study the Database (DB) code class, lets study a typical Table class - checkout below :-

===================================================================================================

In the above code, each of the public properties will become a 'column' in the SQL database Table.

Sometimes we only need the attribute '[Column]' on its own - see another example below :-

=========================================================

And sometimes (most useful) we need to be able to specify that a column value (and hence the public property

as well) can be 'Null' - below are two suitable examples, check them out :-

===================================================================

We can make most standard System types 'Nullable' - and details in both the attribute and the public

property specification need to work together correctly - for example, if it can't be Null then why use a

'Nullable' type !?

Please also be VERY much aware that we always need to supply an 'empty' constructor - check below :-

===========================================================================

And then we get a second error box - check below :-

======================================================================

So we must provide a parameterless constructor for any Table class we design and create.

For any partly experienced .NET developer this may be obvious, or just plain common sense!?

There will be times (behind the scenes) when the compiler / runtime engine etc. needs to instantiate

a member of the Table class being defined, and when it does not have any parameters immediately

at hand.

Lets now move on to see the overall 'form' of the little class which defines the Database (DB) itself.

Check out the details seen in the following image :-

=============================================================================

As you can see above, this DB class (inheriting from the EF 'DataContext' class) has three

public properties, each of which will define a Table which is created at runtime.

Checkout the following details - in the next two images :-

=============================================================================================

And also the detail of what 'DataContext' is :-

==========================================================================================================

Lets move on and get some results ...............

Now that we know that our new DB will have three new Tables, lets see what we get in the

Management Studio pane when we have run our application which generates the "Code First"

database :-

===============================================

Yes, above we see three tables all with names defined in the attribute 'Name' section

of the Table attributes - see below lines 41, 56, and 78, for a checkout :-

=======================================================

For some reason the Database name is not created as 'OurDBname' but instead comes

from the file connection we specify.

==============================================================================

The above code and text string is used when the application creates the new Database.

Here is a "Script Database as ... Create to ..." the same DB from the MS (Management Studio) :-

===============================================================================================================

Notice that 'OurDBname' is not to be seen anywhere in the MS generated script !? yet this was supplied as the

'Name' attribute in our .NET code supplied for 'Code First'.

However, in the script seen above we do see the file and folder string used plenty of times.

Lets now move on .............

We do now need to examine the code for the Database creation - where the DB and the whole set of Tables

are created.

Study the following image code in thorough detail :-

============================================================================================

Obviously, code lines 41 through 50 are where it all takes place, after lines 45 actually creates the DB

with its Tables.

Lines 46/47 populates the Customer Table rows and then reads back the data from them into an in-memory collection.

Lines 49/50 does the same population and read-back for the 'Sales' table.

If we have more tables then we would need more support methods to be used, say for example, for Orders and

Products etc..

Lets now un-wrap the 'CreateDatabase' method which we made for ourselves :-

[ .. notice that we have called a few methods (members) of the 'DataContext' class .. ]

===============================================================================

And here is a short sample of the details of a few of these methods from the Help Viewer 2.0 information :-

==================================================================================================

We have used three of the above methods explicitly, and the fourth one 'Dispose' will get called by the

system as our code is executed.

We will see other very useful DataContext methods later,

========================================================

PHH - 9th. December 2014.


Chapter 14 - LINQ, 'Code First', 'Linq to SQL', and Entity Framework

'ORM' - "Object-Relational Mapping"

"ORM is an abstraction, and like any abstraction it makes life easier for us all."

For us this can be put as follows :-

'ORM' is a technique for converting data (via mapping) from a relational database to an object class in our .NET code.

The software tools in a supporting Framework allow us to use just the data types of the .NET side of things, with

which we should be VERY familiar, on a day to day basis.

Usually there is a fair amount of 'type miss-match' between the sides of the mapping.

So the quite different types of SQL Server can be handled by 'Linq to SQL' and 'Linq to Entity' libraries

(called Entity Frameworks) and then all we as developers need do is use and code with the .NET types.

This in itself is a great step forward ;-0)

Lets now think of how this larger topic developed over time.

Thinking of the Historical 'sequence' involved :

PHH - 31st. December 2014.


Connections - Server and Database

Okay then guys, I will be honest with you, this is definitely one of the "Thorny" sides to using SQL databases.

Making a working connection from code to Server and Database has never been easy ;-0((

In fact I would suggest that many people have wasted hours and hours of their time trying to get a connection

to work for them - I am no exception !!

However, Microsoft seem to have been aware of this and allow both "LINQ to SQL" and "LINQ to Entity" to be

able to be used without having to supply either anything or 'anything much'.

We can get both of these technologies to work for us while still focusing on the code we write as well as only

.NET objects, and our business logic.

Once we can make a connection we can easily create a database using 'CodeFirst'.

Now then, having said how easy it is to make a connection and get into 'data', we also need to realise that when

it comes to runtime, and customer hardware platforms, we do need to be able to control which Server we use and

where our database is stored.

Oh! and of course we may wish to use multiple servers and multiple databases as well.

Lets now make a step or two in the right direction ...................

"LINQ to SQL" technology :

We can't supply no information to the L2S technology - here is the simplest way I have found :-

================================================================

It would appear that we at least need to provide a 'Filepath' - that is a file name along with an existing folder.

Also the folder needs to be accessible for R/W activity, so 'Temp' is probably the safest to try.

And here shown below, are a few other string for connection when a 'DataContext' object is initiated :-

=========================================================================================================================================

Notice in the image seen above that we can actually supply a string which starts to get very similar

in appearance to what we SQL folks call a 'Connection String'.

We will see later if we can use a 'string builder' approach.

First, let us examine our sub-classed 'DataContext' class (VL15_demo) and its associated Constructor :-

==========================================================================

We see that the string is passed 'through' to the Super class, as we call it in Vulcan.

And now we need to see the results of such code when we have built and run the application as few times.

Note also the we must have changed the 'Filepath' string in order to produce the results we see :-

================================================================================================================================================

And when we attach one of the above files to the Server selected in Management Studio we see

the following image on screen :-

[ .. note the server is SQLEXPRESS .. ]

============================================================

Yes, we see the correct three Tables built from our .NET entity classes.

And when we examine one of the Tables we see column data like our hard-coded details - first

we must view the SSOE pane in our VS 2013 shell :-

=================================================================

Notice that 'View Data' is a different option to what we see in Management Studio.

Here is the data :-

===============================================================================================================

Okay then folks, so good, so far ;-0))

But what about us trying to to use the much more convenient string builder class, specially designed

to do the job for us - as well as it being configurable at run time, as it can be built by our running code ?

Here is what Help Viewer says about the class :-

=============================================================================================================================================================================

Yep! - so we need the correct namespace !

Here is what we require ...............

==============================================================

And so this is what I added in the directives section of our code :-

===========================================================

And now we can get some experience of defining our new string builder object - check below :-

[ .. note the same details are used as we had tried previously .. ]

================================================================================================

And in case you may not believe me, here is some visual proof that the connection string 'stuff'

actually works for us :-

=========================================================================

Time to move on, enough success for the moment ;-0)

"LINQ to Entity" technology :

This L2E technology is more complex in many ways, to that of L2S.

The 'DbContext' class does a whole set of different things to 'DataContext' it would seem, when it

comes to creating a SQL database with 'CodeFirst' technology.

Before we start to explore in detail just what we as developers need do with 'DbContext', we need to

see and read what "Help Viewer 2.1" has to say on the matter - check out below :-

================================================================================================================================

Since we are now living in a world where version 6 has been publicly released, and version 7 talked of in the web articles,

we are going to ignore earlier versions to 6.

Here is some more information about a possible connection :-

====================================================================================================================================================

So then guys, how does the above information affect what we do in our code ?

Well, if we wish to to as little as possible then we can instantiate one of our Conference 'DbContext' objects

with zero input parameters to the Constructor - check below :-

==========================================

This will then use the first of the Constructors shown below :-

==========================================================================================================

The result of us supplying virtually NOTHING is that 'L2E' does it all for us !

Since we have not supplied information of server or database name etc., etc, it finds a suitable server

and creates its own name from the solution titles.

In the following image we see details of the connection string automatically created by the DbContext class

when we supply no input data values - check carefully below :-

======================================================================================

You will see above that the 'Initial Catalog' is suitable complex ;-0)

Okay then folks, lets move on to us trying to supply a suitable connection string of our own, and

then passing that as input to another overload of the DbContext constructor in our sub-class - check below thoroughly :-

================================================================================================================================================

Notice that I have purposefully shortened the "Initial Catalog" string in the above image.

Line 40 above is where we use the second Constructor overload.

So what is the result of running the application and creating a new database ?

Well, we need to look in the right place it would seem -

===============================================================================================================================================

Look at the folder path in the images above and below :-

=======================================================================================

Yes, the new MDF file is deep within the Microsoft application folder structure.

It may also interest you to see what we get when we try to add disk and folder detail to the filename of the

initial catalog in our connection string - check below :-

===========================================================================================================================

Above we see that "C:\Temp\ourEF6conf_13" has been changed to one filename of "c__temp_ourEF6conf_13.mdf".

This was not what I was after when I tried things out, I was wishing to place the data file in the "C:\Temp" folder.

Now I have cleaned out the 'deep' folder as seen below :-

===============================================================================================================================

Okay then, we obviously need to find out more about creating our DB where we wish it to be ;-0)

But lets not stop our learning, let us now move on to seeing how to use a String Builder class to aid our coding approach.

Read these details as a starter to our learning :-

==========================================================================================================================================

So why don't we give this a go, and use the values of the connection sting parameters that we already

know to work for us - before we try and make any new changes.

Checkout the next image carefully :-

=================================================================================

Yes, in the above image line 55 is where we use our concatenated string values.

And since I came across an alternative syntax, the following image details shows how to use this

when we supply the attribute / property values - check out in detail below :-

=========================================================================================================================================

Yes, things still working for us !

So here below is a direct comparison of the two syntaxes :-

===============================================================================================

And now finally, below is the extracted detail from the Help Viewer 2.1 notes - just the two overloads we

have used above, and a few useful notes on important properties - check these now :-

=====================================================================================================================================================

Okay then, all is well except that we don't seem as yet to be able to create our new EF6 '.mdf' file where we

would wish to place it.

I have tried heaps of ways and still failed - I will keep trying ;-0))

PHH - 2nd. & 3rd. & 5th. March 2015.


LINQ

Do NOT panic about LINQ !

Below is a URL / live link, to my eNotes after many days of work in researching LINQ.

http://www.winclickstartvulcan2.net/WebNotes/ClickStartLINQ/ClickStartLINQ.html

Here is the contents page of the eNote volume :- (not all sections are full filled !)

===========================================================

If you go about learning it (LINQ) in the right way it will become easy, and a good friend to you.

It took me longer than usual to get to grips with it, simply because there is not a lot of good material

out there to study. On top of that, there is also a lot of confusing and even wrong stuff out there.

And on top of all of the above, the whole topic is an Historic one in many ways, meaning that new stuff

was being released after eBooks and articles were written, which changed the position of the Goal post etc., etc..

So some early stuff is now not much use, or wrong, and has 'holes' in it, as well as necessary content missing.

[ .. so be warned, and use my eNotes whenever you can .. it took me ages to get rid of the rubbish .. ]

LINQ is a Microsoft technology - it is built into the C# and VB.net compilers.

LINQ allows the developer to query in .NET code any 'Collection'.

So LINQ is not about SQL, but is a way of querying any collection.

Remember a 'Collection' is a list of items, where the item is typically a more complex data object

like a 'Customer', or 'SalesOrder'. The item may be simpler, but not commonly.

Although we use LINQ with 'Code First', 'Linq to SQL', and 'Entity Framework', the related data is

'effectively' first made into a collection of items. or certainly that is how the code can be read by us.

We can use LINQ to query 'in-memory' collections - which have never ever been stored in a back-end Data Source.

Once you get used to using LINQ you will never wish to return to the old ways ;-)

At the moment LINQ is only available to me in C# and not as yet in VN3. Maybe we will get it in VN4.

There are simple ways around LINQ not being built into the Vulcan compiler.

Try to use code for as much of your LINQ querying as possible, Microsoft recommend this, and say to keep away

from using Lambda Expressions directly.

This is an example of a Lambda Expression (Yuk!) :-

================================================================================================================================================

==========================================================================================================================

Unfortunately, there is a huge amount of stuff out there written with Lambda Expressions. There are even a few

confusing books and eBooks that should be much better. I know, I struggled through them and found (eventually)

better ways in code, to be able to do just about everything 'query wise'.

Lets see some example LINQ, so that we can understand some of the points made above.

Doing some Code Experiments ('Linq to Objects') :

Okay guys, lets start with some of my earlier code, where we construct a collection directly from hard coded information.

When we query and existing in-memory object we say we are using 'Linq to Objects'.

Here is the data and listed collection :-

==========================================================================================================

So now we can use this to make our own first simple query on an in-memory collection.

Check out carefully the following image code :-

======================================================================================================

In the above image we see code on lines 35 through 38 which query our in-memory list (collection),

and the resulting list has its item 'Count' property displayed.

The above code is being run at application launch time - so the message box is actually 'live'.

And if you check the original data you will be able to see that the result of a slightly more complex

query is a single item in the returned collection - check this out :-

============================================================================================================

LINQ query code is similar to SQL string querying via the Server, simply because its style is also one of 'description'

and not 'Procedural'.

This means we talk and write in terms of the data problem, and NOT in the way the computer goes about finding

the answers.

The above LINQ query can be read as find and place in a list all the Registration items where the person has paid.

If you are a SQL Server user you will definitely know that we never worry at all as to what the Server is actually

doing, or most times how it goes about finding our results set - that's for the SQL engine to sort out and worry about ;-)

Joins - Customer / Contacts :

====================================================================================================================================================================================================================

=======================================================================================

====================================================================================

===================================

Joins (Outer) - Products with No Sales :

==============================================================================================================

========================================================================================

Joins (Outer) - Customers with No Orders :

=====================================================================================================================================================================================================

==================================================================================

Many Joins - Many, Many Tables - the more the merrier !? :

Lets join three tables together to get their combined long rows - we will use Order, OrderItem,

and Product.

Check out this code in the following image :-

[ .. three Tables and Two Joins .. ]

=======================================================================================

=========================================================================================================================================

PHH - 31st. December 2014.


Grouping, and Compound Querying

I have found that there are two very important sides to LINQ, and these are 'Compound Querying'

as well as 'Grouping'.

Personally, I found it hard to come across enough clear examples of 'Grouping' to make it as easy

as it should have been - to learn the full details that is.

I would like to share a couple of my working examples with you - start with Ben's engineering project below :-

================================================================================================================================================================

In the above image checkout the 5 lines of the 'query' statement.

Basically, we are making a listing of time stamps where the set of similar TS's is greater than zero.

The list is shown in the simple GUI table with the scroll-bar.

We will see better and more clear examples as we move through this section.

======================================================================================================================================================

======================================================================================================

=============================================================================================================================================

=============================================================================================================

========================================================================================================================================

===============================================================================================

PHH - 31st. December 2014.


Vulcan and LINQ

Simply put, it just does not exist as yet.

Also simply out, I can't work and code, and develop apps without LINQ, it is that good.

So the best way out seems to me to use a C# class library to handle any LINQ stuff, and

then call the classes and any members of those classes, from the Vulcan business logic we

can then write using Vulcan.NET.

I call this 'using a thin data layer'.

PHH - 31st. December 2014.


'Code First'

PHH - 31st. December 2014.


Vulcan and 'Code First'

PHH - 31st. December 2014.


'Database First'

PHH - 27th. & 31st. December 2014.


Vulcan and 'Database First'

PHH - 1st. January 2014.


'Linq to SQL'

PHH - 31st. December 2014.


Vulcan and 'Linq to SQL'

PHH - 1st. January 2014.


'Entity Framework' - 'LINQ to Entity'

PHH - 31st. December 2014.


Vulcan and 'Entity Framework 6+'

PHH - 31st. December 2014.


'Tracking' changes - 'L2S' and 'L2E'

*** Note *** Although tracking can be turned off, and some would say to optimize performance, I strongly suggest

that we learn to plan our coding style so that we leave it on as a normal procedure.

We would be much better advised (in my opinion) to select and return far fewer SQL table records, and keep tracking

on, that return piles of records from the SQL DB and turn tracking off.

Remember, the whole point of a SQL back-end data source is to keep all the data there - not transfer it to a front-end

application which holds too much data in memory.

With this in mind .............

===================================================================================

One BIG benefit of using the .NET technologies of 'LINQ to SQL' and 'LINQ to Entity' is that we have 'changes

tracking' of our data done for us automatically. That's a BIG relief !!!

If we do things right, we can work on our data (either by GUI interaction or code directly) and then make

an easy call to save the changes, on the 'DataContext' or 'DbContext' object we have been using.

We need to remember that L2S is a simpler form of L2E, where classes can be only mapped as '.NET class

of object' to one single SQL Table.

With L2E we can have more complex mappings from .NET object to multiple SQL Tables.

Lets us take time to examine the two technologies separately - as far as their tracking of changes is concerned.

First the 'L2S' technology :

Here is what "HelpViewer 2.0" has to say about 'Tracking' :-

===========================================================================================================

Looks like we need to find out what a unit of work is ;-0))

So far in my eNotes I have used only one Constructor overload - that seen below :-

=========================================================================================================

And here is my hard coded static property as the 'string' :-

============================================================

Before we can use out string to instantiate a DataContext object we need to see just what our newly

define DataContext (sub-classed) type looks like - study the following :-

=========================================================================

Yep! - we will have three Tables to test and trial.

Now we can instantiate as seen below in line 52 :-

======================================================================

So far so good .............

However, we now need to study all the members we have available to us on the 'db' object shown above.

Check these out carefully, and look for familiar names of members :-

==================================================================================================================================================

Yep! - some we recognise ................

Notice that we can apparently turn off/on 'ObjectTracking' - we need to find out more !

We may need to try out a few of these to get a better idea of what can be done ;-0)

*** NOTE *** the child section form here called "Checking out 'Connection' is useful reading and

topic 'study' !

Lets now see how we can instantiate a 'DataContext' object and then send a handful of items to

a SQL Table to become a handful of rows.

Notice below line 110 and 111 in particular :-

============================================================================================

We can track changes only as long as the 'db' object is in existence, and in scope.

Once we create another one (recreate, with the same name) then all change details will be lost.

For this reason we need to plan our scoping VERY carefully, if we wish to hold on to our changes

and tracking information. More of this later.

In the above Entity code, notice that the way we force the tracked changes to be saved is via a

call to the 'SubmitChanges' method. [ .. in L2E this changes to 'SaveChanges' .. ]

Okay then folks, we need to see the details of the STATIC member which returns the hard-coded collection :-

==================================================================================================================================

A typed List and/or an 'ObservableCollection' can be used for this purpose.

The Importance of 'Scoping Correctly', for Tracking to Work for us :

In the following image we see data in a bound collection to a 'DataGrid' element, where new records

have been added as well as original cell contents edited.

========================================================================================

When we click the green button all the changes should be sent back to the SQL database.

Before we look at saving changes, lets focus our attention on how the above Registration 'view' is

displayed on screen - check this out :-

=======================================================================================

Notice that we are passing in an input parameter of an application wide DataContext object called 'dbApp'.

This can bee seen in full detail within the 'MainWindow' calling code shown below :-

[ .. note 'dbApp' is used to create the SQL database, as well as launch the Registration screen .. ]

========================================================================================================

We should be well aware that events and event handlers will turn into Commands and the like in an MVVM framework!

However, for the moment they are quite helpful while we are doing some simple testing and trialling work.

And now below we can see the .NET code for the 'RegistrationsView' and see how the Constructor accepts the

DataContext parameter and then assigns it to 'dbMine' - check below for details :-

======================================================================================================

===============================================================================================================================

==========================================================================================================

=========================================================================================

================================================================================================

More Scoping - Multiple 'DataContext' objects :

==================================================================================================

============================================================================================================================================================

============================================================================================

Doing some (more) Suitable Tests :

============================================================================================

======================================================

===========================================================================================

=========================================================================================

==========================================================================================================================================

=============================================================================================

PHH - 1st. March 2015.


working script and code

=======================================================

======================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//----------------------------------

using VL15_CodeFirst_CS2.a_Views;

namespace VL15_CodeFirst_CS2

{

    public partial class MainWindow : Window

    {

        //----- fields (none) -----

        //----- application wide scope for tracking -----

        private VL15_demo dbApp;

        //----- constructors -----

        public MainWindow()

        {

            InitializeComponent();

            this.Initialize();

        }

        //----- methods -----

        public void Initialize()

        {

            try

            {

                this.dbApp = new VL15_demo(OurData.cConnect);

                OurGlobals.OurCreateDB(this.dbApp);

                //------------------------

                this.txblkMessageM.Text = "New scoping of the DataContext object ....";

            }

            catch(SystemException oEX)

            {

                MessageBox.Show(oEX.Message,"my Error HIGHest! :");

            }

        }

        //----- event handlers -----

        private void pbRegistration_Click(object sender, RoutedEventArgs e)

        {

            RegistrationsView oRV = new RegistrationsView(this.dbApp);

            oRV.Show();

        }

        private void pbSessions_Click(object sender, RoutedEventArgs e)

        {

            SessionsView oSV = new SessionsView(this.dbApp);

            oSV.Show();

        }

        private void pbHotelReservations_Click(object sender, RoutedEventArgs e)

        {

            HotelReservationsView oHRV = new HotelReservationsView(this.dbApp);

            oHRV.Show();

        }

    }

}

======================================================================================

<Window x:Class="VL15_CodeFirst_CS2.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Code First - C# app two :" Height="350" Width="525"

        Background="Beige">

    <Grid>

        <Button Content="Registrations" HorizontalAlignment="Left" Margin="50,44,0,0"

                Name="pbRegistration" VerticalAlignment="Top" Width="103"

                Click="pbRegistration_Click" Background="LightCoral"/>

        <Button Content="Sessions" HorizontalAlignment="Left" Margin="50,74,0,0"

                Name="pbSessions" VerticalAlignment="Top" Width="103"

                Click="pbSessions_Click" Background="LightGreen"/>

        <Button Content="Hotel Reservations" HorizontalAlignment="Left" Margin="50,104,0,0"

                Name="pbHotelReservations" VerticalAlignment="Top" Width="152"

                Click="pbHotelReservations_Click" Background="LightBlue"/>

        <TextBlock Name="txblkMessageM" HorizontalAlignment="Left" Margin="10,151,0,0" TextWrapping="Wrap"

                   Text=".. will change .." VerticalAlignment="Top" Height="27" Width="327"/>

    </Grid>

</Window>

======================================================================================

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Threading.Tasks;

using System.Windows;

namespace VL15_CodeFirst_CS2

{

    /// <summary>

    /// Interaction logic for App.xaml

    /// </summary>

    public partial class App : Application

    {

    }

}

======================================================================================

<Application x:Class="VL15_CodeFirst_CS2.App"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             StartupUri="MainWindow.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

======================================================================================

//----- MyEnums.prg -----

//----- PHH - 1th. December 2014. -----

using System;

namespace VL15_CodeFirst_CS2{

    public enum FoodPreference

    {

        Vegan,

        Vegetarian,

        Carnivore,

        FishOnly,

        NoneAsYet,

    }

    public enum HotelAccommodation

    {

        Single,

        Double,

        Suite,

        None,

        NoneAsYet,

    }

    public enum TransportMode

    {

        Bicycle,

        Motorbike,

        Coach,

        Train,

        Metro,

        Airplane,

        None,

        NoneAsYet,

    }

}

======================================================================================

//----- DataBasesAndTables.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS2

{

    public class OurGlobals

    {

        //public static void OurCreateDB()

        //{

        //    try

        //    {

        //        VL15_demo db = new VL15_demo(OurData.cConnect);

        //        if (db.DatabaseExists())

        //        { db.DeleteDatabase(); }

        //        //-----------------------------------------------

        //        OurGlobals.CreateDatabase(db);

        //        OurData.FillTableWithBunchRegistrationsFull(db);

        //        OurData.FillTableWithBunchSessionsFull(db);

        //        OurData.FillTableWithBunchHotelReservationsFull(db);

        //    }

        //    catch (SystemException oEX)

        //    {

        //        MessageBox.Show(oEX.Message,"my Errors :");

        //    }

        //}

        public static void OurCreateDB(VL15_demo db)

        {

            try

            {

                if (db.DatabaseExists())

                { db.DeleteDatabase(); }

                //-----------------------------------------------

                OurGlobals.CreateDatabase(db);

                OurData.FillTableWithBunchRegistrationsFull(db);

                OurData.FillTableWithBunchSessionsFull(db);

                OurData.FillTableWithBunchHotelReservationsFull(db);

            }

            catch (SystemException oEX)

            {

                MessageBox.Show(oEX.Message,"my Errors :");

            }

        }

        //=========================================================

        public static string CreateDatabase(VL15_demo db)

        {

            if (db.DatabaseExists())

            {

                string cMessage = "Deleting old database...\n";

                cMessage += "now we have THREE tables ...";

                db.DeleteDatabase();

                return cMessage;

            }

            db.CreateDatabase();

            return "database made / re-made ....";

        }

    }

    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    //=========================================================

    [Database(Name = "Our_VL15_DB1")]

    public class VL15_demo : DataContext

    {

        public Table<Registration> Registrations;

        public Table<Session> Sessions;

        public Table<HotelReservation> HotelReservations;

        public VL15_demo(string connection) : base(connection)

        {

        }

    }

    //=========================================================

    [Table(Name = "Registrations")]

    public class Registration

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int RegistrationID { get; set; }

        [Column]

        public string Firstname { get; set; }

        [Column]

        public string Lastname { get; set; }

        [Column]

        public string Country { get; set; }

        [Column]

        public string Company { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<double> Cost { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<Boolean> HasPaid { get; set; }

        //----- Constructors -----

        public Registration() { }

        public Registration(string cF, string cL, string cCT, string cCP,

                Nullable<double> nC, Nullable<Boolean> lHP)

        {

            this.Firstname = cF;

            this.Lastname = cL;

            this.Country = cCT;

            this.Company = cCP;

            this.Cost = nC;

            this.HasPaid = lHP;

        }

    }

    //=========================================================

    [Table(Name = "Sessions")]

    public class Session

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int SessionID { get; set; }

        [Column]

        public string Title { get; set; }

        [Column]

        public string Resume { get; set; }

        [Column]

        public string Speaker { get; set; }

        [Column]

        public string Language { get; set; }

        [Column(CanBeNull=true)]

        public Nullable<DateTime> StartDateTime { get; set; }

        [Column]

        public Boolean Repeat { get; set; }

        [Column(Name="RoomNo")]

        public int RoomNumber { get; set; }

        //----- Constructors -----

        public Session() { }

        public Session(string cT, string cR, string cS, string cL, Nullable<DateTime> dtSDT, Boolean lR, int nRN)

        {

            this.Title = cT;

            this.Resume = cR;

            this.Speaker = cS;

            this.Language = cL;

            this.StartDateTime = dtSDT;

            this.Repeat = lR;

            this.RoomNumber = nRN;

        }

    }

    //=========================================================

    [Table(Name = "HotelReservations")]

    public class HotelReservation

    {

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int ReservationID { get; set; }

        [Column]

        public int RegistrationID { get; set; }

        [Column]

        public string BookingName { get; set; }

        [Column]

        public int NoOfNights { get; set; }

        [Column(CanBeNull=true, Name="RoomNum")]

        public Nullable<int> Room { get; set; }

        [Column]

        public FoodPreference eFood { get; set; }

        [Column]

        public HotelAccommodation eHotel { get; set; }

        [Column]

        public TransportMode eTrans { get; set; }

        //----- Constructors -----

        public HotelReservation() { }

        public HotelReservation(int nR, string cBN, int nN, Nullable<int> nRM,

                FoodPreference eF, HotelAccommodation eH, TransportMode eT)

        {

            this.RegistrationID = nR;

            this.BookingName = cBN;

            this.NoOfNights = nN;

            this.Room = nRM;

            this.eFood = eF;

            this.eHotel = eH;

            this.eTrans = eT;

        }

    }

    //=========================================================

}

======================================================================================

//----- Business.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

using System.Collections.ObjectModel;   //----- ObservableCollection .....

using System.ComponentModel;   //----- INotifyPropertyChanged .....

namespace VL15_CodeFirst_CS2

{

    [Table(Name = "Registrations")]

    public class Registration_full : INotifyPropertyChanged

    {

        //----- fields -----

        private int _registrationID;

        private string _firstName;

        private string _lastName;

        private string _country;

        private string _company;

        private Nullable<double> _cost;

        private Nullable<Boolean> _hasPaid;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- Constructors -----

        public Registration_full() { }

        public Registration_full(string cF, string cL, string cCT, string cCP,

                Nullable<double> nC, Nullable<Boolean> lHP)

        {

            this.FirstName = cF;

            this.LastName = cL;

            this.Country = cCT;

            this.Company = cCP;

            this.Cost = nC;

            this.HasPaid = lHP;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        //----- properties -----

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int RegistrationID

        {

            get { return _registrationID; }

            set { _registrationID = value; NotifyPropertyChanged("RegistrationID"); }

        }

        [Column]

        public string FirstName

        {

            get { return _firstName; }

            set { _firstName = value; NotifyPropertyChanged("FirstName"); }

        }

        [Column]

        public string LastName

        {

            get { return _lastName; }

            set { _lastName = value; NotifyPropertyChanged("LastName"); }

        }

        [Column]

        public string Country

        {

            get { return _country; }

            set { _country = value; NotifyPropertyChanged("Country"); }

        }

        [Column]

        public string Company

        {

            get { return _company; }

            set { _company = value; NotifyPropertyChanged("Company"); }

        }

        [Column(CanBeNull=true)]

        public Nullable<double> Cost

        {

            get { return _cost; }

            set { _cost = value; NotifyPropertyChanged("Cost"); }

        }

        [Column(CanBeNull=true)]

        public Nullable<Boolean> HasPaid

        {

            get { return _hasPaid; }

            set { _hasPaid = value; NotifyPropertyChanged("HasPaid"); }

        }

    }

    //=========================================================

    [Table(Name = "Sessions")]

    public class Session_full : INotifyPropertyChanged

    {

        //----- fields -----

        private int _sessionID;

        private string _title;

        private string _resume;

        private string _speaker;

        private string _language;

        private Nullable<DateTime> _startDateTime;

        private Boolean _repeat;

        private int _roomNumber;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- Constructors -----

        public Session_full() { }

        public Session_full(string cT, string cR, string cS, string cL,

                        Nullable<DateTime> dtSDT, Boolean lR, int nRN)

        {

            this.Title = cT;

            this.Resume = cR;

            this.Speaker = cS;

            this.Language = cL;

            this.StartDateTime = dtSDT;

            this.Repeat = lR;

            this.RoomNumber = nRN;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        //----- properties -----

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int SessionID

        {

            get { return _sessionID; }

            set { _sessionID = value; NotifyPropertyChanged("SessionID"); }

        }

        [Column]

        public string Title

        {

            get { return _title; }

            set { _title = value; NotifyPropertyChanged("Title"); }

        }

        [Column]

        public string Resume

        {

            get { return _resume; }

            set { _resume = value; NotifyPropertyChanged("Resume"); }

        }

        [Column]

        public string Speaker

        {

            get { return _speaker; }

            set { _speaker = value; NotifyPropertyChanged("Speaker"); }

        }

        [Column]

        public string Language

        {

            get { return _language; }

            set { _language = value; NotifyPropertyChanged("Language"); }

        }

        [Column(CanBeNull = true)]

        public Nullable<DateTime> StartDateTime

        {

            get { return _startDateTime; }

            set { _startDateTime = value; NotifyPropertyChanged("StartDateTime"); }

        }

        [Column]

        public Boolean Repeat

        {

            get { return _repeat; }

            set { _repeat = value; NotifyPropertyChanged("Repeat"); }

        }

        [Column(Name = "RoomNo")]

        public int RoomNumber

        {

            get { return _roomNumber; }

            set { _roomNumber = value; NotifyPropertyChanged("RoomNumber"); }

        }

    }

    //=========================================================

    [Table(Name = "HotelReservations")]

    public class HotelReservation_full : INotifyPropertyChanged

    {

        //----- fields -----

        private int _reservationID;

        private int _registrationID;

        private string _bookingName;

        private int _noOfNights;

        private Nullable<int> _room;

        private FoodPreference _eFood;

        private HotelAccommodation _eHotel;

        private TransportMode _eTrans;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- Constructors -----

        public HotelReservation_full() { }

        public HotelReservation_full(int nR, string cBN, int nN, Nullable<int> nRM,

                FoodPreference eF, HotelAccommodation eH, TransportMode eT)

        {

            this.RegistrationID = nR;

            this.BookingName = cBN;

            this.NoOfNights = nN;

            this.Room = nRM;

            this.eFood = eF;

            this.eHotel = eH;

            this.eTrans = eT;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        //----- properties -----

        [Column(IsPrimaryKey = true, IsDbGenerated = true)]

        public int ReservationID

        {

            get { return _reservationID; }

            set { _reservationID = value; NotifyPropertyChanged("ReservationID"); }

        }

        [Column]

        public int RegistrationID

        {

            get { return _registrationID; }

            set { _registrationID = value; NotifyPropertyChanged("RegistrationID"); }

        }

        [Column]

        public string BookingName

        {

            get { return _bookingName; }

            set { _bookingName = value; NotifyPropertyChanged("BookingName"); }

        }

        [Column]

        public int NoOfNights

        {

            get { return _noOfNights; }

            set { _noOfNights = value; NotifyPropertyChanged("NoOfNights"); }

        }

        [Column(CanBeNull = true, Name = "RoomNum")]

        public Nullable<int> Room

        {

            get { return _room; }

            set { _room = value; NotifyPropertyChanged("Room"); }

        }

        [Column]

        public FoodPreference eFood

        {

            get { return _eFood; }

            set { _eFood = value; NotifyPropertyChanged("eFood"); }

        }

        [Column]

        public HotelAccommodation eHotel

        {

            get { return _eHotel; }

            set { _eHotel = value; NotifyPropertyChanged("eHotel"); }

        }

        [Column]

        public TransportMode eTrans

        {

            get { return _eTrans; }

            set { _eTrans = value; NotifyPropertyChanged("eTrans"); }

        }

    }

}

======================================================================================

//----- Binding.cs -----

//----- PHH - 30th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

using System.Collections.ObjectModel;   //----- ObservableCollection .....

using System.ComponentModel;   //----- INotifyPropertyChanged .....

namespace VL15_CodeFirst_CS2

{

    public class Registration_binding : INotifyPropertyChanged

    {

        //----- fields -----

        private int _registrationID;

        private string _firstName;

        private string _lastName;

        private string _country;

        private string _company;

        private Nullable<double> _cost;

        private Nullable<Boolean> _hasPaid;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- constructors -----

        public Registration_binding() { }

        public Registration_binding(string cF, string cL, string cCT, string cCP,

                Nullable<double> nC, Nullable<Boolean> lHP)

        {

            this.FirstName = cF;

            this.LastName = cL;

            this.Country = cCT;

            this.Company = cCP;

            this.Cost = nC;

            this.HasPaid = lHP;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        //----- properties -----

        public int RegistrationID

        {

            get { return _registrationID; }

            set { _registrationID = value; NotifyPropertyChanged("RegistrationID"); }

        }

        public string FirstName

        {

            get { return _firstName; }

            set { _firstName = value; NotifyPropertyChanged("FirstName"); }

        }

        public string LastName

        {

            get { return _lastName; }

            set { _lastName = value; NotifyPropertyChanged("LastName"); }

        }

        public string Country

        {

            get { return _country; }

            set { _country = value; NotifyPropertyChanged("Country"); }

        }

        public string Company

        {

            get { return _company; }

            set { _company = value; NotifyPropertyChanged("Company"); }

        }

        public Nullable<double> Cost

        {

            get { return _cost; }

            set { _cost = value; NotifyPropertyChanged("Cost"); }

        }

        public Nullable<Boolean> HasPaid

        {

            get { return _hasPaid; }

            set { _hasPaid = value; NotifyPropertyChanged("HasPaid"); }

        }

    }

    //=========================================================

    public class Session_binding : INotifyPropertyChanged

    {

        //----- fields -----

        private int _sessionID;

        private string _title;

        private string _resume;

        private string _speaker;

        private string _language;

        private Nullable<DateTime> _startDateTime;

        private Boolean _repeat;

        private int _roomNumber;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- Constructors -----

        public Session_binding() { }

        public Session_binding(string cT, string cR, string cS, string cL, Nullable<DateTime> dtSDT, Boolean lR, int nRN)

        {

            this.Title = cT;

            this.Resume = cR;

            this.Speaker = cS;

            this.Language = cL;

            this.StartDateTime = dtSDT;

            this.Repeat = lR;

            this.RoomNumber = nRN;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        //----- properties -----

        public int SessionID

        {

            get { return _sessionID; }

            set { _sessionID = value; NotifyPropertyChanged("SessionID"); }

        }

        public string Title

        {

            get { return _title; }

            set { _title = value; NotifyPropertyChanged("Title"); }

        }

        public string Resume

        {

            get { return _resume; }

            set { _resume = value; NotifyPropertyChanged("Resume"); }

        }

        public string Speaker

        {

            get { return _speaker; }

            set { _speaker = value; NotifyPropertyChanged("Speaker"); }

        }

        public string Language

        {

            get { return _language; }

            set { _language = value; NotifyPropertyChanged("Language"); }

        }

        public Nullable<DateTime> StartDateTime

        {

            get { return _startDateTime; }

            set { _startDateTime = value; NotifyPropertyChanged("StartDateTime"); }

        }

        public Boolean Repeat

        {

            get { return _repeat; }

            set { _repeat = value; NotifyPropertyChanged("Repeat"); }

        }

        public int RoomNumber

        {

            get { return _roomNumber; }

            set { _roomNumber = value; NotifyPropertyChanged("RoomNumber"); }

        }

    }

    //=========================================================

    public class HotelReservation_binding

    {

        //----- fields -----

        private int _reservationID;

        private int _registrationID;

        private string _bookingName;

        private int _noOfNights;

        private Nullable<int> _room;

        private FoodPreference _eFood;

        private HotelAccommodation _eHotel;

        private TransportMode _eTrans;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- Constructors -----

        public HotelReservation_binding() { }

        public HotelReservation_binding(int nR, string cBN, int nN, Nullable<int> nRM,

                FoodPreference eF, HotelAccommodation eH, TransportMode eT)

        {

            this.RegistrationID = nR;

            this.BookingName = cBN;

            this.NoOfNights = nN;

            this.Room = nRM;

            this.eFood = eF;

            this.eHotel = eH;

            this.eTrans = eT;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        //----- properties -----

        public int ReservationID

        {

            get { return _reservationID; }

            set { _reservationID = value; NotifyPropertyChanged("ReservationID"); }

        }

        public int RegistrationID

        {

            get { return _registrationID; }

            set { _registrationID = value; NotifyPropertyChanged("RegistrationID"); }

        }

        public string BookingName

        {

            get { return _bookingName; }

            set { _bookingName = value; NotifyPropertyChanged("BookingName"); }

        }

        public int NoOfNights

        {

            get { return _noOfNights; }

            set { _noOfNights = value; NotifyPropertyChanged("NoOfNights"); }

        }

        public Nullable<int> Room

        {

            get { return _room; }

            set { _room = value; NotifyPropertyChanged("Room"); }

        }

        public FoodPreference eFood

        {

            get { return _eFood; }

            set { _eFood = value; NotifyPropertyChanged("eFood"); }

        }

        public HotelAccommodation eHotel

        {

            get { return _eHotel; }

            set { _eHotel = value; NotifyPropertyChanged("eHotel"); }

        }

        public TransportMode eTrans

        {

            get { return _eTrans; }

            set { _eTrans = value; NotifyPropertyChanged("eTrans"); }

        }

    }

}

======================================================================================

//----- DataToAndFromServer.cs -----

//----- PHH - 28th. December 2014. -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

//-------------------------------------------

//----- added for LINQ -----

using System.Data.SqlClient;

using System.Data.Linq.Mapping;  //----- needed for Table & Column .....

using System.Data.Linq;

using System.Data.Sql;

//==================================

using System.Collections;

namespace VL15_CodeFirst_CS2

{

    public class OurData

    {

        //----- properties -----

        public static string cConnect

        {

            get

            {

                return @"c:\Users\ourConf02.mdf";

            }

        }

        //----- CARE can get deadly embrace for 'removal' after -----

        //----- using Management Studio -----

        //----- Registration -----

        //-------------------------------------------------------------

        public static List<Registration_full> MakeBunchOfRegistrationsFull()

        {

            Nullable<double> oND = new Nullable<double>();

            Nullable<Boolean> oNB = new Nullable<Boolean>();

            //--------------------------------------------

            List<Registration_full> aList = new List<Registration_full>();

            aList.Add(new Registration_full("Dan","Logan","Romania","Super Fly",139.31, true));

            aList.Add(new Registration_full("Ben","Hepburn","Wales","Fleasy Finance", oND, oNB));

            aList.Add(new Registration_full("Willie","Moore","USA","ATnT",235.79, false));

            return aList;

        }

        public static void FillTableWithBunchRegistrationsFull(VL15_demo db)

        {

            if (db.DatabaseExists())

            {

                Table<Registration_full> OurRegistrations = db.GetTable<Registration_full>();

                OurRegistrations.InsertAllOnSubmit(OurData.MakeBunchOfRegistrationsFull());

                db.SubmitChanges();

            }

        }

        public static IQueryable<Registration_full> ReturnAllSQLregistrationsFull(VL15_demo db)

        {

            Table<Registration_full> OurRegistrations = db.GetTable<Registration_full>();

            var query =

                from r in OurRegistrations

                select r;

            return query;

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        //----- Session -----

        //--------------------------------------------------------------

        public static List<Session_full> MakeBunchOfSessionsFull()

        {

            Nullable<DateTime> oNDT = new Nullable<DateTime>();

            //--------------------------------------------

            List<Session_full> aList = new List<Session_full>();

            aList.Add(new Session_full("Survey Flights", "using a hexacopter to gather survey data, then processing it.",

                "Frank Maraite", "German", DateTime.Now, false, 12));

            aList.Add(new Session_full("Advanced VN3", "Structuring the SE pane to aid good design.",

                "Dieter Crispien", "German", oNDT, true, 17));

            aList.Add(new Session_full("Views & VMs", "Designing ViewModels to work best with Views.",

                "Phil Hepburn", "English", new DateTime(2015,4,20,15,00,00), true, 39));

            return aList;

        }

        public static void FillTableWithBunchSessionsFull(VL15_demo db)

        {

            if (db.DatabaseExists())

            {

                Table<Session_full> OurSessions = db.GetTable<Session_full>();

                OurSessions.InsertAllOnSubmit(OurData.MakeBunchOfSessionsFull());

                db.SubmitChanges();

            }

        }

        public static IQueryable<Session_full> ReturnAllSQLsessionsFull(VL15_demo db)

        {

             Table<Session_full> OurSessions = db.GetTable<Session_full>();

                var query =

                    from s in OurSessions

                    select s;

                return query;

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        //-------------------------------------------------------------

        //----- Hotel Accommodation -----

        public static List<HotelReservation_full> MakeBunchOfHotelReservationsFull()

        {

            Nullable<int> oNI = new Nullable<int>();

            //--------------------------------------------

            List<HotelReservation_full> aList = new List<HotelReservation_full>();

            aList.Add(new HotelReservation_full(15, "Dan Logan", 3, 112,

                    FoodPreference.Carnivore, HotelAccommodation.Single, TransportMode.Airplane));

            aList.Add(new HotelReservation_full(17, "Ben Hepburn", 2, 213,

                    FoodPreference.FishOnly, HotelAccommodation.None, TransportMode.Bicycle));

            aList.Add(new HotelReservation_full(11, "Willie Moore", 4, 97,

                    FoodPreference.Vegetarian, HotelAccommodation.Suite, TransportMode.Train));

            aList.Add(new HotelReservation_full(01, "Michael Fischer", 5, oNI,

                    FoodPreference.NoneAsYet, HotelAccommodation.None, TransportMode.Metro));

            return aList;

        }

        public static void FillTableWithBunchHotelReservationsFull(VL15_demo db)

        {

            if (db.DatabaseExists())

            {

                Table<HotelReservation_full> OurHotelReservations = db.GetTable<HotelReservation_full>();

                OurHotelReservations.InsertAllOnSubmit(OurData.MakeBunchOfHotelReservationsFull());

                db.SubmitChanges();

            }

        }

        public static IQueryable<HotelReservation_full> ReturnAllSQLhotelReservationsFull(VL15_demo db)

        {

            Table<HotelReservation_full> OurHotelReservations = db.GetTable<HotelReservation_full>();

            var query =

                from hr in OurHotelReservations

                select hr;

            return query;

        }

        //-------------------------------------------------------------------------------------

    }

}

======================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace VL15_CodeFirst_CS2.a_Views

{

    public partial class SessionsView : Window

    {

        private IQueryable<Session_full> aListSF;

        public VL15_demo dbMine;

        public SessionsView(VL15_demo db)

        {

            InitializeComponent();

            this.Initialise();

            this.dbMine = db;

            this.aListSF = OurData.ReturnAllSQLsessionsFull(this.dbMine);

            this.DataContext = aListSF;

            this.tblkMessageS.Text = "Object count :- " + aListSF.Count().ToString();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessageS.Text = "new application DB scoping ...";

        }

        private void pbSaveAllEditing_Click(object sender, RoutedEventArgs e)

        {

            this.dbMine.SubmitChanges();

        }

    }

}

======================================================================================

<Window x:Class="VL15_CodeFirst_CS2.a_Views.SessionsView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Sessions - View :" Height="300" Width="500" Background="LightGreen">

    <Grid>

        <DataGrid Margin="10,40,10,10"

                  GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  AutoGenerateColumns="True"

                  Name="dgL2Qcf_Sess"/>

        <TextBlock Name="tblkMessageS" HorizontalAlignment="Left" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="163" Height="25"/>

        <Button Content="Save all Editing" HorizontalAlignment="Left" Height="25"

                Name="pbSaveAllEditing" Margin="372,10,0,0" VerticalAlignment="Top"

                Width="110" Click="pbSaveAllEditing_Click" Background="DarkGreen"

                Foreground="Gold"/>

    </Grid>

</Window>

======================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace VL15_CodeFirst_CS2.a_Views

{

    public partial class RegistrationsView : Window

    {

        private IQueryable<Registration_full> aListRF;

        public VL15_demo dbMine;

        public RegistrationsView(VL15_demo db)

        {

            this.dbMine = db;

            //---------------

            InitializeComponent();

            this.aListRF = OurData.ReturnAllSQLregistrationsFull(this.dbMine);

            this.Initialise();

            this.dgL2Qcf_Reg.DataContext = aListRF;

            this.tblkMessage.Text = "Object count :- " + aListRF.Count().ToString();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessage.Text = "information will be displayed ...";

        }

        private void pbSaveAllEditing_Click(object sender, RoutedEventArgs e)

        {

            this.dbMine.SubmitChanges();

        }

    }

}

======================================================================================

<Window x:Class="VL15_CodeFirst_CS2.a_Views.RegistrationsView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Registration - View :" Height="300" Width="500" Background="LightCoral">

    <Grid>

        <DataGrid Name="dgL2Qcf_Reg" Margin="10,40,10,10"

                  GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  AutoGenerateColumns="True"  />

        <TextBlock Name="tblkMessage" HorizontalAlignment="Left" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text=".. will change .." VerticalAlignment="Top" Width="230" Height="25"/>

        <Button Content="Save all Editing" HorizontalAlignment="Left" Height="25"

                Margin="341,10,0,0" VerticalAlignment="Top" Width="141"

                Name="pbSaveAllEditing" Click="pbSaveAllEditing_Click" Background="LightGreen"/>

    </Grid>

</Window>

======================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace VL15_CodeFirst_CS2.a_Views

{

    public partial class HotelReservationsView : Window

    {

        private IQueryable<HotelReservation_full> aListHF;

        public VL15_demo dbMine;

        public HotelReservationsView(VL15_demo db)

        {

            InitializeComponent();

            this.Initialise();

            this.dbMine = db;

            this.aListHF = OurData.ReturnAllSQLhotelReservationsFull(this.dbMine);

            this.dgL2Qcf_Hotel.DataContext = aListHF;

            this.tblkMessageH.Text = "Object count :- " + aListHF.Count().ToString();

        }

        //----- methods -----

        public void Initialise()

        {

            this.tblkMessageH.Text = "information will be displayed ...";

        }

        private void pbSaveAllChanges_Click(object sender, RoutedEventArgs e)

        {

            this.dbMine.SubmitChanges();

        }

    }

}

======================================================================================

<Window x:Class="VL15_CodeFirst_CS2.a_Views.HotelReservationsView"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Hotel Reservations - View :" Height="300" Width="500" Background="LightBlue">

    <Grid>

        <DataGrid Name="dgL2Qcf_Hotel" Margin="10,40,10,10"

                  GridLinesVisibility="All" ColumnWidth="Auto"

                  AlternatingRowBackground="AliceBlue"  AlternationCount="2"

                  HeadersVisibility="All" ItemsSource="{Binding }"

                  AutoGenerateColumns="True"  />

        <TextBlock Name="tblkMessageH" HorizontalAlignment="Left" Margin="10,10,0,0"

                   TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Height="25" Width="200"/>

        <Button Content="Save all Changes" HorizontalAlignment="Left" Background="LightGreen"

                Margin="362,10,0,0" VerticalAlignment="Top" Width="120"

                Name="pbSaveAllChanges" Click="pbSaveAllChanges_Click" />

    </Grid>

</Window>

======================================================================================

PHH - 1st. March 2015.


Checking out 'Connection'

==============================================================================================

======================================================================================================================

==============================================================================================================

==========================================================================================================

=============================================================================================================

=================================================================================================================

==========================================================================================================================

================================================================================================================

PHH - 2nd. March 2015.


'Tracking' with 'LINQ to Entity'

PHH - 1st. March 2015.


'SQL Database' - Azure and the Cloud

=====================================================================================================================

Data Source=xbdf484stj.database.windows.net;Initial Catalog=azGroundProbe12;Integrated Security=False;User ID=sqlazdb13;Password=********;Connect Timeout=60;Encrypt=False;TrustServerCertificate=False

Data Source=xbdf484stj.database.windows.net;Initial Catalog=azOlympics;Integrated Security=False;User ID=sqlazdb13;Password=********;Connect Timeout=60;Encrypt=False;TrustServerCertificate=False

PHH - 9th. December 2014.


Vulcan and Azure - 'SQL Database'

PHH - 31st. December 2014.


Chapter 15 - Starting 'Entity Framework 6'

Whatever you have heard about Entity Framework (EF), forget it, it is NOT difficult, and is reasonably easy to

both apply and use. I can do it so you can do it ;-0)

Standard guys can get well into EF (version 6+) and make it work for them and their applications. Here we

start with the current version which is version 6. Already there is web talk about version 7.

The success and ease of this 'stuff' for us guys is having the right mental 'model' in our heads !!

First we need to know few things to help us get going.

ORM :

Object-relational mapping (ORM, O/RM, and O/R mapping) in computer science is a programming technique for

converting data between incompatible type systems in object-oriented programming languages.

For us this means that on one hand we have the SQL database (a relational database) and on the other side of

things we have our .NET code and our Custom / Business objects.

We have back-end Data Source and application code to be executed.

So Microsoft's Entity Framework sits neatly between the two. If we apply EF correctly and completely in our code,

then we need not worry about flat (file) Tables, and the different data types of SQL and T-SQL script.

If we use EF to set up the mapping correctly (and thoroughly) then we can code (and live) in the world of complex

Custom/Business types, which commonly often shows 'nested' property - objects.

The data from deep nested objects still resides in the DB in flat Table structure, it is just that the mapping and the

EF system takes acre of the data movement back and forth across the 'mapping boundary'.

As .NET developers we are used to thinking in terms of Custom / Business class objects, like Customer, Product,

and SalesOrders. We also know and understand our data types in .NET so we don't really wish to have to deal

with (often 'fight') other different types at the same time - as we design and code.

====================================================================================

Lets move on, we now need to know something of 'Code First' and other possibilities - check this out :-

http://msdn.microsoft.com/en-gb/data/ee712907.aspx

We will be doing our work in these eNotes with "Code First" - see what you can read-up from this URL.

====================================================================================================================

PHH - 2nd. January 2015.


Support and learning materials

============================================================================

If its "clear and helpful" you are after then this may not be for you ;-0((

https://www.dropbox.com/sh/z8x3ziek9o17kkx/AAA1Wxg2omm35WFB_f-hUmcIa?dl=0

Read below - BUT - do not panic if you learn 'nothing' !! ?? :-

==============================================================================================================

==============================================================================================================

=================================================================================================================

PHH - 2nd. & 18th. January 2015.


What EF6 is NOT about - don'ts !!!

The BIG no-no with EF generally, and SQL too, is we must not read in too much data from the

back-end server, and we must not hold onto that data in our applications for too long either.

Just because it is easy to query the SQL database and return 'all Customers' is no reason to do it !

We must think of design for our application, and remember that a SQL database is a shared central

data store.

I have seen too many guys wishing to have zillions of rows of data in a DataGrid control. This is just

not what it is all about.

In fact a good developer will design things such as the minimum amount of data is queried and returned,

and also that any data is out of the central database as short a time as possible.

Even when we are just reading data from back-end storage, if it is shared data, then after a while it is

likely that the read and displayed data is out of date - because others changed it. So even for read

only data we need to refresh from time to time.

Mantra :- "Keep data in the central database, and read it only when its needs to be read. data should

be kept in the database, and not in our applications."

PHH - 20th. January 2015.


Our first very simple example - C# for a start

Okay guys, lets get going ;-0)

=====================================================================

As soon as you get a chance, look at the child subsection from here entitled :-

"What is our 'Entity' - why 'Linq to SQL' won't do"

By studying the above child section you will find out what our 'entity' is and why we need EF6,

and why 'Linq to SQL' will not do the task for us instead.

=====================================================================

Moving on ..........

Open Visual Studio 2013 (Update 3) and close any open solutions and projects.

In the Menu-bar select File >> New >> Project... see below :-

==============================================================================================

When the "New Project" dialog wizard screen appears, select and type in details as seen below :-

=================================================================================================================

There is no real need to choose and check 'Add to source control' - so leave that as it is.

Moving on ...........................

Getting our hands on "Entity Framework 6" :

Since we have just used the basic Template for a Console application we will have a limited set of References

in our SE pane.

We need to find and include those References for EF6.

Here is what we are after - check in the following image :-

===============================================================

We are now going to source and download the required EF6 'framework' by using the modern approach

and the 'NuGet' way of doing things.

Go from the Menu-bar and select what I have selected in the next image :-

======================================================================================================

Once the dialog screen appears you will need to search for 'EntityFramework' - my system just happened to

show me what is in the next image, seen below :-

==========================================================================================================================

Make sure you have the package for version 6.1.2 at the least, if it is there now for me then it should be for

you when you need it.

When you have found and displayed the correct 'NuGet' package, start the 'Install' process.

Here are a couple of 'walk-through' images :-

===================================================================

And another .............

======================================================================================================

At this point you should have the two 'Entity' reference entries in the References list in the SE pane.

See below for what you should see in your IDE :-

==========================================================

Just to be sure, check the Properties pane for both of these entries to see we have version 6.

Here is one of my examples :-

===========================================================

Okay then folks, lets get to business ................

Adding our C# code :

Use the text in the child subsection (from here) to add to the 'Program.cs' file the three extra

classes for Blog and Post - check below for details :-

=========================================================================================================================

Make sure you have also included line 7 so that the Namespace associations can refer to the

new References we added above.

Finally, we need to add the text for the code required for the static Main method of the Program class.

Once again you can copy the text from the child subsection for here.

Here is what you should have in place, before we try a build and run :-

[ .. I have included the console displayed a runtime, to save space .. ]

==========================================================================================================================================

Well, the console input and display shows us what the web article says we should get ;-0)

Yes, I know, not a lot, and not very fancy, or even finished off very well !

But, we can improve a lot of these things ourselves, now that we have a simple EF6 application successfully

compiling and running.

At the moment the example is too simple and misses out on a good chance to demonstrate to us what EF6 is

all about.

We need to improve this !!!

Lets move on a pace ....................

Checking the SQL Server, database and any data which has been added :

Before we can further test out the application, with more and better data, we need to be able to

both fins and log into our SQL Server and Database, then we can worry about tables and values etc..

If it is not already on display, or the pane tab nested with others (usually on the LHS (left) of the working

screen area, you can find the "SQL Server Object Explorer" (SSOE) from the 'View' option in the Menu-bar.

Checkout the following :-

===============================================================

And now here is what I can see in my 'SSOE' pane :-

==========================================================================

Notice that from the top little icons we can connect to other and different servers,

as well as refreshing and a couple more useful tasks.

You will most likely need to try to connect to a new server, and the browse to get the software tool to go find

everything 'server' that it can !!

Because I have SQL Server Express installed, the EF system has placed the new database

as if it were attached to it - if there was no Express version then the EF system makes a 'locadb'

version apparently.

I am sure that there are ways of forcing the new database to be attached to my standard MSSS instance

called 'BIG-T\DENALI_2012' - we need to do some further research later.

Let us now try and open my 'Express' server - or as we may also say, 'launch the server instance' :-

================================================================================

Checkout the details shown below with our newly launched 'Express' - yes, I have already

expanded some useful sections under the 'Databases' node.

====================================================================================

Now then guys, we need to see the small item of data that we typed in at the console screen.

If I have read the code correctly then the value item should be in the Table called 'Blogs'.

Follow the selects in my following image :-

================================================================================

And by just a quick click in the correct place we see the next image details :-

============================================================================================================

Yep! - that is what we typed, "ADO.NET Blog".

The 'BlogId' is an identity that is automatically given to the row entry, so we did not specify that.

Lets now look at the other table, the one for 'Posts' - check out below :-

=========================================================================================================================

Yep! this figures with what we have read from the code we ran.

Moving on to further, and better, testing :

Since we have two different 'mappings' and hence I suppose two separate entities, then we do really need to test

these out better than shown in the web article I am reading and following.

Lets start with the 'Post' class - we need to build (instantiate) in code such an object, and then

associate suitable values and other custom objects to the properties.

First lets check the code for the Post class :-

================================================================

In the next image we can see how we may create, populate, and then save an object which

is the in-memory 'side' of an 'entity mapping'.

Look carefully at the following C# code each of the three public properties, Title, Content, and Blog have

been assigned values / objects. It is astonishingly easy to save data to SQL tables ;-0))

=============================================================================================================

*** Please note *** that I have commented out the lines to input text at the console level.

Here below is the active code as well as the console output - which we still keep as in the original.

===========================================================================================================================================

And now the bigger test - has the new hard coded data been saved into both of the different Tables ?

First the 'Blogs' table - check this out :-

===============================================================================================================

And now we need to look at the contents of the dbo.Posts table for the first time - checkout below :-

===================================================================

The context menu was brought up by highlighting the 'Posts' node and then a right mouse click.

Here below is the results - you may need to refresh items and nodes in the LHS panes - remember

that the SQL pattern of use is based on the 'disconnected model'. Meaning we may need to reconnect

and re-populate etc.. Check this out in detail :-

====================================================================================================================================

Note that even the FK (foreign key) has been correctly saved - BlogId above is 2, as it is for the entry in the Blogs table.

Okay then folks - its going well so far.

Now lets try the more complex task, where we need to save a list of Posts in a single Blog entry.

First lets remind ourselves of the structure of the 'Blog' class, so that the entity mapping makes sense

to us - line 84 shows us where we need to supply a list of 'Post' items :-

=======================================================================

Lets now study some suitable hard-coded data as well as some output - the majority of the saved data

will however be seen directly from the SQL database from the VS2013 panes.

==========================================================================================================================

Okay then folks, we can see the input data clearly in lines 34 through 46, and a part of it in the console output as 'our name 2'.

But we would be best to view the Tables directly in VS after we have refreshed the tabled in the SSOE pane.

Study the following details most carefully :-

==============================================================================================================================

If data seems to be missing (and you have not seen any error messages) then Refresh as seen below :-

=======================================================================

And after doing the same for the 'Blogs' table we see the next image :-

=======================================================================================================

Once again all seems well with data inserts and the PK / FK for values '3' seem just fine.

Finally then folks, lets see how easy it is to clear all our test data by deleting the database :-

PHH - 2nd. January 2015.


What is our 'Entity' - why 'Linq to SQL' won't do

Lets start this explanation sub-section by saying, or describing, how many developers use SQL in their application

design 'pattern', and also how they often use Custom, or Business, classes in their code and application design.

*** Remember *** I did not design or create this simple application - it came from a web search !

I will attempt to make a better, or "clearer to understand" example very soon ;-0)

First of all in the Blog & Post app we have the 'DbContext' class as shown below :-

=================================================================

This basically means that our SQL database (when it is made) will have two Tables, one called

'Blogs' and another entitled 'Posts'.

It also states that the data sets for the 'Blogs' table will be one or many 'Blog' objects (items).

So this also reads that the data sets for the Posts table will be one or many 'Post' objects, or items.

Normally we will have a whole bunch more Tables in the 'DbContext' class we define for ourselves and

our applications.

Take a look at the general schema of the Olympics (2012) database I designed and created by 'Code First'

using EF 4.3 - now a couple of years or more ago. Check out the details carefully :-

====================================================

Yes, eight Tables and a View, and most database are a lot more complex than this.

So now lets look at the two data classes - we would often call these 'Custom' or 'Business' classes.

[ .. Other 'Business' classes are Customers, Sales, Orders, Products etc., etc.. ]

The following two classes have properties relating to the other class - they are 'crossed over', Post to

Blog, and Blog to Post(s).

Either one, or the pair, con be considered an Entity for this reason.

So in many ways an 'Entity' can be thought of as an in-memory object where two or more tables are being

mixed up together, by design.

Below we see that the 'Post' class objects have data values from the Post table as well as some from the

'Blog' table. By convention we often leave a spare line or draw a text line between the groups of properties.

================================================================

In the next 'entity' we have a list of 'Post' objects being mixed up with the basic 'Blog' properties.

Once again, notice the empty line - number 83 :-

=======================================================================

We can think of the 'Entity' as the "mapping" of the complex in-memory business object (class) to the

one or more SQL tables needed to take part in the mapping.

The 'entity' is no the object itself, but the mapping to the complex object to the SQL tables.

If we have NO cases of one complex object to many (two or more) tables, then we do not have or need EF,

and can simply use 'Linq to SQL' instead.

'Linq to SQL' is in fact very useful in its own rights, and can be used just like many of us used ADO.NET a

couple of years back.

However, there is one big issue with 'Linq to SQL' in that it will only support Microsoft SQL Server.

EF will support a whole range of SQL server types, depending on whether the Server provider makes a suitable

'driver' or 'converter'.

Short Summary :

If you, me, or anyone else, has an in-memory custom/business object like a Customer with a property of 'Orders'

and also the Order with a list property of 'Products', then we need to be thinking of Entity Framework - right from

the very word 'go'.

In fact, if I had to give some general advice it would be to tray and use EF6+ for everything, right from the start.

Get used to one way of doing things - and do get too fancy, and clever, and complicated too early - take a step at

a time.

There are two choices, do the work to make a more complex mapping and use 'Linq to Entity' or keep your tables

and related classes "one to one" and do the complex work in your code, creating and populating complex objects

from simpler read-in SQL data collections. But you can have it both ways.

I think we will find that EF6+ becomes a way of life to us, and especially 'Code First' for developers. The database

designers can use the other tools ;-0)

PHH - 2nd. January 2015.

Addendum :

====================================================================

==================================================================

===========================================================================================================

============================================================================


working code (C#)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

//--------------------------------------------

using System.Data.Entity;

===================================================================================

 public class BloggingContext : DbContext

    {

        public DbSet<Blog> Blogs { get; set; }

        public DbSet<Post> Posts { get; set; }

    }

    public class Blog

    {

        public int BlogId { get; set; }

        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }

    }

    public class Post

    {

        public int PostId { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int BlogId { get; set; }

        public virtual Blog Blog { get; set; }

    }

===================================================================================

    class Program

    {

        static void Main(string[] args)

        {

            using (var db = new BloggingContext())

            {

                // Create and save a new Blog

                Console.Write("Enter a name for a new Blog: ");

                var name = Console.ReadLine();

                var blog = new Blog { Name = name };

                db.Blogs.Add(blog);

                db.SaveChanges();

                // Display all Blogs from the database

                var query = from b in db.Blogs

                            orderby b.Name

                            select b;

                Console.WriteLine("All blogs in the database:");

                foreach (var item in query)

                {

                    Console.WriteLine(item.Name);

                }

                Console.WriteLine("Press any key to exit...");

                Console.ReadKey();

            }

        }

    }

===================================================================================

===================================================================================

*** after editing by PHH, so new stuff is added ***

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

//-------------------------------------

using System.Data.Entity;

using System.Windows;

namespace CodeFirstNewDatabaseSample

{

    class Program

    {

        static void Main(string[] args)

        {

            using (var db = new BloggingContext())

            {

                //----- make a full Entity 'object' and save it -----

                //var ourPost = new Post { Title = "our title ...", Content = "our content ..." };

                //ourPost.Blog = new Blog { Name = "test13" };

                //db.Posts.Add(ourPost);

                //db.SaveChanges();

                //// Create and save a new Blog

                //Console.Write("Enter a name for a new Blog: ");

                //var name = Console.ReadLine();

                //var blog = new Blog { Name = name };

                //db.Blogs.Add(blog);

                //db.SaveChanges();

                try

                {

                    //----- make another full Entity 'object' and save it -----

                    var ourBlog = new Blog { Name = "our name 2 ..."};

                    var ourPost1 = new Post { Title = "our title 1 ...", Content = "our content 1 ..." };

                    var ourPost2 = new Post { Title = "our title 2 ...", Content = "our content 2 ..." };

                    var ourPost3 = new Post { Title = "our title 3 ...", Content = "our content 3 ..." };

                    ourBlog.Posts = new List<Post>();

                    ourBlog.Posts.Add(ourPost1);

                    ourBlog.Posts.Add(ourPost2);

                    ourBlog.Posts.Add(ourPost3);

                    db.Blogs.Add(ourBlog);

                    db.SaveChanges();

                    //---------------------------

                }

                catch (SystemException oEX)

                {

                    MessageBox.Show(oEX.Message,"my errors :");

                }

                //----- Display all Blogs from the database -----

                var query = from b in db.Blogs

                            orderby b.Name

                            select b;

                Console.WriteLine("All blogs in the database:");

                foreach (var item in query)

                {

                    Console.WriteLine(item.Name);

                }

                Console.WriteLine("Press any key to exit...");

                Console.ReadKey();

            }

        }

    }

    public class BloggingContext : DbContext

    {

        public DbSet<Blog> Blogs { get; set; }

        public DbSet<Post> Posts { get; set; }

    }

    public class Blog

    {

        public int BlogId { get; set; }

        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }

    }

    public class Post

    {

        public int PostId { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int BlogId { get; set; }

        public virtual Blog Blog { get; set; }

    }

}

===================================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

//-------------------------------------

using System.Data.Entity;

using System.Windows;

namespace CodeFirstNewDatabaseSample

{

    class Program

    {

        static void Main(string[] args)

        {

            using (var db = new BloggingContext())

            {

                ////----- make a full Entity 'object' and save it -----

                //var ourPost = new Post { Title = "our title ...", Content = "our content ..." };

                //ourPost.Blog = new Blog { Name = "test13" };

                //db.Posts.Add(ourPost);

                //db.SaveChanges();

                db.Database.Delete();

                //// Create and save a new Blog

                //Console.Write("Enter a name for a new Blog: ");

                //var name = Console.ReadLine();

                //var blog = new Blog { Name = name };

                //db.Blogs.Add(blog);

                //db.SaveChanges();

                //try

                //{

                //    //----- make another full Entity 'object' and save it -----

                //    var ourBlog = new Blog { Name = "our name 2 ..."};

                //    var ourPost1 = new Post { Title = "our title 1 ...", Content = "our content 1 ..." };

                //    var ourPost2 = new Post { Title = "our title 2 ...", Content = "our content 2 ..." };

                //    var ourPost3 = new Post { Title = "our title 3 ...", Content = "our content 3 ..." };

                //    ourBlog.Posts = new List<Post>();

                //    ourBlog.Posts.Add(ourPost1);

                //    ourBlog.Posts.Add(ourPost2);

                //    ourBlog.Posts.Add(ourPost3);

                //    db.Blogs.Add(ourBlog);

                //    db.SaveChanges();

                //    //---------------------------

                //}

                //catch (SystemException oEX)

                //{

                //    MessageBox.Show(oEX.Message,"my errors :");

                //}

                //----- Display all Blogs from the database -----

                //----- the next 3 lines is why we need C# code, & LINQ -----

                var query = from b in db.Blogs

                            orderby b.Name

                            select b;

                Console.WriteLine("All blogs in the database:");

                foreach (var item in query)

                {

                    Console.WriteLine(item.Name);

                }

                Console.WriteLine("Press any key to exit...");

                Console.ReadKey();

            }

        }

    }

    public class BloggingContext : DbContext

    {

        public DbSet<Blog> Blogs { get; set; }

        public DbSet<Post> Posts { get; set; }

    }

    public class Blog

    {

        public int BlogId { get; set; }

        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }

    }

    public class Post

    {

        public int PostId { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int BlogId { get; set; }

        public virtual Blog Blog { get; set; }

    }

}

===================================================================================

PHH - 2nd. January 2015.


Our first simple example in Vulcan.NET 3

Okay then guys, this is a time to be totally honest with ourselves ;-0)

In order to use any of the LINQ related technologies - 'Linq to Objects', 'Linq to SQL' and

'Linq to Entity' - we need to use LINQ and that is built into the Microsoft .NET compilers.

So both C# and VB.net have it available to them.

At this very moment Vulcan.NET (version 303j) does not, and I have not heard of anything

either soon or imminent for the coming year.

So, we need a way around the situation, and it both exists, and is also good for us as developers.

The work around also shows us all some of the major benefits of using .NET and also Visual Studio.

I spent some time last evening moving code around from our previous C# simple example.

In fact I have totally restructured the solution / project, without actually changing the code much.

In the following image we see my new structure, and it is based upon having a Class Library in C#

which has all the classes to do with the SQL database, the table details, and also all data access

using LINQ.

At the moment the 'start-up' project (highlighted in bold) is still written in C#. but that will soon change.

Study the following image details carefully, and thoroughly :-

=================================================================

The launching 'application' code is still in the 'Program.cs' file at the bottom of the

above image.

Here it is shown in the following image, along with some console output :-

==================================================================================================================================

============================

===================================================================

=============================================================================================================================

======================================================================

=========================================================================================================

======================================================================================================

=================================================================================

Moving on to a Vulcan main program, with WPF :

Open VS 2013 and have open the solution / project for the first very simple example.

In the SE pane close down, or collapse, the nodes - see below :-

=====================================================================

With the solution node in focus (highlighted) right click it to get the context menu.

Select to a a new project - see my dialog wizard screen below :-

============================================================================================================================

===============================================================================================================================

==========================================================

====================================================

=====================================================================================================================================

==============================================================

=====================================================================================================

====================================================

=================================================================================

=================================================

====================================================================

===========================================================================================================================

================================================================================

================================================================

=================================================================================================

========================================================================

==============================================================================

=========================================================================================================

======================================================================================================

==============================================================================================================

===================================================

====================================================================

====================================================================

=====================================================================

At this point it is best if we move on to the next section and deal with all the improvements and

extensions to our application features, all in one go.

See you there ............................

PHH - 2nd. & 3rd. January 2015.


working script and code

===============================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

#using LINQ_ClassLibrary1

begin namespace VN303j_CFnewDatabaseSample

partial class Window1 inherit Window

    constructor()

        super()

        InitializeComponent()

        //-----------------------

        try

            MessageBox.Show("basic test ...","my Error :")

            local implied db := LINQ_ClassLibrary1.CS_LinqLibrary.BloggingContext{}

            self:lbxBlogs:DataContext := CS_LinqLibrary.ReturnAllBlogs(db)

            self:lbxPosts:DataContext := CS_LinqLibrary.ReturnAllPosts(db)

        catch oEX as SystemException

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return

end class

end namespace

===============================================================================

<Window x:Class="VN303j_CFnewDatabaseSample.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Vulcan 303j - Linq &amp; EF6 :" Height="400" Width="500" Background="Beige">

    <Grid>

        <ListBox Margin="20,45,288,52"

                 Name="lbxBlogs" ItemsSource="{Binding}"/>

        <ListBox Margin="254,45,10,52"

                 Name="lbxPosts" ItemsSource="{Binding}"/>

        <Label Content="Posts :" HorizontalAlignment="Left"

               Margin="20,10,0,0" VerticalAlignment="Top" Width="99"/>

        <Label Content="Blogs :" HorizontalAlignment="Left"

               Margin="254,10,0,0" VerticalAlignment="Top" Width="56"/>

    </Grid>

</Window>

===============================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE VN303j_CFnewDatabaseSample

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

===============================================================================

<Application x:Class="VN303j_CFnewDatabaseSample.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

===============================================================================

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

//-------------------------------------

using System.Data.Entity;

using System.Windows;

namespace LINQ_ClassLibrary1

{

    public class CS_LinqLibrary

    {

        public static void RemoveDB(BloggingContext db)

        {

            db.Database.Delete();

        }

        public static void HardCodeAndSaveBlog1(BloggingContext db)

        {

            //----- Create and save a new Blog -----

            Console.Write("Enter a name for a new Blog: ");

            var name = Console.ReadLine();

            var blog = new Blog { Name = name };

            db.Blogs.Add(blog);

            db.SaveChanges();

        }

        public static void HardCodeAndSaveBlog2(BloggingContext db)

        {

            //----- make a full Entity 'object' and save it -----

            var ourPost = new Post { Title = "our title ...", Content = "our content ..." };

            ourPost.Blog = new Blog { Name = "test13" };

            db.Posts.Add(ourPost);

            db.SaveChanges();

        }

        public static string HardCodeAndSaveBlog3(BloggingContext db)

        {

            try

            {

                //----- make another full Entity 'object' and save it -----

                var ourBlog = new Blog { Name = "our name 2 ..." };

                var ourPost1 = new Post { Title = "our title 1 ...", Content = "our content 1 ..." };

                var ourPost2 = new Post { Title = "our title 2 ...", Content = "our content 2 ..." };

                var ourPost3 = new Post { Title = "our title 3 ...", Content = "our content 3 ..." };

                ourBlog.Posts = new List<Post>();

                ourBlog.Posts.Add(ourPost1);

                ourBlog.Posts.Add(ourPost2);

                ourBlog.Posts.Add(ourPost3);

                db.Blogs.Add(ourBlog);

                db.SaveChanges();

                //---------------------------

            }

            catch (SystemException oEX)

            {

                //MessageBox.Show(oEX.Message, "my errors :");

                return oEX.Message;

            }

            return "Okay ! - no errors.";

        }

        public static string DisplayAllBlogs(BloggingContext db)

        {

            //----- Display all Blogs from the database -----

            //----- the next 3 lines is why we need C# code, & LINQ -----

            var query = from b in db.Blogs

                        orderby b.Name

                        select b;

            string cResult = "";

            foreach (var item in query)

            {

                cResult += item.Name+"\n";

            }

            return cResult;

        }

        public static string DisplayAllPosts(BloggingContext db)

        {

            //----- Display all Posts from the database -----

            //----- the next 3 lines is why we need C# code, & LINQ -----

            var query = from p in db.Posts

                        orderby p.PostId

                        select p;

            string cResult = "";

            foreach (var item in query)

            {

                cResult += item.Title+"\n";

            }

            return cResult;

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        public static List<Blog> ReturnAllBlogs(BloggingContext db)

        {

            //----- Return all Blogs from the database -----

            var query = from b in db.Blogs

                        orderby b.Name

                        select b;

            var aList = query.ToList();

            return aList;

        }

        public static List<Post> ReturnAllPosts(BloggingContext db)

        {

            //----- Return all Posts from the database -----

            var query = from p in db.Posts

                        orderby p.PostId

                        select p;

            var aList = query.ToList();

            return aList;

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        public class BloggingContext : DbContext

        {

            public DbSet<Blog> Blogs { get; set; }

            public DbSet<Post> Posts { get; set; }

        }

        public class Blog

        {

            public int BlogId { get; set; }

            public string Name { get; set; }

            public virtual List<Post> Posts { get; set; }

            override public string ToString()

            {

                return BlogId.ToString() + " >> " +  Name.Trim();

            }

        }

        public class Post

        {

            public int PostId { get; set; }

            public string Title { get; set; }

            public string Content { get; set; }

            public int BlogId { get; set; }

            public virtual Blog Blog { get; set; }

            override public string ToString()

            {

                return BlogId.ToString() + " >> " + Title.Trim();

            }

        }

    }

}

===============================================================================

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

<packages>

  <package id="EntityFramework" version="6.1.2" targetFramework="net45" />

</packages>

===============================================================================

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

<configuration>

  <configSections>

    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->

    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />

  </configSections>

  <entityFramework>

    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />

    <providers>

      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />

    </providers>

  </entityFramework>

</configuration>

===============================================================================

===============================================================================

PHH - 3rd. January 2014.


Improving and extending our example

Okay then folks, in the last sub-section we managed to get a C# class library working along

side a Vulcan project based on WPF and data binding technologies.

If you remember, the C# project was required so that we could use the LINQ capabilities built into

the C# compiler.

LINQ is so good that I just can't live without it, even when I am using Vulcan.NET and its nice syntax.

And since Microsoft designed and built 'Linq to SQL' and 'Linq to Entity' to work with LINQ, 100%, then

we need to use LINQ if we are to use 'Entity Framework', or any version.

Basically, if we place into our C# class library, any .NET code which interacts with the data source as

well as the classes defined to support such SQL Server back-end storage and retrieval, then all the

rest of the business logic code can be placed in the Vulcan.NET 3 project, from where we can easily

access all the members based on LINQ / EF6 and which is in the class library.

So far we have just retrieved a couple of lists and returned them to our VN3 code, but we need to be

able to accept input data at the WPF GUI form level and save it in the relevant tables via the Entity

'mapping' of EF6.

We need to explore a range of data acquisition techniques within our Class Library.

We could also look at clearing the Database, deleting and creating a new DB, as well as adding an

extra table or two - Oh! and maybe a SQL DB back-up as well ;-0)

Please forgive me if we stick with our rather poor (or weak) example of a DB using the Blog/Post ideas.

Quite soon we will be able to use our new found skills by moving back to our Vulcan.Live.15 example.

Let us start with a few Library classes to save single and list items for both 'Post' and 'Blog' items. Once

we have those we can then create a simplified WPF form to accept input details and allow saving into the

database.

Lets roll up our sleeves and get cracking ..................

What are we aiming to achieve ? :

Here is what we looking to produce after quite a few coding improvements :-

===========================================================================

We will have two bound list elements - one for Posts and the other for Blogs.

We also have a few new buttons to explain - we are going to be brave enough to

both delete and create the whole database - as an object.

We then will have buttons to populate the two Tables (Blogs and Posts) by saving

list of hard coded collection items.

The Refresh buttons are there to simply update the list element displays with the

most current full list of items read directly from the DB tables.

If we are lucky we will do a simple couple of experiments to empty a single Table of

all listed contents - note that this is NOT the same as deleting the table !

Lets move on .........................

Starting at the End ! - a good place to start ? :

Here is the 'shape' of my SE pane now that all the new parts are coded in, tested, and

apparently working okay - check the details :-

=======================================================

Notice that we have one unloaded project - not the same as removed or deleted ;-)

We have a Class Library written in C# .NET code which has been heavily changed and improved,

as well as a vastly changed and updated Vulcan.NET application using VN3 version 303j which is

the new year release we are testing in VPS.

In the above SE pane structure we should have virtually no code in the main Template part of the

Window1 class - check below :-

============================================================

And all the rest of the Vulcan.NET code is in the 'Part2' code file - see the collapsed view

of this in the following image :-

==========================================================================================

The first thing you will notice above is that we have moved all the event handlers into 'Part2' of

the Window1 class code file (lines 62 to 105).

We have two Database methods (lines 38 - 60) to remove and create the database.

There are two methods to provide hard coded data shown at lines 107 through 122.

Good, but not complex or complicated, as we shall see when we 'walk-through' some of the code

and actions I took in making the working app.

Lets take a step or two more ...............

The improved and updated 'Class Library' :

In the following image the first thing to notice in the collapsed member view of the code, is that the classes

for the database definition / description, have been placed outside of the 'CS_LinqLibrary' - an improvement on

what we previously had.

Notice the '3' on the method to save a list of items - this is a development situation, as versions 1 and 2 were

okay, and worked, but inferior in my opinion.

We will examine them in detail later - first check this out CAREFULLY :-

===========================================================================================================

By having the table and database classes external to 'CS_LinqLibrary' we need to have less code in most

members we design, create and code ourselves.

Lets now look at the important static members to save one and many items to the 'Blogs' table :-

===============================================================================================

If you are interested in the two alternative 'old fashioned' methods then here they are shown below :-

=======================================================================================

So as it stands now, both Posts and Blogs tables are updated the better way using directly the

members of the Database Context (DbContext) class.

Now then folks, if we are to use WPF and binding with XAML and the likes, we need to return a

list of items from our querying of Posts and Blogs, not a long text string.

Check out the following LINQ code to do this for the 'Posts' table :-

===============================================================================

Yep! - above is nothing special, pretty standard LINQ stuff really ;-0)

However, we need to study in detail the changes to the Blog class ( as well as Post class).

I needed to tidy up the earlier simple class, so that it would handle better the deletion of the

database itself, and also the creation when tables are empty etc..

Check out in particular the constructors and the 'ToString()' method :-

============================================================================

The code is similar for the Post class definition but is a bit more complex in some ways.

Checkout the following carefully :-

=========================================================================

Moving on - to Part 2 of our Vulcan.NET code in the main project ...........

Okay then guys, lets move on to see what code we needed to put in place to stop our application

crashing when we Delete and Create the database itself.

The bulk of such code comes from trying to trap and catch all errors and issues, to support a clean 'runtime'.

First check the Deletion method :-

================================================================

It is just as well to have such a critical operation return a Boolean, then we can judge what to do next,

when the member returns true or false to the calling code / member.

You could comment line 44 if you like, as the 'error trap' has been made, then the correct Boolean value returned.

Let us now study the more complex 'Creation' method - see below :-

[ .. seemed like a good idea to force a delete first .. ]

========================================================================================

If found it a good idea to force a deletion just before the 'Create' call - BUT - please be warned,

if in VS you have had the SSOE pane open and had the server open and showing the Tables and

data rows etc., you will need to disconnect the Server to stop you getting an error when you try

to delete and create.

Regular MSSS user / developers will recognise the common situation.

Yes, I know, the code could still be further tightened up - I will leave that to you ;-0)

Note however, that lines 54 & 55 refresh the list displays, and maybe these could be made

more robust, or bomb proof, if we forced an association to 'null' before the re-assignment.

I feel I have done enough for you, me and us !

Now we need to check out a couple of event handlers. Lets see how we can populate a table

with a few rows of hard coded data / information :-

======================================================================================

Notice that we are using version 3'3 of the new method, the more modern approach.

And to refresh the list box element from the Posts table - check below :-

========================================================================================

And finally the static method to supply some data a 'bunch' at a time :-

=================================================================

Lets move on a pace or two ..............

Finally, lets show and study what we just about do FIRST of all when we launch the app !!

The Initialize() method is simple enough but still important - check this out :-

===========================================================================================

And of course code line 29 above is probably the most important of all the whole application !!

It instantiates the 'DbContext' type object that we use application wide to access the SQL database.

Here it is below, as we declare it at the head of the main Window class :-

=====================================================================

Okay then guys, we have an instantiated 'db' or DbContext class object - now lets go and do some testing

on how this may be used in the working of the application.

Carrying out the Testing :

We need to see if our application is robust enough to remove and create the database itself,

and not just populate table rows and read back table data - to show in our list elements using 'binding'.

Here (below) we are trying a 'delete' :-

============================================================================

If we were to correctly write the code for the above, then we ought to detect a successful DB

removal, and then clear the list contents - you may have to do that bit yourself ;-0)

You will need to use "db.Database.Exists()" in a few places in your code to make it more robust.

Here is a start :-

================================================================

And here is a little more, as it is also Vulcan.NET code :-

=========================================================================================

There are plenty of places that you can still improve the code as I present it to you. Good Luck !

Now then folks, let move on, when we delete and create the database, what exactly is going on ?

We need to use a software tool to look directly at the SQL Server and the databases on option.

Here is such a tool from within VS2013 - the "SQL Server Object Explorer" - 'SSOE' - checkout the pane :-

[ .. study the detail thoroughly .. ]

=========================================================================================

The highlighted section shows three differently named databases.

It would appear that these were automatically made as I built and ran the application, so why three ?

Well, my guess is that as I improved and updated the app., as I added extra parts and developed it, then

we got newer and differently named databases.

If we study the SE pane content as it is now, then we get a clue as to what is going on :-

=================================================

Notice that the 'DbContext' related class definition is as shown below :-

===============================================================

So when we see the Properties pane of the database node in SSOE we get the following :-

C:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA\LINQ_ClassLibrary1.BloggingContext.mdf

as the Data file, and then the line shown below as the connection string - check it out carefully :-

Data Source=BIG-T\SQLEXPRESS;Initial Catalog=LINQ_ClassLibrary1.BloggingContext;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False

So far we have not had to worry about connection strings - makes a nice change ;-0)

Lets move on and do something a little different ..........

See below how to disconnect the server - the Server is highlighted in blue at the top of pane content :-

====================================================================================================

When we choose to disconnect (with a mouse click) we have the server removed from the list in the

SSOE pane - check below in detail :-

===================================================================

Now we can Delete / Remove the database from code, as well as re-Create it.

But before we go about deleting databases, let us see some of the data we have managed

to save in the two Tables - first the 'Posts' table :-

=======================================================================

And now the 'Blogs' table :-

=========================================================================================================================

You will be please to know that it is easy to select to list the row data in a Table.

Check the image following to see that we right click the actual Table node and get a context menu :-

=================================================================================

After some further testing the 'Posts' table looks like this :-

======================================================================================================================================

Okay then folks, we have learned a lot, now it is time to move on.

Lets us now move the the next sub-section and see how to use all this knowledge to design and

make another, and better, example - one based on the Vulcan.Live.15 event itself.

We will return to Registrations, Hotel Reservations, Sessions, Speakers and more, but

this time we will be applying Entity Framework 6 so that we can place all our data in a SQL database.

Why don't we also make the whole project totally screen and user interactive ?

So we should be putting together everything we have learned so far - all into one nice demo application.

See you in the next section ....................

PHH - 2nd. & 3rd. January 2015.


working script and code

===================================================================================

//----- CS_LinqLibrary.cs -----

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

//-------------------------------------

using System.Data.Entity;

using System.Windows;

namespace LINQ_ClassLibrary1

{

    public class CS_LinqLibrary

    {

        public static void RemoveDB(BloggingContext db)

        {  db.Database.Delete(); }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        public static void BlogSingleSave(BloggingContext db, Blog oB)

        {

            //----- Save a new Blog -----

            db.Blogs.Add(oB);

            db.SaveChanges();

        }

        public static void BlogListSave3(BloggingContext db, List<Blog> aListB)

        {

            //----- Save a new Blog List -----

            db.Blogs.AddRange(aListB);

            db.SaveChanges();

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        public static void PostSingleSave(BloggingContext db, Post oP)

        {

            //----- Save a new Blog -----

            db.Posts.Add(oP);

            db.SaveChanges();

        }

        public static void PostListSave3(BloggingContext db, List<Post> aListP)

        {

            //----- Save a new Blog List -----

            db.Posts.AddRange(aListP);

            db.SaveChanges();

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        public static string DisplayAllBlogs(BloggingContext db)

        {

            //----- Display all Blogs from the database -----

            //----- the next 3 lines is why we need C# code, & LINQ -----

            var query = from b in db.Blogs

                        orderby b.Name

                        select b;

            string cResult = "";

            foreach (var item in query)

            {

                cResult += item.Name+"\n";

            }

            return cResult;

        }

        public static string DisplayAllPosts(BloggingContext db)

        {

            //----- Display all Posts from the database -----

            //----- the next 3 lines is why we need C# code, & LINQ -----

            var query = from p in db.Posts

                        orderby p.PostId

                        select p;

            string cResult = "";

            foreach (var item in query)

            {

                cResult += item.Title+"\n";

            }

            return cResult;

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        public static List<Blog> ReturnAllBlogs(BloggingContext db)

        {

            //----- Return all Blogs from the database -----

            var query = from b in db.Blogs

                        orderby b.Name

                        select b;

            var aList = query.ToList();

            return aList;

        }

        public static List<Post> ReturnAllPosts(BloggingContext db)

        {

            //----- Return all Posts from the database -----

            var query = from p in db.Posts

                        orderby p.PostId

                        select p;

            var aList = query.ToList();

            return aList;

        }

        //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    }

    //============================================================

    public class BloggingContext : DbContext

    {

        public DbSet<Blog> Blogs { get; set; }

        public DbSet<Post> Posts { get; set; }

    }

    public class Blog

    {

        //----- properties -----

        public int BlogId { get; set; }

        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }

        //----- constructors -----

        public Blog()

        {

            this.Name = "";

            this.Posts = new List<Post>();

        }

        public Blog(string cN)

        {

            this.Name = cN;

            this.Posts = new List<Post>();

        }

        //----- methods -----

        override public string ToString()

        {

            if (null != BlogId)

            { return BlogId.ToString() + " >> " + Name.Trim(); }

            else

            { return " >> " + Name.Trim();}

        }

    }

    public class Post

    {

        //----- properties -----

        public int PostId { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int BlogId { get; set; }

        public virtual Blog Blog { get; set; }

        //----- constructors -----

        public Post()

        {

            this.Title = "";

            this.Content = "";

            this.Blog = new Blog();

        }

        public Post(string cT, string cC)

        {

            this.Title = cT;

            this.Content = cC;

            this.Blog = new Blog();

        }

        //----- methods -----

        override public string ToString()

        {

            if (null != PostId)

            {return PostId.ToString() + " >> " + Title.Trim();}

            else

            {return " .... >> " + Title.Trim();}

        }

    }

}

===================================================================================

<Application x:Class="VN303j_CFnewDatabaseSample.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

===================================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE VN303j_CFnewDatabaseSample

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

===================================================================================

<Window x:Class="VN303j_CFnewDatabaseSample.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Vulcan 303j - Linq &amp; EF6 :" Height="400" Width="500" Background="Beige">

    <Grid>

        <ListBox Margin="20,45,288,52"

                 Name="lbxPosts" ItemsSource="{Binding}"/>

        <ListBox Margin="254,45,10,52"

                 Name="lbxBlogs" ItemsSource="{Binding}"/>

        <Label Content="Posts :" HorizontalAlignment="Left"

               Margin="20,10,0,0" VerticalAlignment="Top" Width="59"/>

        <Label Content="Blogs :" HorizontalAlignment="Left"

               Margin="254,10,0,0" VerticalAlignment="Top" Width="56"/>

        <Button Content="Delete DB" HorizontalAlignment="Left" Margin="20,334,0,0"

                Name="pbDeleteDB" VerticalAlignment="Top" Width="84" Click="pbDeleteDB_Click"/>

        <Button Content="Create DB" HorizontalAlignment="Left" Margin="119,334,0,0"

                Name="pbCreateDB" VerticalAlignment="Top" Width="85" Click="pbCreateDB_Click"/>

        <Button Content="Refresh Posts" HorizontalAlignment="Left" Margin="119,16,0,0"

                Name="pbRefreshPosts" VerticalAlignment="Top" Width="85" Click="pbRefreshPosts_Click"/>

        <Button Content="Refresh Blogs" HorizontalAlignment="Left" Margin="390,16,0,0"

                Name="pbRefreshBlogs" VerticalAlignment="Top" Width="92" Click="pbRefreshBlogs_Click"/>

        <Button Content="Populate Posts" HorizontalAlignment="Left" Margin="254,334,0,0"

                Name="pbPopulatePosts" VerticalAlignment="Top" Width="90" Click="pbPopulatePosts_Click" />

        <Button Content="Populate Blogs" HorizontalAlignment="Left" Margin="390,334,0,0"

                Name="pbPopulateBlogs" VerticalAlignment="Top" Width="92" Click="pbPopulateBlogs_Click"/>

    </Grid>

</Window>

===================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

#using LINQ_ClassLibrary1

begin namespace VN303j_CFnewDatabaseSample

    partial class Window1 inherit Window

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

    end class

end namespace

===================================================================================

//----- Window1Part2.prg -----

//----- PHH - January 3rd. / 4th. 2015 -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

#using LINQ_ClassLibrary1

begin namespace VN303j_CFnewDatabaseSample

partial class Window1 inherit Window

    public db as LINQ_ClassLibrary1.BloggingContext

    //----- methods -----

    method Initialize() as void

        try

            //MessageBox.Show("basic test ...","my Error :")

            self:db := LINQ_ClassLibrary1.BloggingContext{}

            self:lbxBlogs:DataContext := CS_LinqLibrary.ReturnAllBlogs(db)

            self:lbxPosts:DataContext := CS_LinqLibrary.ReturnAllPosts(db)

        catch oEX as SystemException

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return

    //----- database -----

    method MyDeleteDB() as Boolean

        local implied lResult := false

        try

            self:db:Database:Delete()

            lResult := true

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return lResult

    method MyCreateDB() as Boolean

        local implied lResult := false

        try

            self:db:Database:Delete()

            self:db:Database:Create()

            lResult := true

            self:lbxBlogs:DataContext := CS_LinqLibrary.ReturnAllBlogs(db)

            self:lbxPosts:DataContext := CS_LinqLibrary.ReturnAllPosts(db)

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return lResult

    //----- database handlers -----

    private method pbDeleteDB_Click( sender as System.Object, ;

                e as System.Windows.RoutedEventArgs ) as System.Void

        if self:MyDeleteDB()

            MessageBox.Show("DB removed !?","my Check :")

        else

            MessageBox.Show("DB not deleted ???","my Check :")

        end if

    return

    private method pbCreateDB_Click( sender as System.Object, ;

                e as System.Windows.RoutedEventArgs ) as System.Void

        if self:MyCreateDB()

            MessageBox.Show("DB remade !","my Check :")

        else

            MessageBox.Show("DB not created ???","my Check :")

        end if

    return

    //----- tables -----

    private method pbPopulatePosts_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        //-------------------------------------------------

        CS_LinqLibrary.PostListSave3(db, GetBunchOfPosts())

    return

    private method pbPopulateBlogs_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        //-------------------------------------------------

        CS_LinqLibrary.BlogListSave3(db, GetBunchOfBlogs())

    return

    private method pbRefreshPosts_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        self:lbxPosts:DataContext := null

        self:lbxPosts:DataContext := CS_LinqLibrary.ReturnAllPosts(db)

    return

    private method pbRefreshBlogs_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        self:lbxBlogs:DataContext := null

        self:lbxBlogs:DataContext := CS_LinqLibrary.ReturnAllBlogs(db)

    return

    //----- data hard coded -----

    public static method GetBunchOfBlogs() as List<Blog>

        local implied aListB := List<Blog>{}

        aListB:Add(Blog{"Test name"})

        aListB:Add(Blog{"Sunday"})

        aListB:Add(Blog{"Issues"})

        aListB:Add(Blog{"Welsh blog"})

        aListB:Add(Blog{"Blogger united"})

    return aListB

    public static method GetBunchOfPosts() as List<Post>

        local implied aListP := List<Post>{}

        aListP:Add(Post{"New", "new content"})

        aListP:Add(Post{"Old", "old content"})

        aListP:Add(Post{"Past", "past content"})

    return aListP

end class

end namespace

===================================================================================

    //----- database -----

    method MyDeleteDB() as Boolean

        local implied lResult := false

        try

            self:db:Database:Delete()

            lResult := true

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return lResult

    method MyCreateDB() as Boolean

        local implied lResult := false

        try

            if ! self:db:Database:Exists()

                self:db:Database:Create()

                lResult := true

                self:lbxBlogs:DataContext := CS_LinqLibrary.ReturnAllBlogs(db)

                self:lbxPosts:DataContext := CS_LinqLibrary.ReturnAllPosts(db)

            endif

        catch oEX as System.Exception

            MessageBox.Show(oEX:Message,"my Error :")

        end try

    return lResult

===================================================================================

PHH - 3rd. January 2015.


Starting a better example - sample two, 'the Conference'

PHH - 2nd. & 6th. January 2015.


The 'Plan' - a possible application design ...

When does the ' DbContext' get applied ?

Or, what do we have to do the have the new database created ?

PHH - 6th. January 2015.


Making a start - the Project

Okay the guys, lets get to work, roll up your sleeves and lets get 'to it' !

Open Visual Studio 2013 and close any solution / project(s) that is/are open.

Start a new Project (solution) from the menu-bar with 'File >> Project...' as seen below :-

======================================================================================

When you get the 'New Project' dialog screen (wizard) as shown below, select and enter as you see

I have done :-

=================================================================================================================================

Yes, the Template we have chosen is a Vulcan.NET one for an application based around WPF and XAML.

Notice also that I have checked the box so that I get the Project added to 'Source Control'. Which is a wise

move as it is likely to get far bigger, and more complex, than the earlier demo apps.

After clicking OK to accept the selections we should see the next image on screen :-

======================================================================================================================

Notice above that I have opted to use TFS and not Git - it suits my own personal development style.

And if you follow what I am doing you then should see something like the following :-

===============================================================

Keep clicking the OK buttons until you see the following details in your SE pane :-

==============================================================

Well, this seems like a good start - we have a Vulcan main XAML/WPF application.

Let us see what the References section looks like - check below :-

=============================================

Okay then, 'so far so good' - but it appears as if we need to use 'NuGet' to add the EF6

(Entity Framework) two entries, as well as an entry to effectively 'point at' the class library that

the main module of the application will need to use.

Lets start with the new 'Class Library' project ..................

We now need a new project based on a Template of a C# class library - so highlight the

solution module in the SE pane and right click to bring up the context menu :-

===============================================================================================

Select to allow us to add a new Project.

Here are the details which are further required - check below :-

===========================================================================================================================

And after pressing OK we should see this next image appear on our screen :-

==================================================================

Yes, in the above image we see a new entry in the SE pane, we now have a second

Project - this new one is called "ClassLibraryFullConf".

Okay, it is a little empty at the moment, but we can soon put that to rights ;-)

Here is what we have at present :-

======================================================================

Okay then folks, lets keep on moving forward ..............

Although the Class Library is virtually empty, we can still add it to the References to our

Vulcan project.

At the same time as we add the Class Library we can also use 'NuGet' to find and install the

EF6 assemblies we require.

Lets open up the References 'node' and add the Class Library as follows :-

=================================================================================

The Visual Studio support system seems to have on-hand exactly what we need, as is

shown above.

Very quickly we get what we need - as seen in the next image, below :-

=================================================

Next we need to move on to getting the 'Entity Framework' assemblies entered into our

References section.

If you like you can try a context menu choice on the References 'node' - see what happens

when we try this :-

================================================================

Whoops ! - Oh dear !! - check below :-

===========================================================================================================

Lets ignore this 'failure' and try another way ;-)

Leave the highlighting in the SE pane as it is - on the References of the VN3 project, and move to the VS main Menu-bar :-

==========================================================================================================

Now let us try this alternative way of hopefully doing the same thing.

After a click in the short drop list shown above we get the following wizard / dialog screen :-

============================================================================================================

Now it looks as though we are in business, lets go for it and click the Install button.

This is what we next see on our screen :-

=====================================================================

Keep going by selecting the defaults, or obvious choices :-

===========================================================

Now accept and see some success, it would appear :-

===============================================================================================

So lets see where the install has placed the EF dlls !? Check this out below :-

===================================================

Oh well ! - we needed to have the EF dlls in our Class Library references, but we still seem

to be missing then in the Vulcan project.

Lets now try again and see if in the Add References dialog we can find a tab which seems to

give us what we are after. Bring up the context menu on References, as seen below :-

=================================================

And with some luck you should be as lucky as me - see what I have located below, in

the 'Recent' tab :-

=================================================================

Now all we need do is multiple select the two EF assemblies (dlls) and click OK.

Lets have a 'long' look at the details ;-0) ... checkout the next view :-

======================================================================================================================================================================

Select and click the OK button at the bottom of the dialog, and with luck you will also see this shown below :-

============================================

Great stuff ! - well we seem to be winning, at last ;-)

Now close down, or collapse, the References sections and compile and run the new application.

Here is what my small success looks like (yes, not a lot BUT it works) :-

=================================================================================================================

It looks from above that it is time for us to type in some code !

Lets start with some simplified versions of the data oriented EF 'DbContext' class and some 'DbSet' related classes.

Here is a start (we will improve them later) :-

============================================================

===========================================================================

=============================================================================

==============================================================================

==================================================================================================================

=========================================================================

============================================================================================

PHH - 6th. January 2015.


Creating the Class Library

Let us start this section by asking a few basic and simple questions !

What is a Class Library, what is it for, and how does it help us with the current application design ?

Some General Background information :

Lets see a simple image of the SE pane for a working application using a Class Library - check below :-

===================================================

In this solution (see SE pane above) we place a second project which is quite separate to the main

project which was created when we started the solution. So we have a VN and a CS project.

Since the 'Class Library' is a separate project then it can be written and designed in any .NET language

we care to use - or prefer to code in.

Remember this is one of the benefits of .NET, we can mix and match different project languages.

So effectively, anything the Vulcan compiler can't do we can move into our C# class library.

If we open up the 'CL' node in the SE pane for the class library we see the following :-

====================================

In many ways it just looks like any project, it has its own References folder for example, and the

last three nodes shown above (x through z) have been created by me.

Obviously, a 'CL' can also be designed and created to be used in other solutions of a similar nature

to the one we have in focus - placing the common classes into the CL.

In this example, I am using a CL for the purpose of handling all the LINQ code, simply because VN3

at the moment does not have LINQ capabilities built into its compiler.

So I describe what we have as a "thin C# 'Data Layer' ".

Now we need to look at the fuller and partly expanded view of the whole solution (as simple as it is) :-

===============================================

See how we have the main project (the first one created) in Vulcan.NET, and the class library ('CL')

itself which is written in C# .NET.

In order to use the C# classes from the library project we need to reference the 'CL' as seen below :-

=======================================

====================================================

Cyclic / Circular Referencing - "WRONG" :

PHH - 6th. & 13th. January 2015.


Designing and making the Database classes

Quite simply 'put' - this is the most important thing to get right in our EF applications.

You may worry at first about LINQ, but that becomes easier and more common place as we use it.

If we design and make our 'Entity' structure and mapping poorly, then the application will be struggling form word 'GO'.

Spend some time and some 'testing' to check that you have a suitable and workable EF 'set-up'.

Take some time to learn a few tricks etc..

PHH - 6th. January 2015.


our DB Classes - as simple as they can be

Please note that it is probably a good idea to put in place all of the required Classes, even

if we only define one or two of the main properties.

The idea will be that we can re-visit them later and 'flesh out' all of those properties that we will

eventually need for the running of our application.

==========================================================

=================================================================

===================================================================

==========================================================================================

==========================================================

======================================================================================================

==============================================================================================================

===================================================================================================================

PHH - 7th. January 2015.


'Configuration' - an extra layer for our DB Classes

So far you may have come to the conclusion that with EF and CF Code First') we can make a

back-end SQL database (tables and all) without actually doing much, or anything ;-0)

Guys with some SQL experience can certainly be excused for this !

However, EF & CF have given us a simple default group of settings to make things easy.

But, there are times when a developer / designer wishes to have some extra control over what

happens at DB creation time, and what properties and settings are 'set' on the Tables and Columns etc..

Here is where the "Configuration" comes into play.

In order to get an idea of all of this 'stuff' we can look at a working application I did just after the 2012 Olympics

in London, UK.

To get us in the mood, here are a couple of interesting images of the demo application in action :-

[ .. first the main screen .. ]

============================================================

And now the Nation entry screen after selecting the second option above :-

Check out the following details :-

===================================================================================================

Yes, we can select flags for nations, we need small and large flag icons.

Okay then folks, after a few nice colourful images lets look at a simple example of a .NET class in my

Olympics2012 sample. Lets try the 'Event' class - checkout below in detail :-

===============================================================================================

"Okay!", I here you say, "not much different to what we have seen in the simple approach" - but wait,

there is more to it that the above.

Let us now see how we can define and apply a 'Configuration' for our Event class.

Study the next image details closely :-

========================================================================================

*** I will need to explain the above detail ***

Line 1235 simply means that the name of the Table is to be 'Event' and not the default value of 'Events'.

It also means that the schema is to be 'VL15.' in place of the default of 'dbo.'

The other lines are also simple enough when explained. 'e' stands for an 'Event' object, and so we can

define any of the properties of the Event class with certain available settings and restrictions.

Line 1237 is an obvious one which restricts the string length for the maximum entry size.

On lines 1236, 1239 and 1240 this is saying the column entries can' be 'null'.

The final one to explain above is line 1238, in which we are specifying a column name in the DB which is

to be different from the property name used in the class definition.

So to summarize, we can set the Table and Column names as we wish, and specify and restrict other

settings for each of the Table columns.

Here is another way to think of it - the main Class definition specifies the details of the 'O' bit of the ORM mapping,

whereas the Configuration class for the main Class specifies the details of the 'R' bit of the mapping.

Configuration is about the Relational part of the EF mapping.

Configuration for Tables, main Class definition for Objects !!!

HOWEVER, not so fast .... if we do not apply our configurations then nothing will happen with the Tables settings.

So how do we apply the configurations ?

Here is the example from my Olympics application - don't worry about the number of additions - take one and

examine it thoroughly :-

=================================================================================================

[ .. we will discuss line 1223 at a later stage .. ]

So if we look at the 'DbContext' class we see the following, and line 1209 is what we are really needing

to check out :-

====================================================================================================

Moving on to our Vulcan.Live.15 example, we need to apply some of the above ideas to

the simple Classes we saw in the last sub-section.

Lets start with the Presentation class, here is the required Configuration, or most of it, we will

probably develop it as we go along :-

===============================================================================================

=============================================================================================================

===================================================================================================

====================================================================================================================================================================================

===================================================

====================================================================================================================================

PHH - 7th. January 2015.


Choosing a bunch of 'Views'

==========================================================================================

=====================================================================================

============================================================

========================================================================================

===============================================================================================================

==========================================================================================================

==============================================================================================

================================================================================

=========================================================================

==============================================================================

====================================================================================

============================================================================================================================

=========================================================================================================================

=====================================================================

PHH - 6th. & 15th. & 16th. January 2015.


Exploring a simple data entry technique

By "Data entry technique" we mean adding new rows to tables via creating new in-memory objects and

have the Entity mapping save are the new details to the correct tables.

Obviously data entry works at a level of one 'Custom' object at a time, but depending on the mapping and the complexity

of the object class, this may produce more than one row in related tables.

"So data entry is object and row(s) addition - 'Add' "

*** Note *** we need to appreciate the differences and similarities between 'Add' and 'Attach' when we use language

and terms related to the 'Entity States' in the child section from here.

[ .. think of >> Added, Modified, Deleted .. as opposed to >> Attached & Detached .. ]

From our VERY simple View called 'RegistrationView' we can add a new row to our DataGrid display - see below :-

==========================================================================================================================

Above I have ignored the first column, the identity, and edited all of the other fields / cells.

When we do this (double click in the Firstname cell), we get a new object of the Registration class created by the

empty constructor for that class. See below to see the default cells / properties entries / values :-

=======================================================================================================================

The above is one reason why we always need to provide an empty Constructor in our Custom classes.

When we double click a new collection item (object) is created with the empty Constructor and then added to the collection.

As we move through the cells and enter / edit data values the object properties are updated with the new values we can

see on screen.

Eventually, the new row looks like that in the following image - but remember we have not been anywhere near the first column,

the one for identity.

When we improve this data input screen we will make the ID column non-editable - or that is the plan ;-0)

Check this out thoroughly :-

=====================================================================================================================

So now when we close the window the new details will be saved, as we have a suitable 'Window_Closing' even handler.

Below was a real test where I displayed the 'Count' value of the underlying collection :-

======================================================================================================================

When we get our code right, we can open the same View from the main screen and the data is re-read from the SQL

database, and the new ID value can be seen below :-

======================================================================================================================

The ID value of 16 was given to John's entry when the 'SaveChanges' member was called on the ConfContext 'DbContext' object.

Now then, lets see a simple but rather 'crude' way of doing this - see lines 38 through 43 shown below :-

[ .. PLEASE note that we can do this in much smarter and EF ways .. ]

===================================================================================================

===========================================================================

=============================================================================

=======================================================

=========================================================================================

=====================================================================================================================================

==================================================================================================================

===========================================================================================================================================

============================================================================================

PHH - 16th. January 2015.


Entity states and 'SaveChanges'

http://msdn.microsoft.com/en-us/data/jj592676.aspx

================================================================================================================================================================

=================================================================================================================

https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449331825/ch04s03.html

======================================================================================================

============================================================================================================================================

===========================================================================================================================================

========================================================================================================================================

Delete / Remove :

=============================================================================================

================================================================================================

========================================================================================================================

=========================================================================================================================

===============================================================

PHH - 16th. January 2015.


Exploring a simple data editing technique

By "Data editing technique" we mean changing property values of one or more properties of the in-memory

object(s) - which were themselves read in from one or more Tables via 'Entity mapping'.

Before the 'editing' takes place, the SQL table rows and the .NET object properties are all in synch - or in agreement with

one another. Once again the Entity mapping system provides the data transfer in both directions, when reading and

when writing back.

So we will typically edit the cell properties of a Data Grid element, which by data binding is actually changing

the property value(s) of an in-memory complex .NET custom object.

Obviously, data editing works at a level of one 'Custom' object property at a time, but one short editing session

at a DataGrid form display can mean that we change many different objects.

All of the changed objects need to be written back to the SQL data source, sooner rather than later I would suggest.

"So data editing is :- object property and row cell (column) value changing - 'Update' is commonly used to describe this"

We are UPDATING entity information.

===============================================================================================================

====================================================================================================

==============================================================================================

===========================================================================================================

======================================================================

============================================================================================

Making Identity column 'Read Only' (R/O) to stop editing :

So far the XAML script for the 'RegistrationView' has been extremely simple - see below :-

==================================================================================================

If we put some work into this so we can define our own columns and their related headers, then we will

be able to give ourselves much more control over the functionality as far as the user interface is concerned.

========================================================================================================================================================================

=====================================================================================================================================

"Sensible Restrictions" - [ Now in Place ] :

Okay then guys, if we can rely on the new entries for Registration 'entities' having a zero (0) valued Identity, and

that existing IDs can't be changed or corrupted, then we can happily use the test condition of the ID being zero to

determine which Entity State is associated with each grid row / collection item.

Here is the XAML script which restricts GUI functionality in the first data grid column :-

====================================================================================================

And now we need to test the input form to see that any mouse activity can't make column one editable, and that

al cells in the first column are always R/O.

Below I have sample output where I have tried my best to access the ID cell, but with no success - the other cells

however, are easily put into focus and editing made possible - check details below :-

==============================================================================================================

Notice above that one full new entry has been made and a second one started.

This now makes good sense that we are using the .NET code shown below, to set entity states :-

=====================================================================================

So all new items added to the collection have their ES (entity state) set to 'Added' whereas all

others are set to 'Modified' which allows small changes to be made to 'stick' !

We can easily change a few details so that the DataGrid could start empty, and only allow new

items to be added, a row at a time.

Simply, the DataGrid is bound to an empty list of type Registration, and not one which has been

filled with a returned list from a LINQ query.

=========================================================================================================

===========================================================================================================

========================================================================================================================================================

PHH - 17th. January 2015.


Exploring a simple data removal technique

By "Data removal technique" we mean deleting existing rows from tables via selecting new 'in-memory' objects and

have the Entity mapping remove the relevant rows from the entity 'mapped' correct tables.

Obviously, data removal works at a level of one 'Custom' object at a time, but depending on the mapping and the complexity

of the object class, this may delete more than one row in related tables.

"So data removal is object 'selection' and then row(s) removal - 'Delete' "

However, at the code (application) end of things, we can select and 'mark' entities (via their 'States') and then only

'SaveChanges' only once. So there is only one query 'trip' to the SQL Server.

Lets start to explore things, one step at a time ..........

Using our Existing 'View' of registrations to help us Explore 'Deletion / Removal' :

While we have our simple 'RegistrationView' class, with a single DataGrid UI control to display collection items,

lets us make some changes and update improvements to it, which will allow us to delete a few chosen items,

while displaying the final results from the SQL database.

To start with we will simply do the selection in .NET code, not interactively. Once we know what we are doing on

Removal / Deletion, then we can move on into the realm of interactivity for our removal selections.

Lets see what we are trying to do - check out the real SQL data from the 'Registrations' SQL table seen below :-

=================================================================================================================================

Checkout the values of the first column, that for identity, note the missing values 2,4,6 and 8.

Yes, you are right, the data seen above was found and displayed in the Visual Studio data related panes,

meaning that the four rows for 2,4,6 & 8 have been removed or deleted.

So what does our application look like just after these changes have been made ? Checkout the following

image to see the 'new look' 'View' for Registrations :-

===================================================================================================================

See the newly placed push button at top left, this is what calls the correct code method(s) to bring about the changes.

PLEASE realise that just because items may disappear from s screen does not say that the relevant tables rows have

been removed at the SQL database end of things. Unless of course we re-read the SQL data and redisplay it.

Changes, of any sort, are only made at the SQL server end when the 'SaveChanges' method is called on the 'DbContext'

object in our application.

In my code 'db.SaveChanges()' is what causes all changes to be made, Additions, Modifications (updates), and Deletions

(removals).

*** REMEMBER *** that when we are doing development changes to our application code we will often need to delete

the actual database itself, this is done from the SSOE pane in VS where we usually view the tables to show their

data contents - like in the first image at the top of section.

Here is a visual reminder of how to get your IDE and application effectively 'unlocked' :-

=============================================================================================================================

Okay then guys, we know we must use 'db.SaveChanges()', but what do we need do to code and related

code settings before we call the changes method ?

The 'States' of our Entities can only be set in a handful of ways - see below to remind ourselves :-

=======================================================================================

For the moment just look at code line 75 to see that the entity (item) to be removed (here called 'item'),

has five states we can set 'on'. Obviously we chose 'Deleted' as seen above.

Any and every item in the DbContext object which is set to state 'Deleted' when the changes are called for, will be removed.

Obviously it is a good idea to make sure the other items are left 'Unchanged'.

Lets move on a step or two .........

Selecting and Effecting our Removals :

Okay folks, what we wish to do is summarized in the next image - shown below :-

================================================================

Remind ourselves :-

===========================================================================================================

We will press a button and then have the four entity items (instances) 'marked' or 'set' from within the Entities in

our DbContext.

Once marked or their states 'set', we can then effect the database changes with the method on the context for 'SaveChanges'.

What we need to remember for Entities :

When we are doing our code work and development with Entities, we need to remember we are dealing with objects and

not data values - so comparisons are different, and we need to be mindful as well as careful.

Remember we can have two separate objects, of the same type and with similar property values - however, they are

not equal or the same object - they have different GUIDs or identities.

So we need to be careful when selecting and comparing, we need to find a method which works and checks out, and

they we need to stick with that method or approach.

Another thing we need to remember while using entities and SQL Tables is that we use IDs to distinguish one row from

another in our EF6 code first database. We must NOT change these ID's once the SQL Server issues and stores them,

and we must not try and issue an ID ourselves - leave then blank or zero and let the SQL server system issue new values

for us when the 'SaveChanges' method is called.

We don't allow users at GUI screens to edit ID's, or try to supply new ones !!!

Let us see what we have working for us :

In the following image we can carefully study what I have managed to get to work for us.

We can then move through it in order and see just what is being done - at each stage.

The first and important thing to notice in the next image are the four lines at 61 - 64 which use one

of our standard static methods to retrieve a single Registration object with a specified ID.

Check out these details :-

===============================================================================================================================

We are specifying the IDs in hard code - on lines 61-64, but then we are retrieving actual objects - 'Registration' objects.

These retrieved objects are then compared directly to those Registration objects in the whole Entity, all of the Registrations.

using FOREACH we cycle through the full set of entity objects of the correct type, and if the found entity object

is one of the specified ones, we mark it for deletion by setting the EntityState :-

===========================================================================================================

Note above how line 68 uses 'Contains' to help do a comparison in an easily 'doable' fashion - no loops etc..

Line 69 is unnecessary but helpful while developing and testing.

Moving on a step further ................

We need to dispose of our local 'DbContext' (context) and create a new one for fresh displaying.

Before we do any data binding or visual display, lets just checkout the basic coding - study this fully :-

=========================================================================================================================

Line 85 shows us that be the time we re-read the SQL database by populating the Entity properties, we have

dropped down to 11 items and rows from the 15 with which we started.

==================================================================================================================

So we can now redisplay the Table in our DataGrid control - see the following image :-

=============================================================================================================

Line 86 above retrieves the refreshed set of Registrations, and binds the data - and so ID's 2,4,6 & 8 are

seen to be missing.

Seeing what is NOT now there !? :

Okay the guys, you know we like to have a bit of fun, so now let us display in the grid on screen, what has

been removed from the SQL database itself - study the next image carefully :-

===========================================================================================================

At least by referencing the SQL database just before deletion, we get the latest state of the SQL Tables before

we attempt to effect a batch removal - so the rows have a better chance of existing.

Yes, I realise that we can improve the above code in quite a few ways, BUT, we have tried at least to keep it

simple so that we can see and understand what is happening.

We will work on a UI way to select entity items in a later sub-section from here.

Time to move on, see you in the next section ......................

PHH - 17th. January 2015.

Addendum : Finding a 'Single' Entity :

Lets explore the possible methods to find a single entity from the whole bunch of Registration entities.

First a solid but 'clunky' approach, followed by a more LINQ and 'smarter' style of approach :-

=============================================================================================

We can further improve and tighten the code in this second approach - see below on line 188 :-

=================================================================================================

Be careful with the combined logic in lines similar to 188, it is tempting to use 'or' / 'OR' / ' || ' in place of

AND (' && ').

We should use something like this last method to find single instances of Entities in future.

PHH - 18th. January 2015.


Speakers 'View' - trying somethings new

==================================================================================================

========================================================================================================================

======================================================================================================================================================

PHH - 18th. January 2015.


Session 'View' - getting it better

=========================================================================

=========================================================================

===============================================================================

=========================================================================================================================================

PHH - 19th. January 2015.


Attendee 'View' - better again !

=======================================================================================================

======================================================================================================================

=================================================================================================================================================

PHH - 19th. January 2015.


HotelReservation - 'View'

==============================================================================================================

========================================================================================================

================================================================================================================================

PHH - 19th. January 2015.


LectureRoom - 'View'

==============================================================================

===========================================================================================

================================================================================

=================================================================================================================================

PHH - 19th. January 2015.


Presentation - 'View'

=========================================================================================================

================================================================================================================

============================================================================================================================

=========================================================================================================================================

PHH - 19th. January 2015.


working script and code - 'Views'

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.RegistrationView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Registration View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgRegistrations"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Reg_Id"

                                    Binding="{Binding RegistrationId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Firstname" Binding="{Binding Firstname}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Lastname" Binding="{Binding Lastname}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Country" Binding="{Binding Country}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="Company" Binding="{Binding Company}" Width="70" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Paid" Binding="{Binding HasPaid}" Width="50" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Newbie" Binding="{Binding IsNewbie}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Cost" Binding="{Binding RegCost}" Width="50" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Speaker" Binding="{Binding IsSpeaker}" Width="Auto" CanUserResize="False"/>

            </DataGrid.Columns>

        </DataGrid>

        <Button Content="Remove 2,4,6 &amp; 8" HorizontalAlignment="Left" Margin="10,10,0,0"

                VerticalAlignment="Top" Width="157" Height="26" FontSize="13"

                Name="pbRemove2468" Click="pbRemove2468_Click" />

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

#using System.Data.Entity   //----- for DbContent / DbSet -----

#using System.Data.Entity.ModelConfiguration

//==========================================

#using ClassLibLinqEF6_CS

//------------------------------------------

begin namespace FullConf_VL15_Linq_EF6_2

    partial class RegistrationView inherit Window

        export db as ConfContext

        export aList as List<Registration>

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            //self:aList := CS_LinqLibrary.ReturnAllRegistrations(db)

            //----- now new entities ONLY ! -----

            self:aList := List<Registration>{}

            self:dgRegistrations:DataContext := self:aList

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            //----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()

        return

        private method pbRemove2468_Click( sender as System.Object, ;

                        e as System.Windows.RoutedEventArgs ) as System.Void

            self:DoRemoveRegistrations2468()

        return

        method DoRemoveRegistrations2468() as void

            local implied db := ConfContext{}

            local implied aListDelete := List<Registration>{}

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 2))

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 4))

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 6))

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 8))

            local cMess := "" as string

            foreach item as Registration in db:Registrations

                if aListDelete:Contains(item)

                    cMess += "To remove :- item with ID = "+item:RegistrationId:ToString()+e"\n"

                    db:Entry(item):State := EntityState.Deleted

                else

                    db:Entry(item):State := EntityState.Unchanged

                endif

            next

            MessageBox.Show(cMess,"Found :")

            db:SaveChanges()

            db:Dispose()

            //--------------------------------

            local implied db2 := ConfContext{}

            MessageBox.Show(db2:Registrations:Count():ToString(),"Our Final, diminished Count 3 :")

            //self:dgRegistrations:DataContext := CS_LinqLibrary.ReturnAllRegistrations(db2)

            self:dgRegistrations:DataContext := aListDelete

        return

    end class

end namespace

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.SpeakerView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Speaker View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding Sessions}" IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgSpeakers"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Spk_Id" Binding="{Binding SpeakerId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="IsNew" Binding="{Binding IsNew}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Reg_Id" Binding="{Binding RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Reg_Id2" Binding="{Binding oReg.RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Country" Binding="{Binding oReg.Country}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Company" Binding="{Binding oReg.Company}" Width="100" CanUserResize="False"/>

                <DataGridTemplateColumn Header="Sessions"

                                        Width="60"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

BEGIN NAMESPACE FullConf_VL15_Linq_EF6_2

   partial class SpeakerView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgSpeakers:DataContext := CS_LinqLibrary.ReturnAllSpeakers(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

END NAMESPACE

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.SessionView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Session View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding Attendees}" IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgSessions"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Sess.Id" Binding="{Binding SessionId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="LectRm.Id" Binding="{Binding LectureRoomId}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="RoomNo." Binding="{Binding RoomNumber}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Pres.Id" Binding="{Binding PresentationId}" Width="50" CanUserResize="False"/>

                <DataGridTemplateColumn Header="Attendees"

                                        Width="100"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class SessionView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgSessions:DataContext := CS_LinqLibrary.ReturnAllSessions(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

end namespace

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.AttendeeView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Attendee View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding Sessions}" IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgAttendees"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Att.Id"

                                    Binding="{Binding AttendeeId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100" CanUserResize="False"/>

                <DataGridTemplateColumn Header="Sessions"

                                        Width="60"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

                <DataGridTextColumn Header="Reg_Id" Binding="{Binding RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Reg_Id2" Binding="{Binding oReg.RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Country" Binding="{Binding oReg.Country}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Company" Binding="{Binding oReg.Company}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="oReg" Binding="{Binding oReg}" Width="90" CanUserResize="False"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class AttendeeView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgAttendees:DataContext := CS_LinqLibrary.ReturnAllAttendees(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

end namespace

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.SessionView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Session View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding Attendees}" IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgSessions"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Sess.Id" Binding="{Binding SessionId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="LectRm.Id" Binding="{Binding LectureRoomId}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="RoomNo." Binding="{Binding RoomNumber}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Pres.Id" Binding="{Binding PresentationId}" Width="50" CanUserResize="False"/>

                <DataGridTemplateColumn Header="Attendees"

                                        Width="100"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class SessionView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgSessions:DataContext := CS_LinqLibrary.ReturnAllSessions(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

end namespace

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.AttendeeView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Attendee View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding Sessions}" IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgAttendees"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Att.Id"

                                    Binding="{Binding AttendeeId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100" CanUserResize="False"/>

                <DataGridTemplateColumn Header="Sessions"

                                        Width="60"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

                <DataGridTextColumn Header="Reg_Id" Binding="{Binding RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Reg_Id2" Binding="{Binding oReg.RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Country" Binding="{Binding oReg.Country}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Company" Binding="{Binding oReg.Company}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="oReg" Binding="{Binding oReg}" Width="90" CanUserResize="False"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class AttendeeView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgAttendees:DataContext := CS_LinqLibrary.ReturnAllAttendees(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

end namespace

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.LectureRoomView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="LectureRoom View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <Grid.Resources>

            <DataTemplate x:Key="ourFirstDTcombo">

                <ComboBox ItemsSource="{Binding Sessions}"

                          IsEditable="False"  IsReadOnly="True"/>

            </DataTemplate>

        </Grid.Resources>

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgLectureRooms"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="LectRm.Id"

                                    Binding="{Binding LectureRoomId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="FloorNo." Binding="{Binding FloorNumber}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="RoomNo." Binding="{Binding RoomNumber}" Width="90" CanUserResize="False"/>

                <DataGridTextColumn Header="Max.Cap." Binding="{Binding MaximumCapacity}" Width="60" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Blackout" Binding="{Binding FullBlackout}" Width="70" CanUserResize="False"/>

                <DataGridTemplateColumn Header="Sessions" Width="80"

                                        CanUserResize="False"

                                        CellTemplate="{StaticResource ResourceKey=ourFirstDTcombo}"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class LectureRoomView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgLectureRooms:DataContext := CS_LinqLibrary.ReturnAllLectureRooms(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

end namespace

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.HotelReservationView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="HotelReservation View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgHotelReservations"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="HRes.Id"

                                    Binding="{Binding HotelReservationId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="IsSpeaker" Binding="{Binding IsSperker}" Width="60" CanUserResize="False"/>

                <DataGridTextColumn Header="RoomNo" Binding="{Binding RoomNumber}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="Nights" Binding="{Binding NumberOfNights}" Width="80" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="OnlyBrkfst" Binding="{Binding HasOnlyBreakfast}" Width="70" CanUserResize="False"/>

                <DataGridTextColumn Header="Reg_Id" Binding="{Binding RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Reg_Id2" Binding="{Binding oReg.RegistrationId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="oReg" Binding="{Binding oReg}" Width="90" CanUserResize="False"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

BEGIN NAMESPACE FullConf_VL15_Linq_EF6_2

    PARTIAL CLASS HotelReservationView INHERIT Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgHotelReservations:DataContext := CS_LinqLibrary.ReturnAllHotelReservations(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

END NAMESPACE

=========================================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.PresentationView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Presentation View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgPresentations"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="HRes.Id"

                                    Binding="{Binding PresentationId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Titel Short" Binding="{Binding TitleShort}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Titel Long" Binding="{Binding TitleLong}" Width="140" CanUserResize="True"/>

                <DataGridTextColumn Header="Experience" Binding="{Binding eExp}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Knowledge" Binding="{Binding eKnow}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Spk.Id" Binding="{Binding SpeakerId}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="oSpk" Binding="{Binding oSpk}" Width="90" CanUserResize="False"/>

            </DataGrid.Columns>

        </DataGrid>

    </Grid>

</Window>

=========================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

BEGIN NAMESPACE FullConf_VL15_Linq_EF6_2

    partial class PresentationView inherit Window

        public db as ConfContext

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:dgPresentations:DataContext := CS_LinqLibrary.ReturnAllPresentations(db)

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            /*//----- yet even newer alternative -----

            foreach item as Registration in self:aList

                if item:RegistrationId < 1

                    self:db:Entry(item):State := EntityState.Added

                else

                    self:db:Entry(item):State := EntityState.Modified

                endif

            next

            self:db:SaveChanges()   */

        return

    end class

END NAMESPACE

=========================================================================================

=========================================================================================

=========================================================================================

PHH - 19th. January 2015.


Making the 'VM's to accommpany the Views

As well all should know by now, each and every 'View' must have a related and properly designed

'ViewModel' which goes with it like a "hand in a glove" !

The VM should have public properties to support data binding in the UI elements of the View.

The VM is then loose coupled to the View in just one simple line of .NET code.

We also should know that the 'Model' is where the data comes from, and this is passed into (or

injected) into the VM at time of instantiation.

So basically business oriented data comes from the Model. Any data originating in the VM itself

is simply there to support the working of the View, usually to promote better interactivity.

So far in this demo application, we have been making data bindings like the one shown below :-

================================================================================================

Above we have bound some returned SQL data (a collection of Entities) directly to a GUI control.

This is not what we should be doing, we need to improve things.

At the moment we have lots of suitable 'Views' - see the next image below :-

==========================================

However, we have only one test ViewModel as yet. Following is the image of the current

state of the SE pane in the demo application :-

================================================

It certainly looks from the above image that we need both Models and VMs adding

into our project.

Lets try out an experiment, to see how we can best use Models based on Entity Framework to

provide our data to a ViewModel.

Let us use the 'PeopleSessions' VM, since we have this already to hand - and because it requires

quite a lot of data.

We can start by seeing just what we are going to display on screen - check this out below :-

=========================================================================================

We are to have four list controls, two drop lists and two fixed list boxes.

Above you can see some detail from each of four separate (and different) collections we have

in memory. Although we have no labels you may be able to tell / detect that we have Sessions,

Presentations, Speakers and Attendees.

We can cross-check this by looking at the XAML script in the following image :-

=============================================================================================

Okay then guys, if we now know what the 'Glove' is like (to you the View), then let us now look at the

hand that goes in it (the ViewModel).

==============================================================================================

Yes, you can tell a few things by studying the code image above.

The VM has four public properties, all List collections, and all are coded to be as shown in line 110, and

that is they are set-up to respond to changes, and send out notification, as we have seen in earlier sections.

*** I do know that as yet our Custom (or Entity) classes do not track changes and send out notification, so

we have to attend to that soon, if we are to show changes properly when we have more complex data binding

scenarios. ***

One thing at a time .......... let us get the basic binding and display sorted out. The changes can be tracked later.

Fine then folks, we have a suitable View and a ViewModel, now we need a Model to finish off the job.

Here is a shot of the SE pane as it is for me in my developing application in VS 2013 :-

==============================================

So what does our Model look like at a code level ?

Well, I have had to copy a previous (working) Model and update it - name and some content too.

Take a careful look at the next image - study it thoroughly :-

========================================================================================

Our new Model simply takes a Constructor parameter of type 'ConfContext' which is of DbContext.

There are four properties, each of which is a List collection - these can be used to assign to similar

properties on the VM.

Look at lines 58 - 61 in the code of the VM, where the Model properties are assigned to VM properties.

Remember, that in reality pointers are being used and not values added afresh etc..

So bindings on the UI elements are passed-through, or linked, to collection data of the Model object.

This all comes together in the code to open and launch the View for 'PeopleSessions' - this is seen in

detail below :-

==================================================================================================

The above lines 52 through 54 are all that it takes to use the Model with a DbContext input, to create

a suitable VM which can then be loosely coupled to the instantiated View.

Simply, all we need is an instantiated 'db' object - as easy as that.

So then guys, if we can do one form with four groups of Entities, then we can do less or more. And, if

we can do collections which are Lists of Entities, then we can do simpler stuff too - single Entities and

also standard data types.

Short Summary :

By now you may realise that SQL databases supplying Table data via EF6 is a great way to provide Models.

From a 'db' (or DbContext) object we can easily create all the property types we need to use at the View surface.

I suggest we get well into LINQ and EF6 and don't ever go back to the old fashioned and more difficult way

of doing things both visual and data wise.

Lets move on to the next section to learn a few more things ;-0) See you there ...................

PHH - 6th. & 20th. January 2015.


Designing and Creating the supporting 'Models'

A short phrase to summarize this sub-section could be said to be "it all depends ! ".

At first site and first thoughts, this may not seem to be helpful - BUT - the way we design our

Models, and how we use our Entity data returned from SQL very much depends on what we wish

to happen at the UI surface.

As we go through this subsection I hope to make it clear just what can be done, and what MUST be

done if we wish to get certain behaviours to take place by user input at a GUI screen.

One BIG consideration is obviously seeing data changes in many UI element attributes at once, and

therefore making sure we create the data collection early enough to use it in Models on many instances

of a View, for example.

This stuff is best shown by example.

One BIG thing to remember is that using a 'db' to return data from a query, only actually takes place when

we try to use the coded data in further code. And that each time we call a STATIC query class the LINQ

query runs again, and hence gets a quite separate return collection object - yes the collection may contain

items with the same values - BUT - that is no help if we wish to have our data bound over more that one

place and / or View element, or indeed many Views.

Enough for now of words, lets see some examples.

========================================================================

===========================================================================================

=======================================================================================

Its all about 'Scope' :

====================================================================================

==========================================================================================

=======================================================================================

=============================================================================================

PHH - 6th. & 20th. January 2015.


Populating / Seeding the SQL database

Particular to using the 'Code First' approach with Entity Framework 6 ( 'EF6' ) we most usually

wish to place data values into our empty Tables after the database has been created.

Commonly, we need suitable test data to be able to verify our code operation.

It is quite a different situation when we inherit an existing database and employ the 'Database First'

approach.

So what do we do if we have a nice new shiny database which has empty Tables ?

Well it is quite simple in many respects, we need some hard coded members which can supply

suitable values to properties of the EF class objects, and then save them into the SQL database.

Usually we will make the effort to code members to provide a handful, or group, of object items for

each of the Tables we have created - remember we have at least one table corresponding to each of

the 'Classes' we have included in the Entity definition.

If however, we also design our classes so that we have a 'Many to Many' relationship, then we will

get an extra Table, which more or less belongs to the 'system'. We will see more on this soon, in our

examples we see below in this section.

Oh! I have to say that there are simpler ways to instigate / launch this initial 'seeding' of data, and they

are slightly 'Smarter' ways to do it using the features of the EF main class based on 'DbContext'.

For a number of reasons, one being the mix of Vulcan and C#, we will first look at and use the more

basic methods or approach. The central part of both is really the same code, so it does not matter

much at all really - it just more convenient to do it the EF way, as you would expect.

Let us start to study the working code I have here on my development machine.

Here is my Initialize method that runs for 'Window1' when the application is launched :-

[ .. check out line 50 in particular .. ]

============================================================================================

Line 50 is all it takes to partly fill each of the Tables in our database.

Obviously, there is more code behind the static member 'SeedAllTables' ;-0)

Lets first of all look at the relevant section of the SE pane - the Vulcan project - check this :-

=====================================

We have a specific folder in which I have grouped all the Vulcan code files for Seeding the

database.

Lets have a look at the first one - study the following details :-

=======================================================================================

[ .. above we have a list of Sessions being returned, and this is added into the Table on lines 58/59 .. ]

In the above image the static member 'SeedAllTables' actually just calls a bunch of seven similar

members, all static.

If you look above at lines 57 through 60 you will see one specifically for 'Sessions', but the other

six are all virtually the same - nearly identical !?

*** Note *** that each 'seed' method sends its changes to the SQL Server, to update the relevant Tables,

before the next 'seed' method is called. Hopefully that will mean that we have data in place which may be

required for the next 'seed' request.

*** You need to CAREFULLY work out the order of the Table 'seeding' ***

So we really need to examine the 'PopulateSessions' static member to see what is going on :-

[ .. this is the most complex of what we have in this database example for 'Conference Cologne' .. ]

===================================================================================

The above code forms a method which given the DbContext object, forms a short list of two

items which are Session items.

However, because of the Entity design, we also need to find and use existing and correct Attendee

objects, we can examine the 'FindSingleAttendee' method later / soon.

First lets remind ourselves of the format / structure of the Session class definition, check below :-

================================================================================

Obviously, we are currently using the third Constructor, that on line 163 through 169.

As you can clearly see it requires a list of Attendee items line 168.

If we examine the Table structure made for us by the EF 'Code First' system, we can

see below that we appear to have an extra foreign key (FK) column - see the last one shown below :-

================================================

In fact this extra column has been made by the system because we have a "many to many" relationship

between Sessions and Attendees.

This is the only 'Many-to-Many' relationship we have for the 'Conference Cologne' application. More on this

later, as well as a tip or two on how to read the data.

Now we need to look at how we use LINQ in the C# Class Library to find suitable and existing Attendee

object items. Study the next image thoroughly - notice we are searching for identity values :-

===============================================================================

So the result returned by the above code is either the item with identity ' nId ' or a default item.

The bunch of members which find single items by Id are grouped together in the library - see below :-

=======================================

Okay then guys, lets move on ......................

Lets see what we get when we run the full 'seeding' member at start-up time. Lets first see the

Sessions table - check below :-

===========================================================================================

If you look up the values shown in the cells above, you will see they match those in the 'seed' code.

Because a Session refers to a group of Attendees, we need to check that Table for details too :-

========================================================================================================

Okay folks, that looks fine and dandy - BUT - we need to move on and discuss 'many to many' !

"Many to Many" - what is this !? :

Well first of all lets look at the SQL Table structure in the SSOE pane, as well as the data values :-

============================================================================================================

How do we read the data grid / table ? That seen above and to the right.

Ever heard of a 'look-up table' ?

We can read the above data grid in two ways - basically the grid comes in between the two main tables

of Sessions and Attendees - and we can go from either one and then move to the other.

It can tell us the group of sessions that any one attendee is planning to visit - OR - the group of attendees

that are booked in to see and experience a particular session.

Both of these ways of reading the 'SessionAttendees' table data is correct and useful.

Lets see which parts of the class definitions bring about this database structure.

First the Attendee class - line 177 is the crucial one :-

=====================================================================

And for the Session class we have below the line 144 which is crucial :-

=========================================================================

Notice that most of this is under the hood for us developer guys, we just use the Entity and build

objects, assign their properties, and save the changes using the DbContext object.

The reason we have added all the extra explanation above, is because we need to know something

about where the extra Tables comes from, why, and what it does for us and our application.

Lets do one more thing on 'M2M' - "Many-to-Many" ...........

A final fancy (and interesting) test of our 'Many-to-Many' :

Okay then guys, get to think on this situation !

When we seed the Attendees table with some data rows, we are not supplying any Session objects.

Here, shown below, is an example of an Attendee being created for the list to be added.

Check out these details :-

================================================================================================================================

In the above code the Constructor being used is the following one - one which supplies an empty list

for the class 'Sessions' property - check below :-

=================================================================

However, when we now try the code in the next image, we see that Attendee with identity 'ID' of six ( 6 ) is

shown to have one session 'to his name' - line 51 returns the attendee with the chosen identity :-

============================================================================================================================================

This can be seen to be correct if we 'cross-check' the Session seeding code - see highlighted

line in the following image :-

===============================================================================

And if we display another property of the same Attendee then we see some more 'confirming' information.

Check the next set of details :-

======================================================================================================================================================================

Yep! - presentation identity '3' is what we hard coded - see both two images above, and one below :-

=====================================================

So to summarize, in a 'M2M' relationship data can be added from either ends of the relationship.

Here we can supply attendee information via a Session entry, or session information via an Attendee entry.

Lets move on ...............

Is it Always this Complex ? :

No, we can often have much simpler relationships in our Entity and its mapping.

"Many to Many" is common but not that frequent. One to many is much more frequent.

However, the 'Seeding' can be even simpler, as shown below - where all class properties are standard data types :-

===================================================================

If you look closely at all the above data types then you see that none are business objects based

on other Tables - just standard .NET data types.

So the Registrations table does not have a relationship with any other, it stands on its own.

Notice the lack of the word 'virtual' in the property definitions. Virtual means a relationship exists.

Lets look at something a little more complex, lets check out 'HotelAccommodation' class - see below :-

=======================================================================================

Looking carefully at the above code we see on line 256 the qualifier 'virtual', but it appears in the

list only once. So we do have one relationship.

Since the property type is NOT a list (or collection) the relationship is 'One to One'. Registration

to HotelReservation.

Moving on to something a little more complex, we can look to the Speaker class definition - check below :-

===========================================================================

Looking carefully at the properties definitions we see the 'virtual' qualifier twice, so we have two relationships.

On line 109 we have code to specify a one-to-one with Registration, and on line 107 a list type which means

we are likely to have a 'one-to-many' with a Relationship with the Sessions table.

Note that we can only determine that the relationship is or isn't 'M2M' by checking the code for the Session

class definition. In the following image there is no 'virtual' entry for Speaker, so it is 'One to Many' - check this :-

============================================================================

What we really need is a full Class diagram for our "Conference Cologne" application database.

Lets see if I can find where to do this in VS 2013, or even Management Studio.

PHH - 6th. & 14th. January 2015.


Adding more user interactivity in the Views

Okay then guys, let us make a new 'View' which will allow us to 'Add' more Registrations into our

existing SQL database, built on the improved demo application for the Cologne Conference.

Once we have the 'Add' facility working we will then look at possible ways to allow editing of existing

Registration 'entities' - that is we will be able to update them.

We may even look into a third possibility, that to remove entities.

Personally, I dislike the idea of removing / deleting data, and MUCH prefer to make items and entities

'inactive. To do this we do need an Inactive property and column, as well as one to record the data and time

the row / item was made inactive.

For now lets focus on Add and Edit as these are VERY important to all applications.

We will also use the 'UserControl' ( 'UC' ) approach in our new View. This will allow us to use one main Add-Edit form,

or window, and to switch in and out different UCs into the containing 'ContentControl' UI element.

We often see UCs used frequently in today's world of Tablet app development, and I feel this approach has been

neglected somewhat for desktops - maybe because of lack of knowledge ?!

Before you read and study this subsection, go to 'Chapter 9' and study the information therein on UserControls.

PHH - 6th. & 24th.January 2015.


Testing out the screen data input, saving, and re-display

PHH - 6th. January 2015.


working script and code

PHH - 6th. January 2015.


SQL data - in and out, and changes saved etc.

*** CARE ***

In the 'section text' following, we need to realise that we can have an apparent 'item' equal to another item in

a related list / collection - BUT - for purposes of identification (and removal) within the SQL database we need

to have an exact returned copy - NOT one which has been passed / copied through from one object to another.

You will get the idea by reading and studying the working code of the part sample shown below - check it out :-

======================================================================================================

And obviously we need to be able to study the code from the C# Class Library - that for 'FindSingleRegistration2'.

Here it is for you to examine closely, along with a simple alternative :-

===========================================================================================

Any existing Registration table row should have an identity which is unique and is greater that zero.

Below is a less elegant (or smart) way of doing the same coding task :-

=============================================================================================

Moving on ..............

You need to study the above code carefully, and try to think it through, keep thinking of this as you read and

examine the rest of this section - its easy when you get the hang of it - or get the idea !!

=============================================================================

Lets move on ....................

When we come to using Entity Framework - EF6, and the 'LINQ to Entity' technology, there is a

slightly different way of saving changes back to the SQL database, from changes made on screen

within a DataGrid for example.

At first it seems more 'fiddly' or 'complex', but actually the newer approach for 'L2E' gives us as developers

far more flexibility, or even 'control' in what we do with our collection items.

Before we study how to save our changes, inserts, and updates, back to the SQL database using 'L2E', we

need to remind ourselves of what we did in the earlier (and possibly simpler) 'L2S' technology.

How it was done for 'L2S' - (DB changes) :

The whole process in 'LINQ to SQL' was built around the 'SubmitChanges()' member - see below for

a suitable example from Chapter 13 :-

========================================================================================

The object on which this member was being called is one instantiated as in the following image code :-

===================================================================================

The returned 'query' was coupled to the 'DataGrid' UI element, for simplicity and demonstration, and this

can be seen clearly below :-

[ .. normally for the MVVM pattern we would make one 'loose' coupling to the form, with the ViewModel object .. ]

========================================================================

Any changes made at the surface of the DataGrid would then be saved back to the back-end data source.

This includes rows removed, rows newly added, and any cell detail changed by the user.

When we move to L2E (LINQ to Entity) we do things differently, there is no 'SubmitChanges()' member.

How it is done for 'L2E' - (DB changes) :

Let me say right from the beginning that we have much 'finer' control over collection items which we wish to

have 'changed' - we will use the term 'changed' to mean all three of Add, Delete and Update (or modify).

We can by business code logic set a state for 'Entry' on each and every item in the collection.

The way we see and change the 'entry state' is via the 'State' property associated with the individual item.

So the item 'State attribute can be changed to on of a bunch of 'EntryState' enums values - see below for

a real working bit of sample code :-

===========================================================================

And now we need to see what the possible options are - check these out :-

=======================================================================================

Before we make any changes for ourselves, the default setting is apparently 'Unchanged'.

I think we need to investigate the 'Detached' option more thoroughly ;-0) meaning I am not sure

myself at the moment as to how we use this to good effect.

Lets keep going, and examine a bunch of items with a default (and unchanged) state.

Here is my working sample :-

========================================================================

And finally for this short 'knowledge' section, the following image shows some working code from a member

which removes items from the DB which have been selected for deletion - check the details :-

======================================================================================================

Above we are identifying items to be removed from the SQL database from a list compiled in some way from

UI elements and our screen interaction. There a a few ways we can do this on-screen.

For now just realise that we can get lists of items needing deletion, with which we can compare the returned

items, and set states accordingly.

So what about the code to find out what the 'state' settings are ?

Check below to see how this is done :-

================================================================================

The next image shows the Registration screen where all that has been done is one extra row has been

manually added by me the user - study the details carefully :-

===========================================================================================================

And now the code which sets the states - see lines up to number 52 :-

============================================================================

Look at the above code - lines 54 - 58 and 62 - 66, these are on either side of a 'SaveChanges()'

method call.

The following two images show how the call to 'SaveChanges' resets the entry of the 'EntityState'

back to the default value - of 'Unchanged' :-

=========================================================

And finally, we can see the newly 'refreshed' table data from the Registrations Table after we have

selected the 'Remove 2,4,6 & 8 button - check these details carefully :-

[ .. look for RegId values of 2, 4, 6, and 8 .. ]

======================================================================================================

Time to move on .......................

Lets go to the next subsection and make some working code of our own from scratch.

The working code and script for these samples are in the child section from here.

PHH - 2nd. January 2015 & February 28th. 2015.


working script and code

===========================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//----------------------------------

#using System.Data.Entity   //----- for DbContent / DbSet -----

#using System.Data.Entity.ModelConfiguration

//==========================================

#using ClassLibLinqEF6_CS

//------------------------------------------

begin namespace FullConf_VL15_Linq_EF6_2

    partial class RegistrationView inherit Window

        export db as ConfContext

        export aList as List<Registration>

        export lRemoved2468 as Boolean

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        public method Initialize() as void

            self:db := ConfContext{}

            self:aList := CS_LinqLibrary.ReturnAllRegistrations(db)

            self:lRemoved2468 := false

            //----- now new entities ONLY ! -----

            //self:aList := List<Registration>{}

            self:dgRegistrations:DataContext := self:aList

        return

        private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

            //----- yet even newer alternative -----

            if !self:lRemoved2468

                foreach item as Registration in self:aList

                    if item:RegistrationId < 1

                        self:db:Entry(item):State := EntityState.Added

                    else

                        self:db:Entry(item):State := EntityState.Modified

                    endif

                next

                //-----------------------------------------------------------------

                local cMess := "" as string

                foreach item as Registration in self:aList

                    cMess += self:db:Entry(item):State:ToString()+e"\n"

                next

                MessageBox.Show(cMess,"Our Listed States :")

                //-----------------------------------------------------------------

                self:db:SaveChanges()

                //-----------------------------------------------------------------

                cMess := ""

                foreach item as Registration in self:aList

                    cMess += self:db:Entry(item):State:ToString()+e"\n"

                next

                MessageBox.Show(cMess,"Our Listed States :")

                //-----------------------------------------------------------------

            else

                //-----------------------------------------------------------------

                local cMess := "" as string

                foreach item as Registration in self:aList

                    cMess += self:db:Entry(item):State:ToString()+e"\n"

                next

                MessageBox.Show(cMess,"Our Listed States :")

                //-----------------------------------------------------------------

            endif

        return

        private method pbRemove2468_Click( sender as System.Object, ;

                        e as System.Windows.RoutedEventArgs ) as System.Void

            try

                self:DoRemoveRegistrations2468()

            catch oEX as SystemException

                MessageBox.Show(oEX:Message,"my Error Remove-2468 :")

            end try

        return

        method DoRemoveRegistrations2468() as void

            local implied db := ConfContext{}

            local implied aListDelete := List<Registration>{}

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 2))

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 4))

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 6))

            aListDelete:Add(CS_LinqLibrary.FindSingleRegistration2(db, 8))

            local cMess := "" as string

            foreach item as Registration in db:Registrations

                if aListDelete:Contains(item)

                    cMess += "To remove :- item with ID = "+item:RegistrationId:ToString()+e"\n"

                    db:Entry(item):State := EntityState.Deleted

                else

                    db:Entry(item):State := EntityState.Unchanged

                endif

            next

            MessageBox.Show(cMess,"Found :")

            //-----------------------------------------------------------------

            local cMess2 := "" as string

            foreach item as Registration in self:aList

                cMess2 += self:db:Entry(item):State:ToString()+e"\n"

            next

            MessageBox.Show(cMess2,"Our Listed States :")

            //-----------------------------------------------------------------

            db:SaveChanges()

            self:lRemoved2468 := true

            db:Dispose()

            //--------------------------------

            local implied db2 := ConfContext{}

            MessageBox.Show(db2:Registrations:Count():ToString(),"Our Final, diminished Count 3 :")

            self:dgRegistrations:DataContext := CS_LinqLibrary.ReturnAllRegistrations(db2)

            //self:dgRegistrations:DataContext := aListDelete

        return

    end class

end namespace

===========================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.RegistrationView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Registration View :" Height="400" Width="675" Closing="Window_Closing">

    <Grid >

        <DataGrid Margin="14,49,13,5" ItemsSource="{Binding}"

                  Name="dgRegistrations"

                  AutoGenerateColumns="False"

                  Background="AliceBlue"

                  AlternatingRowBackground="BlanchedAlmond"

                  AlternationCount="2"

                  CanUserReorderColumns="True"

                  CanUserResizeColumns="True"

                  CanUserAddRows="True" >

            <DataGrid.Columns>

                <DataGridTextColumn Header="Reg_Id"

                                    Binding="{Binding RegistrationId}" Width="70"

                                    CanUserResize="False"  IsReadOnly="True"/>

                <DataGridTextColumn Header="Firstname" Binding="{Binding Firstname}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Lastname" Binding="{Binding Lastname}" Width="100" CanUserResize="False"/>

                <DataGridTextColumn Header="Country" Binding="{Binding Country}" Width="80" CanUserResize="False"/>

                <DataGridTextColumn Header="Company" Binding="{Binding Company}" Width="70" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Paid" Binding="{Binding HasPaid}" Width="50" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Newbie" Binding="{Binding IsNewbie}" Width="50" CanUserResize="False"/>

                <DataGridTextColumn Header="Cost" Binding="{Binding RegCost}" Width="50" CanUserResize="False"/>

                <DataGridCheckBoxColumn Header="Speaker" Binding="{Binding IsSpeaker}" Width="Auto" CanUserResize="False"/>

            </DataGrid.Columns>

        </DataGrid>

        <Button Content="Remove 2,4,6 &amp; 8" HorizontalAlignment="Left" Margin="10,10,0,0"

                VerticalAlignment="Top" Width="157" Height="26" FontSize="13"

                Name="pbRemove2468" Click="pbRemove2468_Click" />

    </Grid>

</Window>

===========================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

    partial class Window1 inherit Window

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

    end class

end namespace

===========================================================================

<Window x:Class="FullConf_VL15_Linq_EF6_2.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Full Conf. (two) :" Height="420" Width="500"

        Background="Beige">

    <Grid>

        <Grid.Resources>

            <Style TargetType="Button" >

                <Setter Property="Width" Value="133"/>

                <Setter Property="Height" Value="26"/>

                <Setter Property="FontSize" Value="13"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

            </Style>

        </Grid.Resources>

        <Button Name="pbRegistration" Content="Registration"   Margin="10,10,0,0"

                Click="pbRegistration_Click"/>

        <Button Name="pbSpeaker" Content="Speaker" Margin="10,41,0,0"

                Click="pbSpeaker_Click"/>

        <Button Name="pbSession" Content="Session"

                Margin="10,72,0,0" Click="pbSession_Click" />

        <Button Name="pbAttendee" Content="Attendee" Margin="10,103,0,0"

                Click="pbAttendee_Click"/>

        <Button Name="pbLectureRoom" Content="LectureRoom" Margin="10,134,0,0"

                Click="pbLectureRoom_Click"/>

        <Button Name="pbHotelReservation" Content="HotelReservation" Margin="10,165,0,0"

                Click="pbHotelReservation_Click"/>

        <Button Name="pbPresentation" Content="Presentation" Margin="10,196,0,0"

                Click="pbPresentation_Click"/>

        <Button Content="PeopleSessions" HorizontalAlignment="Left" Margin="10,243,0,0"

                Name="pbPeopleSessions" VerticalAlignment="Top" Width="133" Click="pbPeopleSessions_Click" />

        <Button Content="UCs Attendee" HorizontalAlignment="Left" Margin="10,295,0,0"

                Name="pbUCsAttendee" VerticalAlignment="Top" Width="133" Click="pbUCsAttendee_Click"/>

    </Grid>

</Window>

===========================================================================

// Window1_Part2.prg

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using ClassLibLinqEF6_CS

begin namespace FullConf_VL15_Linq_EF6_2

partial class Window1 inherit Window

    public db as ConfContext

    public oPSM2 as PeopleSessionsModel2DB

    public aListA as List<Attendee>

    public method Initialize() as void

        self:db := ConfContext{}

        if self:db:Database:Exists()

            self:db:Database:Delete() //----- no need if we use SSOE function -----

            self:db:Database:Create()

            if self:db:Database:Exists()

                SeedTables.SeedAllTables(db)

            endif

        else

            self:db:Database:Create()

            if self:db:Database:Exists()

                SeedTables.SeedAllTables(db)

            endif

        endif

       /* try

            //SeedTables.SeedAllTables(db)

        catch oEX as SystemException

            MessageBox.Show(oEX:Message,"my Main Error :")

            MessageBox.Show(oEX:InnerException:Message,"my Main Inner Error :")

        end try*/

        //-------------------------------------------

        self:oPSM2 := PeopleSessionsModel2DB{db}

        self:aListA := CS_LinqLibrary.ReturnAllAttendees(db)

    return

    private method pbUCsAttendee_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        //-----------------------------------------------------

        local implied oxAttUCs := xAttendeeUCs{}

        //oxAttUCs:DataContext := PeopleSessionsViewModel{self:oPSM2}

        oxAttUCs:Show()

        //-----------------------------------------------------

    return

    private method pbPeopleSessions_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        //-----------------------------------------------------

        local implied oPSV := PeopleSessionsView{}

        oPSV:DataContext := PeopleSessionsViewModel{self:oPSM2}

        oPSV:Show()

        //-----------------------------------------------------

    return

    private method pbRegistration_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oRegV := RegistrationView{}

        oRegV:Show()

    return

    private method pbSpeaker_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oSpkV := SpeakerView{}

        oSpkV:Show()

    return

    private method pbAttendee_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oAttV := AttendeeView{self:aListA}

        oAttV:Show()

    return

    private method pbLectureRoom_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oLectRV := LectureRoomView{}

        oLectRV:Show()

    return

    private method pbHotelReservation_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oHRV := HotelReservationView{}

        oHRV:Show()

    return

    private method pbPresentation_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oPresV := PresentationView{}

        oPresV:Show()

    return

    private method pbSession_Click( sender as System.Object, ;

                    e as System.Windows.RoutedEventArgs ) as System.Void

        local implied oSessV := SessionView{}

        oSessV:Show()

    return

end class

end namespace

===========================================================================

PHH - 28th. February 2015.


SQL data - in and out (Part two)

PHH - 28th. February 2015.


Using an 'Entity' compared with 'Linq to SQL'.

You guys may get your heads around 'LINQ to SQL' as compared to 'LINQ to Entity' if we make a few

simple statements and comparisons - then go away and have a good 'think' !.

In the old days of ADO.NET programming, when we did all the code stuff ourselves in .NET, we often

had many code classes, and hence in-memory objects, which were basically a 100% 'one-to-one' image

of the Table structure.

Commonly, we would have a class to 'mirror' each and every Table in the SQL database.

Then came along 'LINQ to SQL' and nothing much changed on this structure, or design front, except that

we did not need to script in T-SQL any more, and we could only use .NET data types - a huge step in

itself, but not much / any change on the .NET object side of things.

Okay, we did sometimes make in-memory class objects which were built on the basic Table objects, but

we would have to do the data transfer from the basic class objects to the more complex business related

objects.

Because we had to do all the coding work we often kept things as simple as we could, and our business

'data' classes would often fall short (not be as good) of what we would really like to have.

Now then, along came 'LINQ to Entity' and the Entity Framework itself. This changed things all around,

and quite completely as well ;-0)

What do I mean by this ? It is far more fundamental a change that it at first looks!

Remember ORM ? - object relational mapping !

And that 'O' was for the objects in .NET (in our case) and 'R' was for the flat tables in a relational database,

SQL Server in our case.

When we use the technology of 'LINQ to SQL' we focused on the 'R' side of things - we basically designed the

data tables, and at the point of reading data in our applications, brought table data structure across into

our applications as 'R' based objects.

Now with Entity Framework, and 'LINQ to Entity' technologies, we can forget the 'R' side of things and very

much focus on the 'O' side of things. Right from the start we can 'think objects', and more than that, we can

think deep and nested objects, objects within objects.

If we design and code such nested objects, then the Entity Framework takes care of translating data in

populated objects into rearranged data in flat Tables in the relational database - not just the data types this

time, but also the splitting up of data values from the object properties into rows of values in one or more

SQL Tables.

Effectively, if we use Entity Framework correctly, we can almost forget a Tables and SQL data types and rows

altogether. Nearly, but not quite, perhaps ;-0)

So if we design a Customer class in .NET to have a property which is a list of 'Order' items, then each item is

itself of a complex type called 'Order'. The Customer class can also have a property of 'ProductsUsed' which

is a list of 'Product' items the customer uses. Whereas the 'Order' class can have a property of 'ProductsOrdered'

which is a list of all products involved in the single order.

It is quite easy to get quite complex in our design and requirements - we would not have done this using 'LINQ to SQL'.

*** REMEMBER *** EF6 and Code First will do all the hard work of setting up the mapping, and making sure

that when data is moved in and out of the SQL Database it keeps to this mapping it made for us.

All we need do is correctly instantiate a complex object like a 'Customer', assign it the Orders list and the products

list, (and producst list in each Order) and then simply call the 'SaveChanges' method on the 'DbContext' (EF) object.

Yep! - believe it or not, it is as simple as that ;-0))

I told you the EF was a major step forward in using SQL Server with .NET - oh! and remember, you can select to use

other flavours of SQL Server if you so wish - not the case with 'LINQ to SQL' however.

Short Summary :

Using EF allows the developer to bring his whole mindset over into .NET and leave behind for good the world of the

relational database and its data types.

The developer can think and design in a world of complex and nested object classes, and let the EF technology

take care of the O to R mapping, which at runtime takes physical care of the data transferred from back-end

data source into in-memory objects. We can as developers now work with collections of in-memory objects, and

think only of the collection items and not their supporting Tables.

PHH - 2nd. January 2015.


Improving our Entity classes - adding change notification

Okay guys, time to get serious about the full details in our Entity class definitions.

So far the classes we have defined have worked well for us as far as the performance at the SQL

server end of things - meaning that we can create a database with appropriate tables and seed

sample data, as well as read data back vis LINQ queries.

So we have taken care of the 'relational' side of things in our class code definitions.

What we now need to address is the public properties side of things, such that Property Change

notification is sent each time any of the public properties has its value (or content) changed.

We have seen how to define responsive Custom classes previously in these eNotes, so let us use

the same approach and make the Entity classes work as well for us when it comes to data binding.

Here is one of our Entity classes (Attendee) as it is at this very moment - check it out :-

===========================================================================

The above code is as simple and as straightforward as it comes - it does the Entity part a-okay!

The first thing we need to put right :

We can see from the next few images, that although the View displays apparently just fine, when we

attempt to make on-screen changes, things start to go wrong.

First lets see how we launch the 'Attendee' View from the main screen push button - check below :-

================================================

The click of the button is all it takes to show the next image detail - well, in fact I have clicked the push

button twice to be precise ;-0)

Because the 'Show' method is being used, and not the 'ShowDialog', we can get more than one instance

of the 'Attendee View' on screen.

Checkout the following image - noting that 'Murdoch' has been edited and replaced with 'Murray' :-

=================================================================================

Even when the focus is moved from the row 5 grid line to another, the change is not seen in the second

instance of the View.

Here is another example, where we edit the first row 5 Name detail - check thoroughly :-

==========================================================================

So we need to find out why this is and also how to make changes to allow responsive interaction to take

place in our data bindings.

Lets look at how we instantiate a View object - check the following code :-

=========================================================================================

Notice above that we are not finding and supplying any data objects before instantiation.

In fact the data collection is being read from the SQL database each time we instantiate, so we get

separate collections, one each behind every View for Attendee.

The image below shows how we were doing it before I made the necessary changes - see line 44 below :-

=============================================================================================

So when we launch each Attendee View we get back from the database a separate collection, even though

the individual data values and property values may be similar (identical?).

Let us improve the 'Scope' of the data object we are going to use on screen.

If we make a returned list of Attendees at the main window level of things, then we can use this single object

each and every time we instantiate an Attendee View object - hence there will be sharing of the data or item

collection.

Study the new code and scoping seen below :-

===============================================================================

Now that we have seen above that we have one listed data collection object, how do we share this

across each instantiation ?

It is quite simple, see below have we 'inject' or pass, the data into the Constructor for the new form/window :-

=========================================================================================

We will need to change the Constructor code to accept such an object, but first lets see some

suitable success - check below :-

=========================================================================

Remember that we need to move 'off' the row in focus in a DataGrid control for the changes to be seen

elsewhere.

Also remember in the above example that we are using DataGrids, and these seem to be more successful

in passing on data changes than other controls like list boxes.

Meaning that we have solved one 'scope' issue but need to realise we are not 'out of the woods' yet ;-)

For the moment, lets look at the code change we needed to make to our Constructor(s) - check below :-

===========================================================================================

The above code has been responsible for the earlier image of two screens and duplicated editing, but with

only data grid controls in use.

Lets now go to using the more demanding ListBox control in our screen, along with a DataGrid control in

the same window.

Here is the binding, or slightly loose coupling :-

====================================================================

So each UI element displays the same data collection.

Lets look at the XAML for the new ListBox :-

============================================================================================

And launching and running the application shows the following :-

=========================================================================================================

So lets see what happens when we edit the Name in row 5 of our DataGrid - study carefully :-

========================================================================================================

Even moving the focus in each control does not allow us to see 'Murray' in the ListBox.

First of all we need to remember just what is being displayed in our list - since we have no DataTemplate

defined the system is using the 'ToString' method we defined in our Entity class - check this out :-

================================================================================

So to be sure that it is not this which is causing our issues / problems, we will eventually define a template.

For the moment however, we will proceed to add the extra code to the Entity class definition - that for Notification :-

================================================================================================

In the above code image note that we do not change the 'virtual' entries - leave them as they were.

Also don't make any fields for these either !

Notice in the above new (updated) code that we have the interface added, and its event, and also the 'Notify...'

method as well.

[ .. NPC == 'NotifyPropertyChanged' .. ]

Along with the NPC method call in each SET of the public properties, these code additions make the Entity class

work correctly with data binding when we have code changes - both from UI interaction, as well as code changes to

values of the properties.

Now then, lets rebuild and re-run our application using the newly adapted and updated Attendee 'Entity' class.

However, as we do (and show you the on-screen images below) let us realise that we now also are using a

'DataTemplate' definition in the XAML script - checkout all of the following details :-

=============================================================================================================

Above look for item five in the listed collection - "Missie Hitty" is in all of the four UI elements.

So "Murdoch" has become 'Hitty' - and what is more, any of the four editable texts can be used to make the change,

and the rest respond as soon as focus is changed, and moves on in some way or another.

Let's now look at the XAML script used to define the data template we are using for the ListBox - check it out below :-

[ .. it is the second DT which is of direct interest to us .. ]

==============================================================================================================

Notice in lines 13-15 we use both TextBox and TextBlock elements - this is so we can have both R/O and R/W.

So line 14 above deals with the UI element which allows us the change the 'Name' property and hence to 'Missie Hitty'.

Here is the XAML script for the ListBox itself - note how to set the template for the 'Item' as well as how to bind

the collection of Attendee 'Entities'.

==========================================================================================================

Okay then folks, not a very clever or colourful 'DT', but with a few small changes it can look as nice as that

shown in the next image - not over the top, but quite nice :-

==========================================

And now that we have seen the results of the applied 'template, lets check out the XAML script additions :-

============================================================================================================

Above, it is pretty easy to pick out just what does what ;-)

Let us move on a pace or two AND do a small test which has HUGE consequences, or at least an important

impact on our understanding of Data Binding and what is necessary to make it work correctly.

With two added text characters, lets change the application .NET code, and then rerun the application to see if we have

still got a responsive editing of the Name property etc., etc..

Here is what I am changing at my end of things :-

==========================================================

And when we launch and run the application I have clicked the Attendee push button twice, to get two windows on screen.

In the list box of the second window I have changed 'Murdoch' to 'Murray' and moved focus, only to see that all the

other three 'cell' entries stay unchanged.

Data Binding done wrongly often gives this sort of result - I know, I have been there, many a time before now and present

my age of enlightenment ;-0)

Study the following image carefully :-

===================================================================================================

And, if we play around with alternatively editing the four related 'cell' contents we can get some odd (strange)

and unpredictable results - check the next image most carefully :-

=======================================================================================================

I think the mess and confusion over correct cell contents should be ended NOW, and straight away I will

uncomment the SET line with the NPC method call in it - see below for the code 'repair' :-

=============================================================================

And now everything works OK as seen below, the last cell edited (and focus moved on the the next list item)

causes all four entries to be up to date and correct - study below carefully :-

=====================================================================================================

The above just shows that we must do our tests and checking most carefully - not all things are what they

seem at first sight. Also we need to remember that for some reason DataGrids seem to make a better

attempt at showing changes than other controls - I mean that they can give us false security by seeming

to work, when in fact the NPC code is not correctly define in the Entity class.

Before we finish this subsection, lets try another and different property. The 'Company' property.

From 'Fife Fiddlers' to "Funny Fife Fiddlers" - see details below :-

=======================================

Yes, it works across the two windows, from DataGrid to DataGrid, but how about trying 'Country' ?

==============================================================

I will leave it to you folks to add 'Company' to the template for the data of the ListBox, and try tests

to see that we get the correct response.

Lets us now move on ..........................

What of testing for basic Code Value changes ? :

This is in fact the MOST important way to check that you have your code written correctly, and your bindings

made and set successfully.

Always try to be able to test with a 'forced code change', and this is done in the background, behind the GUI stuff.

I like to add a test button so that I can study the GUI before and after the forced change.

Study what I have done in the next image - checkout item ID equal to 5 :-

=====================================================================================================

Notice in the above image that the words 'Force Code Change' are visible and partly visible.

Here is how I did it - make an event handler method which is similar to that shown below :-

===========================================================================================

Notice that the 5th element in the list array is that for Name equal to "Missie Murdoch", so she should completely

disappear and "Forced Code Change" appear in her place.

Below is the XAML script for this new button :-

============================================================================================================

I have often found that doing a forced code change test, similar to that above, has helped me pinpoint places

where data binding is not working correctly.

It is all too easy to get drawn into GUI issues, and XAML script alterations, when in fact the FCC test indicates

that our Custom class in the list of collection items is not passing on the change notification.

Do as above and you won't regret it ;-0)

The Way Forward :

We simply now need to re-visit the code for all the other of our Entity classes, and insert that which makes

them respond correctly to changes in the value, or association, of all public properties that are not virtual.

All the Entity classes need to notify all relevant property changes to the system.

Enough for now and this subsection.

Lets move on to learn more, see you in the next section .....................

PHH - 21st. & 22nd. January 2015.


working code

    public class Registration : INotifyPropertyChanged

    {

        //----- fields -----

        private int _registrationId;

        private string _firstname;

        private string _lastname;

        private string _country;

        private string _company;

        private Boolean _hasPaid;

        private Nullable<Boolean> _isNewbie;

        private double _regCost;

        private Boolean _isSpeaker;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int RegistrationId

        {

            get { return _registrationId; }

            set { _registrationId = value; NotifyPropertyChanged("RegistrationId"); }

        }

        public string Firstname

        {

            get { return _firstname; }

            set { _firstname = value; NotifyPropertyChanged("Firstname"); }

        }

        public string Lastname

        {

            get { return _lastname; }

            set { _lastname = value; NotifyPropertyChanged("Lastname"); }

        }

        public string Country

        {

            get { return _country; }

            set { _country = value; NotifyPropertyChanged("Country"); }

        }

        public string Company

        {

            get { return _company; }

            set { _company = value; NotifyPropertyChanged("Company"); }

        }

        public Boolean HasPaid

        {

            get { return _hasPaid; }

            set { _hasPaid = value; NotifyPropertyChanged("HasPaid"); }

        }

        public Nullable<Boolean> IsNewbie

        {

            get { return _isNewbie; }

            set { _isNewbie = value; NotifyPropertyChanged("IsNewbie"); }

        }

        public double RegCost

        {

            get { return _regCost; }

            set { _regCost = value; NotifyPropertyChanged("RegCost"); }

        }

        public Boolean IsSpeaker

        {

            get { return _isSpeaker; }

            set { _isSpeaker = value; NotifyPropertyChanged("IsSpeaker"); }

        }

        //----- constructors -----

        public Registration()

        {

            this.Firstname = "...";

            this.Lastname = "...";

            this.Country = "...";

            this.Company = "...";

            this.HasPaid = false;

            this.IsNewbie = new Nullable<Boolean>();

            this.RegCost = 0.00;

            this.IsSpeaker = false;

        }

        public Registration(string cF, string cL, string cCT, string cCP,

                                Boolean lHP, Nullable<Boolean> lNB, double nC, Boolean lSP)

        {

            this.Firstname = cF;

            this.Lastname = cL;

            this.Country = cCT;

            this.Company = cCP;

            this.HasPaid = lHP;

            this.IsNewbie = lNB;

            this.RegCost = nC;

            this.IsSpeaker = lSP;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        override public string ToString()

        {

            if (RegistrationId > 0)

            { return RegistrationId.ToString() + " >> " + Lastname.Trim(); }

            else

            { return " >> " + Lastname.Trim(); }

        }

    }

    //---------------------------------------------------------

    public class Speaker : INotifyPropertyChanged

    {

        //----- fields -----

        private int _speakerId;

        private string _name;

        private Boolean _isNew;

        private int _registrationId;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int SpeakerId {

            get { return _speakerId; }

            set { _speakerId = value; NotifyPropertyChanged("SpeakerId"); }

        }

        public string Name {

            get { return _name; }

            set { _name = value; NotifyPropertyChanged("Name"); }

        }

        public Boolean IsNew {

            get { return _isNew; }

            set { _isNew = value; NotifyPropertyChanged("IsNew"); }

        }

        public int RegistrationId {

            get { return _registrationId; }

            set { _registrationId = value; NotifyPropertyChanged("RegistrationId"); }

        }

        //-------------------------------------------------

        public virtual List<Session> Sessions { get; set; }

        public virtual Registration oReg { get; set; }

        //----- constructors -----

        public Speaker()

        {

            this.Name = "";

            this.IsNew = false;

            this.Sessions = new List<Session>();

            this.oReg = new Registration();

        }

        public Speaker(Registration oR, Boolean lN)

        {

            this.oReg = oR;

            this.Name = oR.Firstname+" "+oR.Lastname;

            this.IsNew = lN;

            this.Sessions = new List<Session>();

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        override public string ToString()

        {

            if (SpeakerId > 0)

            { return SpeakerId.ToString() + " >> " + Name.Trim(); }

            else

            { return " >> " + Name.Trim(); }

        }

    }

    //---------------------------------------------------------

    public class Session : INotifyPropertyChanged

    {

        //----- fields -----

        private int _sessionId ;

        private int _lectureRoomId ;

        private int _roomNumber ;

        private int _presentationId ;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int SessionId

        {

            get { return _sessionId; }

            set { _sessionId = value; NotifyPropertyChanged("SessionId"); }

        }

        public int LectureRoomId

        {

            get { return _lectureRoomId; }

            set { _lectureRoomId = value; NotifyPropertyChanged("LectureRoomId"); }

        }

        public int RoomNumber

        {

            get { return _roomNumber; }

            set { _roomNumber = value; NotifyPropertyChanged("RoomNumber"); }

        }

        public int PresentationId

        {

            get { return _presentationId; }

            set { _presentationId = value; NotifyPropertyChanged("PresentationId"); }

        }

        //---------------------------------------------------

        public virtual List<Attendee> Attendees { get; set; }

        //----- constructors -----

        public Session()

        {

            this.LectureRoomId = -1;

            this.PresentationId = -1;

            this.RoomNumber = -1;

            this.Attendees = new List<Attendee>();

        }

        public Session(int nLR, int nPI, int nRN)

        {

            this.LectureRoomId = nLR;

            this.PresentationId = nPI;

            this.RoomNumber = nRN;

            this.Attendees = new List<Attendee>();

        }

        public Session(int nLR, int nPI, int nRN, List<Attendee> aLA)

        {

            this.LectureRoomId = nLR;

            this.PresentationId = nPI;

            this.RoomNumber = nRN;

            this.Attendees = aLA;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        override public string ToString()

        {

            if (SessionId > 0)

            { return SessionId.ToString() + " >> " + LectureRoomId.ToString().Trim(); }

            else

            { return " >> " + LectureRoomId.ToString().Trim(); }

        }

    }

    //---------------------------------------------------------

    public class Attendee0

    {

        //----- properties -----

        public int AttendeeId { get; set; }

        public string Name { get; set; }

        public virtual List<Session> Sessions { get; set; }

        public virtual Registration oReg { get; set; }

        public int RegistrationId { get; set; }

        //----- constructors -----

        public Attendee0()

        {

            this.Name = "";

            this.oReg = new Registration();

            this.RegistrationId = this.oReg.RegistrationId;

            this.Sessions = new List<Session>();

        }

        public Attendee0(Registration oR)

        {

            this.Name = oR.Firstname+" "+oR.Lastname;

            this.oReg = oR;

            this.RegistrationId = this.oReg.RegistrationId;

            this.Sessions = new List<Session>();

        }

        //----- methods -----

        override public string ToString()

        {

            if (AttendeeId > 0)

            { return AttendeeId.ToString() + " >> " + Name.Trim(); }

            else

            { return " >> " + Name.Trim(); }

        }

    }

    //---------------------------------------------------------

    public class Attendee : INotifyPropertyChanged

    {

        //----- fields -----

        private int _attendeeId;

        private string _name;

        private int _registrationId;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int AttendeeId {

            get { return _attendeeId; }

            set { _attendeeId = value; NotifyPropertyChanged("AttendeeId");}

        }

        public string Name {

            get { return _name; }

            set { _name = value; NotifyPropertyChanged("Name");}

        }

        public int RegistrationId {

            get{return _registrationId;}

            set{_registrationId = value; NotifyPropertyChanged("RegistrationId");}

        }

        public virtual List<Session> Sessions {get; set;}

        public virtual Registration oReg {get; set;}

        //------------------------------------------------------------------------

        //----- constructors -----

        public Attendee()

        {

            this.Name = "";

            this.oReg = new Registration();

            this.RegistrationId = this.oReg.RegistrationId;

            this.Sessions = new List<Session>();

        }

        public Attendee(Registration oR)

        {

            this.Name = oR.Firstname + " " + oR.Lastname;

            this.oReg = oR;

            this.RegistrationId = this.oReg.RegistrationId;

            this.Sessions = new List<Session>();

        }

        //----- methods -----

        override public string ToString()

        {

            if (AttendeeId > 0)

            { return AttendeeId.ToString() + " >> " + Name.Trim(); }

            else

            { return " >> " + Name.Trim(); }

        }

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

    }

    //---------------------------------------------------------

    public class LectureRoom : INotifyPropertyChanged

    {

        //----- fields -----

        private int _lectureRoomId ;

        private int _floorNumber ;

        private int _roomNumber ;

        private int _maximumCapacity ;

        private Boolean _fullBlackout ;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int LectureRoomId

        {

            get { return _lectureRoomId; }

            set { _lectureRoomId = value; NotifyPropertyChanged("LectureRoomId"); }

        }

        public int FloorNumber

        {

            get { return _floorNumber; }

            set { _floorNumber = value; NotifyPropertyChanged("FloorNumber"); }

        }

        public int RoomNumber

        {

            get { return _roomNumber; }

            set { _roomNumber = value; NotifyPropertyChanged("RoomNumber"); }

        }

        public int MaximumCapacity

        {

            get { return _maximumCapacity; }

            set { _maximumCapacity = value; NotifyPropertyChanged("MaximumCapacity"); }

        }

        public Boolean FullBlackout

        {

            get { return _fullBlackout; }

            set { _fullBlackout = value; NotifyPropertyChanged("FullBlackout"); }

        }

        //-------------------------------------------------

        public virtual List<Session> Sessions { get; set; }

        //----- constructors -----

        public LectureRoom()

        {

            this.FloorNumber = -1;

            this.RoomNumber = -1;

            this.MaximumCapacity = -1;

            this.FullBlackout = false;

            this.Sessions = new List<Session>();

        }

        public LectureRoom(int nFN, int nRN, int nMC, Boolean lFB)

        {

            this.FloorNumber = nFN;

            this.RoomNumber = nRN;

            this.MaximumCapacity = nMC;

            this.FullBlackout = lFB;

            this.Sessions = new List<Session>();

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        override public string ToString()

        {

            if (LectureRoomId > 0)

            { return LectureRoomId.ToString() + " >> " + RoomNumber.ToString(); }

            else

            { return " >> " + RoomNumber.ToString(); }

        }

    }

    //---------------------------------------------------------

    public class HotelReservation : INotifyPropertyChanged

    {

        //----- fields -----

        private int _hotelReservationId ;

        private string _name ;

        private Boolean _isSpeaker ;

        private int _roomNumber ;

        private int _numberOfNights ;

        private Nullable<DateTime> _startDate ;

        private Boolean _hasOnlyBreakfast ;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int HotelReservationId

        {

            get { return _hotelReservationId; }

            set { _hotelReservationId = value; NotifyPropertyChanged("HotelReservationId"); }

        }

        public string Name

        {

            get { return _name; }

            set { _name = value; NotifyPropertyChanged("Name"); }

        }

        public Boolean IsSpeaker

        {

            get { return _isSpeaker; }

            set { _isSpeaker = value; NotifyPropertyChanged("IsSpeaker"); }

        }

        public int RoomNumber

        {

            get { return _roomNumber; }

            set { _roomNumber = value; NotifyPropertyChanged("RoomNumber"); }

        }

        public int NumberOfNights

        {

            get { return _numberOfNights; }

            set { _numberOfNights = value; NotifyPropertyChanged("NumberOfNights"); }

        }

        public Nullable<DateTime> StartDate

        {

            get { return _startDate; }

            set { _startDate = value; NotifyPropertyChanged("StartDate"); }

        }

        public Boolean HasOnlyBreakfast

        {

            get { return _hasOnlyBreakfast; }

            set { _hasOnlyBreakfast = value; NotifyPropertyChanged("HasOnlyBreakfast"); }

        }

        //-----------------------------------------------

        public virtual Registration oReg { get; set; }

        public int RegistrationId { get; set; }

        //----- constructors -----

        public HotelReservation()

        {

            Nullable<DateTime> oNDT = new DateTime();

            this.oReg = new Registration();

            this.Name = this.oReg.Firstname + " " + this.oReg.Lastname;

            this.IsSpeaker = false;

            this.RoomNumber = -1;

            this.NumberOfNights = -1;

            this.StartDate = oNDT;

            this.HasOnlyBreakfast = true;

        }

        public HotelReservation(Registration oR, Boolean lSK, int nRM, int nNN,

                                    Nullable<DateTime> dtSD, Boolean lBO)

        {

            this.oReg = oR;

            this.Name = oR.Firstname + " " + oR.Lastname;

            this.IsSpeaker = lSK;

            this.RoomNumber = nRM;

            this.NumberOfNights = nNN;

            this.StartDate = dtSD;

            this.HasOnlyBreakfast = lBO;

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        override public string ToString()

        {

            if (HotelReservationId > 0)

            { return HotelReservationId.ToString() + " >> " + oReg.Lastname.Trim(); }

            else

            { return " >> " + oReg.Lastname.Trim(); }

        }

    }

    //---------------------------------------------------------

    public class Presentation : INotifyPropertyChanged

    {

        //----- fields -----

        private int _presentationId;

        private string _titleShort ;

        private string _titleLong ;

        private ExperienceLevel _eExp ;

        private KnowledgeLevel _eKnow ;

        public int _speakerId;

        //----- events -----

        public event PropertyChangedEventHandler PropertyChanged;

        //----- properties -----

        public int PresentationId

        {

            get { return _presentationId; }

            set { _presentationId = value; NotifyPropertyChanged("PresentationId"); }

        }

        public string TitleShort

        {

            get { return _titleShort; }

            set { _titleShort = value; NotifyPropertyChanged("TitleShort"); }

        }

        public string TitleLong

        {

            get { return _titleLong; }

            set { _titleLong = value; NotifyPropertyChanged("TitleLong"); }

        }

        public ExperienceLevel eExp

        {

            get { return _eExp; }

            set { _eExp = value; NotifyPropertyChanged("eExp"); }

        }

        public KnowledgeLevel eKnow

        {

            get { return _eKnow; }

            set { _eKnow = value; NotifyPropertyChanged("eKnow"); }

        }

        public int SpeakerId

        {

            get { return _speakerId; }

            set { _speakerId = value; NotifyPropertyChanged("SpeakerId"); }

        }

        //---------------------------------------

        public virtual Speaker oSpk { get; set; }

        //----- constructors -----

        public Presentation()

        {

            this.TitleShort = "...";

            this.TitleLong = ".....";

            this.PresentationId = -13;

            this.eExp = ExperienceLevel.General;

            this.eKnow = KnowledgeLevel.nonerequired;

            this.oSpk = new Speaker();

        }

        public Presentation(string cTS, string cTL, ExperienceLevel eE, KnowledgeLevel eK)

        {

            this.TitleShort = cTS;

            this.TitleLong = cTL;

            this.PresentationId = -13;

            this.eExp = eE;

            this.eKnow = eK;

            this.oSpk = new Speaker();

        }

        //----- methods -----

        public void NotifyPropertyChanged(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        override public string ToString()

        {

            //if (null != PresentationId)

            if (PresentationId > 0)

            { return PresentationId.ToString() + " >> " + TitleShort.Trim(); }

            else

            { return " >> " + TitleShort.Trim(); }

        }

    }

    //---------------------------------------------------------

PHH - 22nd. January 2015.


'DiagnosticsContext' - Code Project class

"Get detailed information on 'ChangeTracker' entries."

http://www.codeproject.com/Tips/890432/Entity-Framework-DiagnosticsContext-Get-Detailed

PHH - 27th. March 2015.


Chapter 17 - the best parts of WPF - data binding !

PHH - 8th. December 2014.

.


Chapter 18 - control your XAML, make it tidy and readable

PHH - 8th. December 2014.


Chapter 19 - 'AutoMapper' transforming objects

*** CARE *** This software tool can be 'seriously' over used !!!

It can also be misunderstood, as 'shallow' copies are made by default, and NOT the

'deep' copies that most folks would want and expect.

The deep/shallow copying issue can be a 'serious' mistake, as we can easily end up with data

values being mixed up from the original to the part copied 'new' ? object.

This could mean that values edited on the UI screen could be from both original and copied objects !!

It is possible to get into quite a 'mess' ;-0((

AutoMapper is nice and has its place - BUT - do not over use it, we ought NOT to be moving data values

around in memory just because we have a mental concept about data layering.

Data layering, or Model layering, can be quite different things depending on how we go about the design.

See Chapter 13 subsection "Layering our Models".

Having said all that, here is a useful URL / link for getting hold of 'AutoMapper', and some information

on its use.

http://www.codeproject.com/Articles/867901/Map-Framework-for-AutoMapper

PHH - 8th. December 2014.


Chapter 20 - on-screen Validation

PHH - 8th. December 2014.


Chapter 21 - 'multi-part' / layered Models

PHH - 8th. December 2014.


Chapter 23 - 'Unit testing' made possible

PHH - 8th. December 2014.


Chapter 27 - 'Azure' and WPF ...

PHH - 8th. December 2014.


Appendix A - Radio buttons, data binding

Well guys, believe it or not using Radio Buttons with WPF (in fact all XAML) can get folks into

lots of problems and hit lots of issues while trying to do 'Data Binding'.

If you Google it you will get lots of postings, moans and complaints - AND - some very confusing

and complex answers.

Needless to say that there is a way to keep our View and VM separate (disentangled) and still have

the Radio Buttons working OK for us.

At the moment my solution works, is clean, clear and understandable, even if it is not perfect to those

amongst us who are budding 'Renaissance Men' - you know, mates of Leonardo !? ;-0))

In the next two or three subsections I intend to show and develop what is now working.

Keep and eye out for developments and improvements.

PHH - 9th. & 10th. December 2014.


a Simple sample demo - MVVM style

Open up VS 2013 and close any currently open solution.

Start a new project, 'File, New, Project ...' as shown below :-

===============================================================================================

At the 'New Project' dialog screen enter the following detail (or similar) :-

Notice that we will not select 'Source Control'.

Also notice that this time we have made the names of our Solution and Project different - check it out, above and below :-

====================================================

Edit the code for the 'Windows1' class to be as shown below :-

==========================================================

=======================================================================================

========================================================================================================================

================================================================================================================

====================================================================================================================

In the above XAML script notice that in lines 21 & 22 we see the two alternative syntaxes for binding to a public property

of the supporting object associated via the 'DataContext' code link - we do not need to supply the 'Path=' text.

Now then, the following image shows the working code - namely lines 78 - 81 so check it out :-

[ .. we will improve on this first design attempt later in these eNotes .. ]

===================================================================

[ .. other properties of lHope and lCharity have different and suitable entries for lines 78-81 .. ]

The issue appears to be a time one, so as long as we force the situation by getting our code lines right, and in order,

then the button clicks do as they should - one click to change the group and also the textblock display.

When I did it the conventional way (easy way) and similar to all other bindings I do in WPF, it required two successive

clicks of the mouse on the radio button to get the correct textblock entry ;-0((

Now the adjusted code works fine, and is shown below :-

===============================================================================================================================================

The good news for us developers is that the code shown above does not conflict with what we are

trying to do with MVVM and its pattern of development.

We should be able to apply this code method with MVVMlight and Prism too I should think.

However, always check that a new framework may have a better way of doing a few things - don't

fight your framework, go with it, find out what it has to offer us, even if we think we can manage ourselves.

PHH - 10th. December 2014.


working code and script

==========================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//=====================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace RadioButton01

partial class Window1 inherit Window  implements INotifyPropertyChanged

    private _lFaith as logic

    private _lHope as logic

    private _lCharity as logic

    //------------------------

    private _lresult as string

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    //----- Constructors -----

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

        //----- bind Public properties to 'self' -----

        self:DataContext := self

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:ClearAllRBs()

        lResult := "... result will be here ..."

        //--------------------------------------

        lFaith := true

    return

    method ClearAllRBs() as void

        lFaith := false

        lHope := false

        lCharity := false

    return

    //----- Properties -----

    property lResult as string

        get

            return self:_lresult

        end get

        set

            self:_lresult := value

            self:NotifyPropertyChanged("lResult")

        end set

    end property

    property lFaith as logic

        get

            return self:_lFaith

        end get

        set

            self:_lFaith := value

            self:NotifyPropertyChanged("lFaith")

            //----------------------------------

            if lFaith == true

                lHope := false

                lCharity := false

            endif

            self:lResult := "chosen 'Faith' .."

        end set

    end property

    property lHope as logic

        get

            return self:_lHope

        end get

        set

            self:_lHope := value

            self:NotifyPropertyChanged("lHope")

            //---------------------------------

            if lHope == true

                lCharity := false

                lFaith := false

            endif

            self:lResult := "chosen 'Hope' .."

        end set

    end property

    property lCharity as logic

        get

            return self:_lCharity

        end get

        set

            self:_lCharity := value

            self:NotifyPropertyChanged("lCharity")

            //------------------------------------

            if lCharity == true

                lFaith := false

                lHope := false

            endif

            self:lResult := "chosen 'Charity' .."

        end set

    end property

end class

end namespace

==========================================================================

[ .. simpler script afterwards .. ]

<Window x:Class="RadioButton01.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="160" Width="260" Background="MintCream" >

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBlock" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="RadioButton" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <RadioButton Content="Faith :" Margin="39,35,0,0" IsChecked="{Binding Path=lFaith, Mode=TwoWay, UpdateSourceTrigger=Default}"/>

        <RadioButton Content="Hope :" Margin="39,55,0,0" IsChecked="{Binding lHope, Mode=TwoWay, UpdateSourceTrigger=Default}"/>

        <RadioButton Content="Charity :" Margin="39,75,0,0" IsChecked="{Binding lCharity, Mode=TwoWay, UpdateSourceTrigger=Default}" />

        <TextBlock Margin="122,96,0,0" TextWrapping="Wrap"

                   Text="{Binding lResult}" Background="BlanchedAlmond"/>

    </Grid>

</Window>

==========================================================================

<Window x:Class="RadioButton01.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="160" Width="260" Background="MintCream" >

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBlock" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="RadioButton" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <RadioButton Content="Faith :" Margin="39,35,0,0" IsChecked="{Binding Path=lFaith}"/>

        <RadioButton Content="Hope :" Margin="39,55,0,0" IsChecked="{Binding lHope}"/>

        <RadioButton Content="Charity :" Margin="39,75,0,0" IsChecked="{Binding lCharity}" />

        <TextBlock Margin="122,96,0,0" TextWrapping="Wrap"

                   Text="{Binding lResult}" Background="BlanchedAlmond"/>

    </Grid>

</Window>

==========================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE RadioButton01

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

<Application x:Class="RadioButton01.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

==========================================================================

==========================================================================

==========================================================================

PHH - 10th. December 2014.


a Better sample demo - MVVM style

Lets improve things a little, using our first simple sample as a basis for moving forward.

In our solution, let us make another project - see below :-

===============================================================================================

At the 'Add New project' dialog we need to supply a suitable name - check the following :-

=================================================================================================================

So we now create a second WPF window class with name 'RadioButton02'.

Let us make this new project the 'Start-Up' project - right click for the context menu :-

===================================================================

If you get this right then the new project entry (node in SE pane) will be highlighted,

or shown in bold type - see below for an example :-

===========================================

Now we have a new project we can start to add new and improved code form that we used in the

first project.

Lets make a start to improvement .................

Creating an 'Enum' :

Since we are not as yet making a sample in the full MVVM pattern approach, let us add the new

code for the 'enum' in the 'Window1.prg' code file, insid ethe Namespace and outside of the Window1

class definition - check this out :-

===============================================================

Now we need to add some fields and properties to the Window1 class to support our Radio Buttons

for use as we require them.

First of all, lets see the general overall 'shape' to our Window1 class - check below :-

==========================================================================================

Notice above that we have made a few private fields and used these to create some public properties.

We will use all of these to support the operation of our set of Radio Buttons.

Note also that we are using notification of changing property values, to make our class fully responsive to

value changes - and to hence make data binding work 100%.

Let us now look in detail at one of the four similar property definitions for the four choices on offer.

In particular study the extra code lines after the call to notification on line 148. So lines 150 through 155 are

the ones to provide the necessary button selection and data binding functionality :-

======================================================================

Yes, I know, it would be nice if things were cleaner and simpler than this - BUT - to see what a mess

developer guys can get into, go Google on the topic and find some StackOverflow stuff (and other) which is

horrendous to say the least ;-0((

Now then, crucial to our simple approach is a small method to clear all possible 'selection' values.

Here it is below :-

=======================================================

At this stage we had better study all the private fields we are needing to use - check these thoroughly :-

=============================================================================================

We have one for each radio button 'logic' and one for the tracked result, as well as an important

one for the 'enum' value which will eventually come in as part of the ViewModel in project 3.

With Radio Buttons, we really require to pass back and forth only the value selected, and NOT the others.

Lets now see the standard format of the public property which is associated with the 'enum' private field :-

===============================================================

Yes, as you can see above, there are no extra code lines over and above the basic format that we use

for most properties we wish to supply notification when their value changes.

The other standard coded property for 'lResult' has been seen previously in the earlier 'Simple' sample.

Now then guys, lets take a look at the XAML script for this second RB project. Check below to see how simple it is :-

==================================================================================================================================

Notice in the script shown above that the bindings to the 'IsChecked' attribute show both syntax alternatives.

In the above image I have collapsed the script section for the Grid Resources - to make things clearer to read.

If we partly expand this Resources section we see the following :-

============================================================

And then if we fully expand it we see that shown in the following image :-

==================================================================================

In fact we can remove the Resources section altogether, as long as we place it in the Application file called

'App.xaml'.

First lets see our XAML window script with the Resources section moved, or removed :-

======================================================================================================================

Yes, looks quite simple and clear when viewed like this above.

How does our 'App' file look now we have moved things ? Check below :-

===========================================================================================

So 'Grid' resources have become 'Application' resources.

Okay the folks, before we build and run the new RB application, lets see what our Constructor does for us :-

=======================================================================

Not a great deal - BUT - the 'DataContext' assignment (or association) is rather crucial (or important)

to the functioning of the new app - without it the app would not work.

Instead of the data for binding coming from and external ViewModel object, it is to be supplied by the

Window1 object itself.

The following small image shows I am setting the original value of the Radio Button set to 'Carnivore'.

However, in reality we would get this from the ViewModel and use the value to set the RB set correctly.

Check out these few details :-

===================================================================

And now when we compile and run the second RB app we see this note I have clicked the second button :-

==============================================

Take it from me that each button clicks and changes nicely (with only one click) and that the reported

string value of the stored RB 'enum' selection corresponds correctly to what it should be.

Time to move on, lets now go and see how to make a third and fully working multiple RB set application.

See you in the next sub-section ...............

PHH - 10th. & 11th. December 2014.


working code and script

==================================================

==========================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//=====================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace RadioButton02

public enum FoodPreference

    Vegan

    Vegetarian

    Carnivore

    FishOnly

end

partial class Window1 inherit Window implements INotifyPropertyChanged

    private _eFP as FoodPreference

    //----------------------------

    private _lVegan as logic

    private _lVegetarian as logic

    private _lCarnivore as logic

    private _lFishOnly as logic

    //------------------------

    private _lresult as string

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    //----- Constructors -----

    constructor()

        super()

        InitializeComponent()

        self:Initialize()

        //----- bind Public properties to 'self' -----

        self:DataContext := self

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:ClearAllfieldRBs()

        lResult := "... result will be here ..."

        //--------------------------------------

        lCarnivore := true

    return

    method ClearAllfieldRBs() as void

        _lVegan := false

        _lVegetarian := false

        _lCarnivore := false

        _lFishOnly := false

    return

    //----- Properties -----

    property eFP as FoodPreference

        get

            return self:_eFP

        end get

        set

            self:_eFP := value

            self:NotifyPropertyChanged("eFP")

        end set

    end property

    property lResult as string

        get

            return self:_lresult

        end get

        set

            self:_lresult := value

            self:NotifyPropertyChanged("lResult")

        end set

    end property

    property lVegan as logic

        get

            return self:_lVegan

        end get

        set

            self:_lVegan := value

            self:NotifyPropertyChanged("lVegan")

            //----------------------------------

            if lVegan == true

                ClearAllfieldRBs()

                _lVegan := true

                eFP := FoodPreference.Vegan

                self:lResult := eFP:ToString()

            endif

        end set

    end property

    property lVegetarian as logic

        get

            return self:_lVegetarian

        end get

        set

            self:_lVegetarian := value

            self:NotifyPropertyChanged("lVegetarian")

            //---------------------------------

            if lVegetarian == true

                ClearAllfieldRBs()

                _lVegetarian := true

                eFP := FoodPreference.Vegetarian

                self:lResult := eFP:ToString()

            endif

        end set

    end property

    property lCarnivore as logic

        get

            return self:_lCarnivore

        end get

        set

            self:_lCarnivore := value

            self:NotifyPropertyChanged("lCarnivore")

            //------------------------------------

            if lCarnivore == true

                ClearAllfieldRBs()

                _lCarnivore := true

                eFP := FoodPreference.Carnivore

                self:lResult := eFP:ToString()

            endif

        end set

    end property

    property lFishOnly as logic

        get

            return self:_lFishOnly

        end get

        set

            self:_lFishOnly := value

            self:NotifyPropertyChanged("lFishOnly")

            //------------------------------------

            if lFishOnly == true

                ClearAllfieldRBs()

                _lFishOnly := true

                eFP := FoodPreference.FishOnly

                self:lResult := eFP:ToString()

            endif

        end set

    end property

END CLASS

END NAMESPACE

==========================================================================

<Window x:Class="RadioButton02.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Better RBs :"  Height="190" Width="260" Background="Lavender" >

    <Grid>

        <Grid.Resources>

            <Style TargetType="TextBlock" >

                <Setter Property="HorizontalAlignment" Value="Left" />

                <Setter Property="Height" Value="23" />

                <Setter Property="TextWrapping" Value="Wrap"/>

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="Width" Value="120"/>

            </Style>

            <Style TargetType="RadioButton" >

                <Setter Property="VerticalAlignment" Value="Top"/>

                <Setter Property="HorizontalAlignment" Value="Left"/>

            </Style>

        </Grid.Resources>

        <RadioButton Content="Vegan :" Margin="39,35,0,0" IsChecked="{Binding Path=lVegan}"/>

        <RadioButton Content="Vegetarian :" Margin="39,55,0,0" IsChecked="{Binding lVegetarian}"/>

        <RadioButton Content="Carnivore :" Margin="39,75,0,0" IsChecked="{Binding lCarnivore}" />

        <RadioButton Content="Fish Only :" Margin="39,95,0,0" IsChecked="{Binding lFishOnly}" />

        <TextBlock Margin="122,126,0,0" TextWrapping="Wrap"

                   Text="{Binding lResult}" Background="BlanchedAlmond"/>

    </Grid>

</Window>

==========================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE RadioButton02

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

<Application x:Class="RadioButton02.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

    </Application.Resources>

</Application>

==========================================================================

PHH - 11th. December 2014.


a Sample to copy/adapt, in the MVVM approach

Okay then folks, before we get dragged into details of the new project 'build', lets first of

all take a minute or two to focus on where we are headed, what we will create / produce, and also

how it will look at runtime.

Lets us study the following image - carefully, and in small detail as well :-

=============================================================================================================================================================

At top left of image we can see a light brown (in colour) launching screen / window.

This has a push button which produces on screen a View for "Multi RB sets".

Each time we press the launch button we get a new and extra window / WPF form.

The ViewModel objects loosely coupled to each and every screen is one objects - the

same ViewModel object.

We can prove the above by making changes in any of the screens by clicking on a Radio

Button and see all (three in the above example) of the Radio Buttons and the results text

change at the same click.

We also will see that any screen (window) can be clicked and the others will simultaneously

change - in the blink of an eye.

Finally, we will see that we have two quite separate sets (or groups) of Radio Buttons, and that

one set does not get mixed up (or confused) by the other.

And all this is done in the same manner as we have done previous sections, so it is done on

the pattern for MVVM but without the need of a supporting framework. We are just using

the basic WPF and XAML features.

PHH - 11th. December 2014.


Starting the project (RB 03)

Okay guys, lets get going ............

Open Visual Studio 2013 (update 4) and close down any open solutions in the IDE.

Find, select and open the solution we have been working on previously entitled "BindingRadioButtons".

In the SE (Solution Explorer) pane right click the solution node to bring up the context menu as seen below :-

==============================================================================================

To the already existing two RB (Radio Button) projects, select to add a third - a new project ...

Make the appropriate selections and entries as seen in the following image :-

===================================================================================================================

Yes, we have entitled our new project "RadioButton03", to fit in with the previous two.

As soon as you click the OK button you should see this - check it out (below) :-

==============================================

Let us now change the setting for the 'StartUp' project - right click the new node in the SE pane

as seen in the next image :-

=========================================================

And then hopefully you will see the following detail in the SE pane :-

===========================================

Okay folks, "so far so good" as they say ;-0)

Let us now add our regular bunch of folders, those to hold the View, ViewModel, Model stuff. We

will need four in total :-

===================================================================================

In the above image we right click the project node to bring up the Context Menu.

And the next image shows just which folder names you should be using :-

===============================================

Notice that in the above image we have 'settled' on using the folder name of "d_ClassesAndEnums" for

that folder which holds our Custom / Business classes.

This is simply because for real apps (not just test and demo apps) we will use 'enums' a great deal in

our coding and design.

Okay then folks, we are ready to use our newly structured SE pane, we will make a simple start

in the next sub-section, and add some 'enums'.

See you there ..............

PHH - 12th. December 2014.


Making our 'enums'

In the SE pane select and highlight the node entitled "d_ClassesAndEnums".

Right click to bring up the Context Menu - see below :-

=======================================================================================

We are now going to add a new item, of type 'Code File' - checkout below :-

=============================================================================================================

As you can see we need to call the file 'MyEnums' - give it this name now, and 'Add' :-

=====================================

Now you need to do some typing, or cut and paste from the following "working code and script" subsection.

This is what you need to add to the new file :-

=============================================================

Yes, we need two 'enums' as we will have two separate sets, or groups' of radio buttons in our 'View'.

Lets now move on to the next subsection where we will create a 'View' to fit with our new 'enums'.

See you there ..............

PHH - 12th. December 2014.


Making the View

Hi guys, now we need to make a new 'View' for our third RB project.

Select and highlight the node in the SE pane entitled "a_Views" - check this out :-

===================================================================================

This time we need a 'Window' template and not just a code file - here are some details :-

=====================================================================================================

Make sure you entitle the new Window "MultiRBsetsView.xaml" and then the SE pane should appear

as in the following image :-

=============================================

Okay then folks, this gives us the basic 'empty' stub of a Window class, XAML script and .NET code,

but we do need to now add the extra content that we require for our RB form.

Let us start in the XAML editor and slide from the Toolbox two bunches of Radio Button UI elements.

Use the alignment features of the designer to help you place them correctly - we this simple sample

we will not use grid columns and grid rows - just to keep things simple.

===================================================

As soon as we have placed all of the eight separate RBs on our form, the accompanying XAML script

should look something like the following (you may need to tidy and clean it for yourself) :-

[ .. edit lines 4 & 5 to suit .. ]

===================================================================================================================================

Yuk ! - we can do something to tidy this up I feel.

Go into the "App.xaml" file and add some Resources - we need a few 'Styles' - check the following :-

=======================================================================================

The above two Styles will do us for the moment, now lets return to the View XAML file to carry

out some cleaning up of our script text :-

==========================================================================================

Okay, things are looking fine - BUT - we need to specify two groups or sets of RBs so that we get

suitable and appropriate behaviour of our 'View' at runtime.

Lets add the script for the two sets now - check below :-

==================================================================================================

Okay then guys, we have a set called 'Food' and another called 'Hotel', and it will become obvious

why, when we see which 'enums' we use.

Lets us now start to make things more clear by editing the text to be displayed on the View by the 'Content'

attributes in the above and following script :-

================================================================================================

In the above image the Content text should match the 'enums' we created earlier.

That is enough for now, as until we design and create the ViewModel we will not know what

we need type into the XAML editor to make all the data 'Bindings'.

Lets leave things for the moment and move onto the next section where we focus and work on

the VM (ViewModel).

See you there ..................

PHH - 12th. December 2014.

Addendum :

Before we shoot off to another subsection we ought to see how the Window code behind looks !

It is said that if we do MVVM correctly then there ought to be very little (to nothing) in this file.

Lets see what we have - checkout below :-

===============================================================================================================

Yep! - not bad, as short as we can make it now while not using MVVM and a framework.

The event handler on line 26 is needed to stop Model data corruption - as explained in a later subsection from here.

And line 22 is where the VM comes in as a parameter and is loosely coupled.

It is this 'DataContext' property / attribute which needs a controlled de-coupling on line 28 - then everything works

as planned and hoped ;-0)


Making the ViewModel

Hi guys, before we can set any bindings in the View, with the XAML script and the available

attributes, we need to have designed and made a VM ('ViewModel').

It is the VM which brings the data items to the View - via bindings with Public properties on

the VM itself.

We need to bring the data as 'Models' to the VM, both in our design of the VM and also in our coding

of the instantiation of the VM that we then use with our View.

All of the above will become more obvious as we make and use out ViewModel (VM).

Lets make a start by adding a code file to the folder for VMs - check this out :-

=======================================================================================

To bring up the Context Menu as seen above, select and highlight the 'ViewModel' node in the SE pane.

This will then bring up the 'Add New Item' dialog - check below :-

===============================================================================================================

Yes, we need a new file called "MultiRBsetsViewModel.prg" and the results of our efforts can be

seen in the next image :-

=============================================

Okay the folks, we have a new default 'stub' file, and now we need to fill it with suitable code ;-0)

Lets start a new small section ...........

Filling out the VM file with Suitable Code :

Before we get into the more important details, lets see the required directives section, and start of the

Namespace and new class - see below :-

==============================================================================

Just one extra #using over the bunch placed there by the Template we used.

Private Fields :

Now we need to study in detail the Private fields we need to support the Public properties we

will use to good effect in our bindings.

============================================================================

In the above image we see that we need a field for every Radio Button, and also a couple for

the two TextBlocks we will use to display the selections made.

And, of course, we need a Private field for each of the data objects we will have passed to the

ViewModel at the time of instantiation - those relating to Food and Hotel.

Lets move on a pace ..........

Public Properties :

Remember that any property used in data binding has to be Public, and so we need a Public

property to match each Private field - at least most of the time.

Here are the collapsed properties we have created :-

==================================================================

The above are for the two data in/out Model objects, then we have two properties for the screen results.

The two bunches of properties for the RB groups are pretty obvious.

Now let us start at the easier end, and look at the code detail of one of the Model related properties.

Lets check out the 'Food' one :-

==================================================================

And as you can see above this is just standard code, as for any other Field/Property we

have seen up to now, when we need to track the 'Changed' notification.

And now here is another standard code segment, for the Hotel result :-

==========================================================================

Okay folks, so good so far, but we now need to take much more care over our studying of the

property code related to all the logic radio buttons.

I have re-coded the handful of lines added to make the Radio Buttons respond in the way we

expect them to.

I the earlier (simpler) samples we had code which worked - BUT - it was not as clean and as tidy

as we need to have sets of RBs to which new ones can easily be added, or indeed easily removed.

Study in particular lines 233 through 238, and notice that only direct references ar made to the 'FishOnly'

option, and none of the others. Yes we do have a common method called from line 234.

Lets look in full detail at one of the RB logic properties :-

==================================================================

It becomes apparent (after careful study of the above code) that an extra and new button option can be

easily added without need to change any existing properties for other 'Food' related properties.

However, as you can see, we will need to change the code in the common method - checkout below :-

======================================================

As you can see above, the code to be changed when a RB is added or deleted, is just in one place.

We have a similar method for the bunch of 'Hotel' fields - check below :-

=========================================================

It may help if we see just which Methods we have, and so can keep a check on what needs explaining :-

==========================================================================================

The two highlighted ones have been explained above, so now lets check out the last one, that

for setting up the logic of the 'Hotel' group initially - on instantiation :-

==================================================================

Yep! - not very clever or 'smart' or 'pretty' even - but effective ;-0)

The incoming related 'enum' holds just the information on the RB which is pressed / checked,

and we have to do the rest. Once again we are keeping things simple.

So how does the method 'Initialize()' bring all this stuff together ?

I suggest you give the following image a carefully study :-

====================================================================================

The first two lines simply cause the new input Model data (injection) to be displayed in the results TextBlock elements.

The other two groups of two lines are self evident, and set-up the RB logic.

Bringing Everything Together :

Okay then guys, we just now need to see what happens in the Constructor to the VM.

=========================================================================================

Notice I have commented out the empty Constructor simply because I wished the VM to have

nothing but 'Data Injection' used for instantiation - see line 57 for this.

In the above image, lines 59 & 60 are where the incoming Models are assigned to VM Public

properties - so from here on, the VM really deals in pointers to the original data, and not values as such.

If you wish you could uncomment the empty Constructor - see below :-

===============================================================

Enough for now and the ViewModel, lets go and make some suitable 'bindings'.

See you there - in the next subsection .............

PHH - 12th. December 2014.


Setting the bindings

In the MVVM pattern of 'coding approach', we need to make our bindings in the XAML script.

If the ViewModel itself is to know 'NOTHING' of the 'View' being used, then we can be setting bindings

in code belonging to the VM.

You will notice that there are o 'Name' attributes being defined or used in the next image - check out all details :-

================================================================================================================================

Yep! - nothing in the above is a surprise - just simple 'bindings' - ten in all, and each to a different Public property.

Notice the absence of 'Name' attributes - so the View knows of the VM but not the other way around.

With the loose coupling being done in one line at the same time as the data injection. Study the small image below :-

=======================================================================================================================

Okay folks, time for a change, lets move on.

See you in the next subsection .............

PHH - 12th. December 2014.


Creating the main 'Launch' screen.

Okay then folks, our requirement for this subsection is to make a simple main screen

or 'Launch' screen, from which we instantiate other RB 'Views'.

I won't call our main Window a 'View' as it is a bit different, and does not have a ViewModel

to go with it, as such.

Lets first see what we get as the default code file :-

========================================================

The first thing we can do is remove the highlighted section (above) as we do not require it in

our simple test app.

After some editing, and collapsing the '#using' directives we get the following - check it out :-

==============================================================

Lets move on a pace ..............

Since we will need a push button on our 'launch' window, lets add an extra Style into the App.xaml file :-

======================================================================================

The Application Resources now looks as follows - with the main Window showing as we require it :-

================================================================================================

With the Button style details placed in the Application Resources file we can write our 'Launch'

window as simply as shown in the following image :-

==========================================================================================

Notice that we have added a single 'Click' event to this, even though in MVVM we will keep clear of

using Events, and use Commands instead - this will do us for now.

So when we flesh out the code in the Click event handler stub we get the following :-

==============================================================================================

Let us now see what should happen when we compile and run our application, and then select and

click the push button once :-

============================================================

Okay, fine ! - enough for now, lets move on.

See you in the next subsection ..........

PHH - 12th. December 2014.


A controlled way to 'de-couple'

===============================================================================================================

PHH - 12th. December 2014.


Testing out thoroughly

================================================================================================================================================

PHH - 12th. December 2014.


working code and script

==========================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace RadioButton03

    partial class Window1 inherit Window

        public oMRBSVM as MultiRBsetsViewModel

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        method Initialize() as void

            self:oMRBSVM := MultiRBsetsViewModel{FoodPreference.FishOnly, HotelAccommodation.Double }

        return

        private method pbLaunchRBs_Click( sender as System.Object, ;

                        e as System.Windows.RoutedEventArgs ) as System.Void

            local oMRBS as MultiRBsetsView

            oMRBS := MultiRBsetsView{self:oMRBSVM}

            oMRBS:Show()

        return

    end class

end namespace

==========================================================================

<Window x:Class="RadioButton03.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="200" Width="330" Background="BurlyWood">

    <Grid>

        <Button Name="pbLaunchRBs"

                Content="Launch RB sets"

                Margin="51,45,52,88"

                Click="pbLaunchRBs_Click" />

    </Grid>

</Window>

==========================================================================

#using System

#using System.Collections.Generic

#using System.Configuration

#using System.Data

#using System.Linq

#using System.Windows

BEGIN NAMESPACE RadioButton03

   /// <summary>

   /// Interaction logic for App.xaml

   /// </summary>

   PARTIAL CLASS App INHERIT Application

   END CLASS

END NAMESPACE

===========================================

<Application x:Class="RadioButton03.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

        <Style TargetType="TextBlock" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="23" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="RadioButton" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Button" >

            <Setter Property="VerticalAlignment" Value="Stretch"/>

            <Setter Property="HorizontalAlignment" Value="Stretch"/>

            <Setter Property="Height" Value="Auto"/>

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Background" Value="Yellow"  />

            <Setter Property="VerticalContentAlignment" Value="Center"/>

            <Setter Property="HorizontalContentAlignment" Value="Center"/>

        </Style>

    </Application.Resources>

</Application>

==========================================================================

//----- MyEnums.prg -----

//----- PHH - 1th. December 2014. -----

begin namespace RadioButton03

    public enum FoodPreference

        Vegan

        Vegetarian

        Carnivore

        FishOnly

    end

    public enum HotelAccommodation

        Single

        Double

        Suite

        None

    end

end  namespace

==========================================================================

//----- MultiRBsetsViewModel.prg -----

//----- Monday 11th. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace RadioButton03

class MultiRBsetsViewModel implements INotifyPropertyChanged

    //----- will normally be a bunch of private fields -----

    //----- and their related public properties -----

    private _eFood as FoodPreference

    private _eHotel as HotelAccommodation

    //-----------------------------------

    private _lVegan as logic

    private _lVegetarian as logic

    private _lCarnivore as logic

    private _lFishOnly as logic

    //----------------------------

    private _lSingle as logic

    private _lDouble as logic

    private _lSuite as logic

    private _lNone as logic

    //----------------------------

    private _lResultFood as string

    private _lResultHotel as string

    //----------------------------

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    //----- Constructors -----

    /*constructor()

        super()

        eFood := FoodPreference.Carnivore

        eHotel := HotelAccommodation.Single

        self:Initialize()

    return*/

    //----- data comes in as 'Registration' object -----

    constructor(eFP as FoodPreference, eHA as HotelAccommodation)

        super()

        eFood := eFP

        eHotel := eHA

        self:Initialize()

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        //----- do something with set values of eFP & eHA -----

        self:lResultFood := eFood:ToString()

        self:lResultHotel := eHotel:ToString()

        self:ClearFieldRBsFood()

        self:SetRBlogicFood()

        self:ClearFieldRBsHotel()

        self:SetRBlogicHotel()

    return

    method ClearFieldRBsFood() as void

        _lVegan := false

        _lVegetarian := false

        _lCarnivore := false

        _lFishOnly := false

    return

    method ClearFieldRBsHotel() as void

        _lSingle := false

        _lDouble := false

        _lSuite := false

        _lNone := false

    return

    method SetRBlogicFood() as void

        if eFood == FoodPreference.Vegan

            lVegan := true

        endif

        if eFood == FoodPreference.Vegetarian

            lVegetarian := true

        endif

        if eFood == FoodPreference.Carnivore

            lCarnivore := true

        endif

        if eFood == FoodPreference.FishOnly

            lFishOnly := true

        endif

    return

    method SetRBlogicHotel() as void

        if eHotel == HotelAccommodation.Single

            lSingle := true

        endif

        if eHotel == HotelAccommodation.Double

            lDouble := true

        endif

        if eHotel == HotelAccommodation.Suite

            lSuite := true

        endif

        if eHotel == HotelAccommodation.None

            lNone := true

        endif

    return

    //----- Properties -----

    property eFood as FoodPreference

        get

            return self:_eFood

        end get

        set

            self:_eFood := value

            self:NotifyPropertyChanged("eFood")

        end set

    end property

    property eHotel as HotelAccommodation

        get

            return self:_eHotel

        end get

        set

            self:_eHotel := value

            self:NotifyPropertyChanged("eHotel")

        end set

    end property

    property lResultHotel as string

        get

            return self:_lResultHotel

        end get

        set

            self:_lResultHotel := value

            self:NotifyPropertyChanged("lResultHotel")

        end set

    end property

    property lResultFood as string

        get

            return self:_lResultFood

        end get

        set

            self:_lResultFood := value

            self:NotifyPropertyChanged("lResultFood")

        end set

    end property

    //===================================================

    property lVegan as logic

        get

            return self:_lVegan

        end get

        set

            self:_lVegan := value

            self:NotifyPropertyChanged("lVegan")

            //----------------------------------

            if lVegan == true

                self:ClearFieldRBsFood()

                _lVegan := true

                eFood := FoodPreference.Vegan

                self:lResultFood := eFood:ToString()

            endif

        end set

    end property

    property lVegetarian as logic

        get

            return self:_lVegetarian

        end get

        set

            self:_lVegetarian := value

            self:NotifyPropertyChanged("lVegetarian")

            //---------------------------------

            if lVegetarian == true

                self:ClearFieldRBsFood()

                _lVegetarian := true

                eFood := FoodPreference.Vegetarian

                self:lResultFood := eFood:ToString()

            endif

        end set

    end property

    property lCarnivore as logic

        get

            return self:_lCarnivore

        end get

        set

            self:_lCarnivore := value

            self:NotifyPropertyChanged("lCarnivore")

            //------------------------------------

            if lCarnivore == true

                self:ClearFieldRBsFood()

                _lCarnivore := true

                eFood := FoodPreference.Carnivore

                self:lResultFood := eFood:ToString()

            endif

        end set

    end property

    property lFishOnly as logic

        get

            return self:_lFishOnly

        end get

        set

            self:_lFishOnly := value

            self:NotifyPropertyChanged("lFishOnly")

            //------------------------------------

            if lFishOnly == true

                self:ClearFieldRBsFood()

                _lFishOnly := true

                eFood := FoodPreference.FishOnly

                self:lResultFood := eFood:ToString()

            endif

        end set

    end property

    //===================================================

    property lSingle as logic

        get

            return self:_lSingle

        end get

        set

            self:_lSingle := value

            self:NotifyPropertyChanged("lSingle")

            //----------------------------------

            if lSingle == true

                self:ClearFieldRBsHotel()

                _lSingle := true

                eHotel := HotelAccommodation.Single

                self:lResultHotel := eHotel:ToString()

            endif

        end set

    end property

    property lDouble as logic

        get

            return self:_lDouble

        end get

        set

            self:_lDouble := value

            self:NotifyPropertyChanged("lDouble")

            //---------------------------------

            if lDouble == true

                self:ClearFieldRBsHotel()

                _lDouble := true

                eHotel:= HotelAccommodation.Double

                self:lResultHotel := eHotel:ToString()

            endif

        end set

    end property

    property lSuite as logic

        get

            return self:_lSuite

        end get

        set

            self:_lSuite := value

            self:NotifyPropertyChanged("lSuite")

            //------------------------------------

            if lSuite == true

                self:ClearFieldRBsHotel()

                _lSuite := true

                eHotel := HotelAccommodation.Suite

                self:lResultHotel := eHotel:ToString()

            endif

        end set

    end property

    property lNone as logic

        get

            return self:_lNone

        end get

        set

            self:_lNone := value

            self:NotifyPropertyChanged("lNone")

            //------------------------------------

            if lNone == true

                self:ClearFieldRBsHotel()

                _lNone := true

                eHotel := HotelAccommodation.None

                self:lResultHotel := eHotel:ToString()

            endif

        end set

    end property

    //===================================================

end class

end namespace

==========================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

begin namespace RadioButton03

    partial class MultiRBsetsView inherit Window

    constructor(oVM as MultiRBsetsViewModel)

        super()

        InitializeComponent()

        self:DataContext := oVM

    return

    //----- needed to stop the 'damage' to the VM object still bound to other View ! -----

    private method Window_Closing( sender as System.Object, ;

                    e as System.ComponentModel.CancelEventArgs ) as System.Void

        self:DataContext := null

    return

    end class

end namespace

==========================================================================

<Window x:Class="RadioButton03.MultiRBsetsView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Multi RB sets :" Height="300" Width="300"

    Background="LightBlue" Closing="Window_Closing" >

    <Grid>

        <RadioButton Content="Vegan" GroupName="Food" Margin="42,42,0,0" IsChecked="{Binding Path=lVegan}"/>

        <RadioButton Content="Vegetarian" GroupName="Food" Margin="42,62,0,0" IsChecked="{Binding Path=lVegetarian}"/>

        <RadioButton Content="Carnivore" GroupName="Food" Margin="42,82,0,0" IsChecked="{Binding Path=lCarnivore}"/>

        <RadioButton Content="FishOnly" GroupName="Food" Margin="42,102,0,0" IsChecked="{Binding Path=lFishOnly}"/>

        <RadioButton Content="Single" GroupName="Hotel" Margin="42,138,0,0" IsChecked="{Binding Path=lSingle}"/>

        <RadioButton Content="Double" GroupName="Hotel" Margin="42,158,0,0" IsChecked="{Binding Path=lDouble}"/>

        <RadioButton Content="Suite" GroupName="Hotel" Margin="42,178,0,0" IsChecked="{Binding Path=lSuite}"/>

        <RadioButton Content="None" GroupName="Hotel" Margin="42,198,0,0" IsChecked="{Binding Path=lNone}"/>

        <TextBlock Margin="162,104,0,0" Text="{Binding Path=lResultFood}" Background="Yellow"/>

        <TextBlock Margin="162,199,0,0" Text="{Binding Path=lResultHotel}" Background="Yellow"/>

    </Grid>

</Window>

==========================================================================

==========================================================================

==========================================================================

==========================================================================

==========================================================================

PHH - 11th. December 2014.


A much better alternative to Radio Buttons !?

Lets be bold - lets make some sensible statements to help us improve our Data Binding with

WPF / XAML in the future.

Radio Buttons belong to 'yesteryear' - they are not really 'Data Binding' friendly.

RBs are a single value, or a selection from many (within a group).

A selection from a 'Drop List' or ComboBox is also one selection form many.

Both approaches can start with 'nothing' being selected from the available group.

We need to design and create our 'enums' correctly to easily allow the above, and more.

Drop Lists can be a set of 'enums'.

A 'selected' ComboBox item can be easily bound, and binding works nicely.

This approach can also be used within item rows in a 'DataGrid' control.

From now on (personally) I will try and NOT use Radio Buttons, instead using selected items from drop lists.

It looks like we need a suitable sample, and one to duplicate and replace the previous example.

We need a sample to allow us to explore the DL possibilities, and then a better sample to show greater

potential when dealing with real life situations.

Lets start in this introduction with a look at the two previously used 'enum's :-

===============================================

And now a new 'View' object with no Radio Buttons at all, but plenty of Drop Lists.

The following exploratory example has many more DL's than we can in fact manage

with, simply so that we can experiment.

Take a look at the following image - 3 ComboBoxes in each group are for Integer,

String, and actual 'enum' :-

==============================================================================

In the above image we also have TextBlocks to show the 'selected' values from the

Drop Lists - once again, Int, String & 'enum'.

Eventually, we will only deal in 'enum's for ViewModel public properties as well as List

item contents.

As we go, and get into this, it will get easier, clearer, and simpler to apply and understand.

Lets now move on and go to the next subsection to so the exploratory work.

See you there ...............

PHH - 18th. & 21st.December 2014.


Some 'exploratory' work to replace RB's

====================================================================================

=============================================

===================================================================================

=============================================================================================================

===========================================

===========================================================================================================

===================================================================================================================

========================================================================================================================

==========================================================================================================

=======================================================================================

======================================================================================

=====================================================================================

Moving Forward - Tidying things up :

=======================================================================================================

=============================================================================

=================================================================================

PHH - 22nd.December 2014.


More like a 'real' example

=======================================================================================

=============================================

================================================

===============================================================================================

===========================================================================================================

==============================================

===========================================================================================================

===============================================

================================================================================================

===============================================

============================================================

===================================================================================================================

=====================================================================

======================================================================================================

=====================================================================

========================================================================

====================================================================

======================================

=================================================================================

================================================================================================

=================================================================

===================================================================================================

============================================================================================================

=================================================================================================================================================================

================================================================================================

===========================================

================================================================

=================================================================

==============================================================================================

PHH - 22nd. & 24th. December 2014.


working script and code

======================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace RadioButton03

    partial class Window1 inherit Window implements INotifyPropertyChanged

        export _oMRBSVM as MultiRBsetsViewModel

        // ----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            super()

            InitializeComponent()

            self:Initialize()

        return

        //----- Methods -----

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, ;

                            System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method Initialize() as void

            self:oMRBSVM := MultiRBsetsViewModel{FoodPreference.FishOnly, HotelAccommodation.Double }

            /*local implied oList := enum.GetValues(typeof(FoodPreference))

            MessageBox.Show(oList:Length:ToString(),"Enum length :")*/

        return

        private method pbLaunchRBs_Click( sender as System.Object, ;

                        e as System.Windows.RoutedEventArgs ) as System.Void

            local oPCVM as PersonChoicesViewModel

            oPCVM := PersonChoicesViewModel{DataModels.GetSinglePersonChoices()}

            local oPCV as PersonChoicesView

            oPCV := PersonChoicesView{oPCVM}

            oPCV:Show()

            /* local oPCDGV as PersonChoicesDG_View

            //oPCDGV := PersonChoicesDG_View{}

            oPCDGV := PersonChoicesDG_View{oPCVM}

            oPCDGV:Show()   */

          /*  local oDLAV as DropListAlternativeView

            oDLAV := DropListAlternativeView{DropListAlternativeViewModel{}}

            oDLAV:Show()*/

            /*local oMRBS as MultiRBsetsView

            oMRBS := MultiRBsetsView{self:oMRBSVM}

            oMRBS:Show()*/

        return

        //----- Properties -----

        property oMRBSVM as MultiRBsetsViewModel

            get

                return self:_oMRBSVM

            end get

            set

                self:_oMRBSVM := value

                self:NotifyPropertyChanged("oMRBSVM")

            end set

        end property

    end class

end namespace

======================================================================================

//----- PersonChoices.prg -----

//----- Monday December 23rd. 2014.-----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==============================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

#using RadioButton03

begin namespace RadioButton03

    class PersonChoices implements INotifyPropertyChanged

        //----- Fields -----

        private _personChoicesId as long

        private _firstName as string

        private _lastName as string

        private _country as string

        //---------------------------------

        private _eFP as FoodPreference

        private _eHA as HotelAccommodation

        private _ePP as PetPreference

        private _eTM as TransportMode

        //---------------------------------

        private _photoImage as string

        //---------------------------------

        private _eListFP as List<FoodPreference>

        private _eListHA as List<HotelAccommodation>

        private _eListPP as List<PetPreference>

        private _eListTM as List<TransportMode>

        //------------------------------------------

        //----- Properties -----

        property eListFP as List<FoodPreference>

            get

                return self:_eListFP

            end get

            set

                self:_eListFP := value

                self:NotifyPropertyChanged("eListFP")

            end set

        end property

        property eListHA as List<HotelAccommodation>

            get

                return self:_eListHA

            end get

            set

                self:_eListHA := value

                self:NotifyPropertyChanged("eListHA")

            end set

        end property

        property eListPP as List<PetPreference>

            get

                return self:_eListPP

            end get

            set

                self:_eListPP := value

                self:NotifyPropertyChanged("eListPP")

            end set

        end property

        property eListTM as List<TransportMode>

            get

                return self:_eListTM

            end get

            set

                self:_eListTM := value

                self:NotifyPropertyChanged("eListTM")

            end set

        end property

        //----- Events -----

        event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

        //----- Constructors -----

        constructor()

            //------- getting a 'NULL' ---------

            /*local oNDT as Nullable<DateTime>

            oNDT := Nullable<DateTime>{}    //----- without a value ------

            local oNLG as System.Nullable<logic>

            oNLG := Nullable<logic>{}*/

            //------------------------------------------------------------

            super()

            self:Initialize()

            self:PersonChoicesId := -1

            //---------------------------------

            self:FirstName := "..."

            self:LastName := "..."

            self:Country := "..."

            //----------------------

            self:eFP := FoodPreference.NoneAsYet

            self:eHA := HotelAccommodation.NoneAsYet

            self:ePP := PetPreference.NoneAsYet

            self:eTM := TransportMode.NoneAsYet

            //--------------------------------------

            self:PhotoImage := "..."

        return

        constructor(cF as string, cL as string, cCT as string, eF as FoodPreference,;

                    eH as HotelAccommodation, eP as PetPreference, eT as TransportMode,;

                    cPhotoImg as string)

            super()

            self:Initialize()

            self:PersonChoicesId:= -1

            //---------------------------------

            self:FirstName := cF

            self:LastName := cL

            self:Country := cCT

            //----------------------

            self:eFP := eF

            self:eHA := eH

            self:ePP := eP

            self:eTM := eT

            //--------------------------------------

            self:PhotoImage := cPhotoImg

        return

        //----- Methods -----

        method Initialize() as void

            self:eSetFP2()

            self:eSetHA2()

            self:eSetPP2()

            self:eSetTM2()

        return

        method eSetFP2() as void

            local implied aFoodValues := Enum.GetValues(typeof(FoodPreference))

            self:eListFP := List<FoodPreference>{}

            //-----------------------------------------------------------------

            foreach i as int in aFoodValues

                local cEnumF as string

                local eFP as FoodPreference

                cEnumF := Enum.GetName(typeof(FoodPreference), i)

                eFP := (FoodPreference)Enum.Parse(typeof(FoodPreference), cEnumF)

                self:eListFP:Add(eFP)

            next

        return

        method eSetHA2() as void

            local implied aHotelValues := Enum.GetValues(typeof(HotelAccommodation))

            self:eListHA := List<HotelAccommodation>{}

            //-----------------------------------------------------------------

            foreach i as int in aHotelValues

                local cEnumH as string

                local eHA as HotelAccommodation

                cEnumH := Enum.GetName(typeof(HotelAccommodation), i)

                eHA := (HotelAccommodation)Enum.Parse(typeof(HotelAccommodation), cEnumH)

                self:eListHA:Add(eHA)

            next

        return

        method eSetPP2() as void

            local implied aPetValues := Enum.GetValues(typeof(PetPreference))

            self:eListPP := List<PetPreference>{}

            //-----------------------------------------------------------------

            foreach i as int in aPetValues

                local cEnumP as string

                local ePP as PetPreference

                cEnumP := Enum.GetName(typeof(PetPreference), i)

                ePP := (PetPreference)Enum.Parse(typeof(PetPreference), cEnumP)

                self:eListPP:Add(ePP)

            next

        return

        method eSetTM2() as void

            local implied aTransportValues := Enum.GetValues(typeof(TransportMode))

            self:eListTM := List<TransportMode>{}

            //-----------------------------------------------------------------

            foreach i as int in aTransportValues

                local cEnumT as string

                local eTM as TransportMode

                cEnumT := Enum.GetName(typeof(TransportMode), i)

                eTM := (TransportMode)Enum.Parse(typeof(TransportMode), cEnumT)

                self:eListTM:Add(eTM)

            next

        return

        method NotifyPropertyChanged(propertyName as string) as void

            if (self:PropertyChanged != null)

                self:PropertyChanged:Invoke(self, System.ComponentModel.PropertyChangedEventArgs{propertyName})

            endif

        return

        method ToString() as string

        return self:FirstName+" "+self:LastName

        //----- Properties -----

        property PersonChoicesId as long

            get

                return self:_personChoicesId

            end get

            set

                self:_personChoicesId := value

                self:NotifyPropertyChanged("PersonChoicesId")

            end set

        end property

        property FirstName as string

            get

                return self:_firstName

            end get

            set

                self:_firstName := value

                self:NotifyPropertyChanged("FirstName")

            end set

        end property

        property LastName as string

            get

                return self:_lastName

            end get

            set

                self:_lastName := value

                self:NotifyPropertyChanged("LastName")

            end set

        end property

        property Country as string

            get

                return self:_country

            end get

            set

                self:_country := value

                self:NotifyPropertyChanged("Country")

            end set

        end property

        //-----------------------------------------------

        property eFP as FoodPreference

            get

                return self:_eFP

            end get

            set

                self:_eFP := value

                self:NotifyPropertyChanged("eFP")

            end set

        end property

        property eHA as HotelAccommodation

            get

                return self:_eHA

            end get

            set

                self:_eHA := value

                self:NotifyPropertyChanged("eHA")

            end set

        end property

        property ePP as PetPreference

            get

                return self:_ePP

            end get

            set

                self:_ePP := value

                self:NotifyPropertyChanged("ePP")

            end set

        end property

        property eTM as TransportMode

            get

                return self:_eTM

            end get

            set

                self:_eTM := value

                self:NotifyPropertyChanged("eTM")

            end set

        end property

        //-----------------------------------------------

        property PhotoImage as string

            get

                return self:_photoImage

            end get

            set

                self:_photoImage := value

                self:NotifyPropertyChanged("PhotoImage")

            end set

        end property

        //-----------------------------------------------

    end class

end namespace //----- VL15_Lists_01

======================================================================================

//----- MyEnums.prg -----

//----- PHH - 1th. December 2014. -----

begin namespace RadioButton03

    public enum FoodPreference

        Vegan

        Vegetarian

        Carnivore

        FishOnly

        NoneAsYet

    end

    public enum HotelAccommodation

        Single

        Double

        Suite

        None

        NoneAsYet

    end

    public enum PetPreference

        Dog

        Cat

        Mouse

        Bird

        Parrot

        Horse

        Goldfish

        None

        NoneAsYet

    end

    public enum TransportMode

        Bicycle

        Motorbike

        Coach

        Train

        Metro

        Airplane

        None

        NoneAsYet

    end

end  namespace

======================================================================================

//----- PersonChoicesModel.prg -----

//----- PHH - December 23rd. 2014. -----

#using System

#using System.Collections.Generic

#using System.Windows

#using System.Collections

#using System.Collections.ObjectModel   //----- ObservableCollection .....

begin namespace RadioButton03

class DataModels

    static method GetSinglePersonChoices() as PersonChoices

        local implied oPC := PersonChoices{"Dan","Logan","Romania", FoodPreference.Carnivore,;

                             HotelAccommodation.Single, PetPreference.Goldfish, ;

                             TransportMode.Airplane, "/Images/DanLogan.jpg"}

        oPC:PersonChoicesId := 13

    return oPC

    //===============================================================================================

    static method GetPersonChoicesCollection() as ObservableCollection<PersonChoices>

    return ObservableCollection<PersonChoices>{GetaBunchOfPersonChoices()}

    static method GetaBunchOfPersonChoices() as List<PersonChoices>

        // ------- getting a 'NULL' ---------

        local oNDT as Nullable<DateTime>

        oNDT := Nullable<DateTime>{}    //----- without a value ------

        //------------------------------------------------------------

        local aList as List<PersonChoices>

        aList := List<PersonChoices>{}

        aList:Add(PersonChoices{"Dan","Logan","Romania", FoodPreference.Carnivore,;

                                     HotelAccommodation.Single, PetPreference.Goldfish, ;

                                     TransportMode.Airplane, "/Images/DanLogan.jpg"})

        aList:Add(PersonChoices{"Brian","Feldman","USA", FoodPreference.Carnivore,;

                                     HotelAccommodation.Double, PetPreference.Horse, ;

                                     TransportMode.Metro, "/Images/BrianFeldman.jpg"})

        aList:Add(PersonChoices{"Chris","Pyrgas","Greece", FoodPreference.Carnivore,;

                                     HotelAccommodation.Suite, PetPreference.Bird, ;

                                     TransportMode.Train, "/Images/ChrisPyrgas.jpg"})

    return aList

    //===============================================================================================

end class

end namespace

======================================================================================

//----- PersonChoicesViewModel.prg -----

//----- PHH - Tuesday 23rd. December 2014. -----

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

//==================================

#using System.ComponentModel   //----- INotifyPropertyChanged .....

begin namespace RadioButton03

class PersonChoicesViewModel implements INotifyPropertyChanged

    private _oPC as PersonChoices

    private _eListFP as List<FoodPreference>

    //----- Properties -----

    property eListFP as List<FoodPreference>

        get

            return self:_eListFP

        end get

        set

            self:_eListFP := value

            self:NotifyPropertyChanged("eListFP")

        end set

    end property

    property oPC as PersonChoices

        get

            return self:_oPC

        end get

        set

            self:_oPC := value

            self:NotifyPropertyChanged("oPC")

        end set

    end property

    //=========================================================

    //----- Events -----

    event PropertyChanged as System.ComponentModel.PropertyChangedEventHandler

    //----- Constructors -----

    constructor()

        super()

        self:Initialize()

    return

    constructor(oP as PersonChoices)

        super()

        self:Initialize()

        self:oPC := oP

    return

    //----- Methods -----

    method NotifyPropertyChanged(propertyName as string) as void

        if (self:PropertyChanged != null)

            self:PropertyChanged:Invoke(self, ;

                        System.ComponentModel.PropertyChangedEventArgs{propertyName})

        endif

    return

    method Initialize() as void

        self:eListFP := List<FoodPreference>{}

        self:eListFP:Add(FoodPreference.Carnivore)

        self:eListFP:Add(FoodPreference.FishOnly)

        self:eListFP:Add(FoodPreference.NoneAsYet)

        self:eListFP:Add(FoodPreference.Vegan)

        self:eListFP:Add(FoodPreference.Vegetarian)

    return

/*    method SetFoodList() as void

        local implied aFoodValues := Enum.GetValues(typeof(FoodPreference))

        self:aFoodE := List<FoodPreference>{}

        self:aFoodV := List<int>{}

        self:aFoodN := List<string>{}

        //-----------------------------------------------------------------

        foreach i as int in aFoodValues

            local nEnumF := i as int

            local cEnumF as string

            cEnumF := Enum.GetName(typeof(FoodPreference), nEnumF)

            self:aFoodV:Add(nEnumF)

            self:aFoodN:Add(cEnumF)

            self:eSelectedFood := (FoodPreference)Enum.Parse(typeof(FoodPreference), cEnumF)

            self:aFoodE:Add(self:eSelectedFood)

            //----------------------------

            self:cSelectedFood := cEnumF

            self:nSelectedFood := nEnumF

        next

    return

    method SetHotelList() as void

        local implied aHotelValues := Enum.GetValues(typeof(HotelAccommodation))

        self:aHotelE := List<HotelAccommodation>{}

        self:aHotelV := List<int>{}

        self:aHotelN := List<string>{}

        //-----------------------------------------------------------------

        foreach i as int in aHotelValues

            local nEnumH := i as int

            local cEnumH as string

            cEnumH := Enum.GetName(typeof(HotelAccommodation), nEnumH)

            self:aHotelV:Add(nEnumH)

            self:aHotelN:Add(cEnumH)

            self:eSelectedHotel := (HotelAccommodation)Enum.Parse(typeof(HotelAccommodation), cEnumH)

            self:aHotelE:Add(self:eSelectedHotel)

            //----------------------------

            self:cSelectedHotel := cEnumH

            self:nSelectedHotel := nEnumH

        next

    return*/

    //----- Properties -----

   /* property aFoodE as List<FoodPreference>

        get

            return self:_aFoodE

        end get

        set

            self:_aFoodE := value

            self:NotifyPropertyChanged("aFoodE")

        end set

    end property

    */

    //------------------------------------------------

end class

end namespace

======================================================================================

#using System

#using System.Collections.Generic

#using System.Linq

#using System.Text

#using System.Windows

#using System.Windows.Controls

#using System.Windows.Data

#using System.Windows.Documents

#using System.Windows.Input

#using System.Windows.Media

#using System.Windows.Media.Imaging

#using System.Windows.Navigation

#using System.Windows.Shapes

BEGIN NAMESPACE RadioButton03

    PARTIAL CLASS PersonChoicesView INHERIT Window

    CONSTRUCTOR()

        SUPER()

        InitializeComponent()

        return

    CONSTRUCTOR(oPCVM as PersonChoicesViewModel)

        SUPER()

        InitializeComponent()

        self:DataContext := oPCVM

        //MessageBox.Show(oPCVM:oPC:LastName,"My Last name :")

        //MessageBox.Show(oPCVM:oPC:eFP:ToString(),"My eFP detail :")

    return

    END CLASS

END NAMESPACE

======================================================================================

<Window x:Class="RadioButton03.PersonChoicesView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="PersonChoices" Height="420" Width="400">

    <Grid>

        <TextBox Height="23" Margin="50,28,0,0"

                 Text="{Binding oPC.FirstName}" />

        <TextBox Height="23" Margin="50,56,0,0"

                 Text="{Binding oPC.LastName}"/>

        <TextBox Height="23" Margin="50,84,0,0"

                 Text="{Binding oPC.Country}"/>

        <TextBox Height="23" Margin="50,112,0,0"

                 Text="{Binding oPC.PhotoImage}" Width="155"/>

        <!--=====================================================================================-->

        <ComboBox Margin="50,156,0,0" ItemsSource="{Binding oPC.eListFP}" SelectedItem="{Binding oPC.eFP}"/>

        <ComboBox Margin="50,185,0,0" ItemsSource="{Binding oPC.eListHA}" SelectedItem="{Binding oPC.eHA}"/>

        <ComboBox Margin="50,214,0,0" ItemsSource="{Binding oPC.eListPP}" SelectedItem="{Binding oPC.ePP}"/>

        <ComboBox Margin="50,243,0,0" ItemsSource="{Binding oPC.eListTM}" SelectedItem="{Binding oPC.eTM}"/>

        <!--=====================================================================================-->

        <TextBox Height="23" Margin="215,157,0,0" Text="{Binding oPC.eFP}" />

        <TextBox Height="23" Margin="215,185,0,0" Text="{Binding oPC.eHA}"/>

        <TextBox HorizontalAlignment="Left" Height="23" Margin="215,214,0,0"

                 TextWrapping="Wrap" Text="{Binding oPC.ePP}" VerticalAlignment="Top" Width="120"/>

        <TextBox Height="23" Margin="215,243,0,0" Text="{Binding oPC.eTM}"/>

        <Image HorizontalAlignment="Left" Height="107" Margin="233,28,0,0"

                VerticalAlignment="Top" Width="102" Source="{Binding oPC.PhotoImage}" Stretch="Fill"/>

        <!--<ComboBox Margin="215,290,0,0" Width="120" ItemsSource="{Binding eListFP}"/>-->

    </Grid>

</Window>

======================================================================================

<Application x:Class="RadioButton03.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <!--"Window1.xaml"-->

    <Application.Resources>

        <Style TargetType="TextBlock" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="26" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="TextBox" >

            <Setter Property="HorizontalAlignment" Value="Left" />

            <Setter Property="Height" Value="26" />

            <Setter Property="TextWrapping" Value="Wrap"/>

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="Width" Value="120"/>

            <!--<Setter Property="Background" Value="Yellow"/>-->

        </Style>

        <Style TargetType="RadioButton" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

        </Style>

        <Style TargetType="Button" >

            <Setter Property="VerticalAlignment" Value="Stretch"/>

            <Setter Property="HorizontalAlignment" Value="Stretch"/>

            <Setter Property="Height" Value="Auto"/>

            <Setter Property="FontSize" Value="16"/>

            <Setter Property="FontWeight" Value="Bold"/>

            <Setter Property="Background" Value="Yellow"  />

            <Setter Property="VerticalContentAlignment" Value="Center"/>

            <Setter Property="HorizontalContentAlignment" Value="Center"/>

        </Style>

        <Style TargetType="ComboBox" >

            <Setter Property="VerticalAlignment" Value="Top"/>

            <Setter Property="HorizontalAlignment" Value="Left"/>

            <Setter Property="Width" Value="125"/>

            <Setter Property="Background" Value="LightCoral"/>

            <Setter Property="Height" Value="24" />

        </Style>

    </Application.Resources>

</Application>

======================================================================================

======================================================================================

======================================================================================

PHH - 24th. December 2014.


Even more like a real example - DataGrids

==================================================================================================================

===========================================================================================================

======================================================================================================================

================================================================

Starting at the Beginning ? :

=======================================================================================================================================================

===============================================================================================================================================================

===================================================================================================================================

======================================================================================================================

====================================================================================================================================

=========================================================================================

=========================================================================================================

========================================================================================================

==================================================

===========================================

=========================================================================================================================

===================================================

=============================================================================================================

PHH - 24th. December 2014.


working script and code

======================================================================================

======================================================================================

======================================================================================

======================================================================================

======================================================================================

======================================================================================

======================================================================================

======================================================================================

======================================================================================

PHH - 24th. December 2014.


Appendix B - instantiating Model data objects before calling 'View'

===========================================================================================================

PHH - 9th. December 2014.


Appendix C - 'AutoMapper'

To get us going we need to see what the internet has to offer us as general information.

Here is a very useful link :-

https://github.com/AutoMapper/AutoMapper

=================================================================================================================

Looks like we all need to say thanks to 'Jimmy' - Jimmy Bogard, et al.

===========================================================================================================

Having had a play with this (new to me) technology, I think the title ought to be extended so we can more easily tell

what it is, and does.

Although it will never 'catch on' it should be called "Auto Mapper, with Data Conversion and Transfer Through".

As well as being able to map one existing class to another existing class (generally by properties) it also is

used to pass (and/or copy) data values from the source object to the target object.

We will do some extensive exploration of Jimmy's "AutoMapper".

To put it simply, this is a great tool, if used in the correct manner - if we do not do our homework carefully and

thoroughly, then we may rush off and use it in the wrong way ;-)

Lets experiment, explore, and learn together!

"We make a map and then we use that mapping - two parts to this!"

See you in the next sub-section ...........

PHH - 13th. & 14th. September 2014.

Addendum :

Here is an interesting snippet from Rick Strahl :-

http://weblog.west-wind.com/posts/2009/Aug/04/Simplistic-Object-Copying-in-NET

=======================

==========================================================================================================================================

The above would tend to suggest that the 'map / copy' process done by AutoMapper means that we end up with two quite separate

data objects, and that no pointers are passed through the process where the 'Map' is used on two objects, after initially the 'Map'

is created by a configuration process.

PHH - 19th. September 2014.

PHH - 1st. January 2015.


What is it and why do we need it

Here is a useful link :-

https://github.com/AutoMapper/AutoMapper/wiki/Getting-started

===============================================================================================

Answer(s) :

So the answer is, "it is an object-object mapper" ...."mapping is done at a member level" ...

"most often 'member' means property".

There are two parts to 'AutoMapper', the mapping itself (configuration), and then the use of

the 'mapping' to copy across the required data.

[ .. 'AM' = AutoMapper .. ]

Rick Strahl terms 'AM' as a "map/ copy" facility, or tool.

We use it when we have 'conflict of concerns' in the boundary between 'View' and 'Presentation Model',

or more likely 'Presentation Model' (PM) and 'Data Model'.

Often we wish to simplify the 'PM' and many types may end up as 'string' types, when originally they

are numeric, dates or logic types. This more likely for MVC than MVVM apps.

In this simple case we would map the original data object to a simpler representation class of object. The

new 'target' object could have more or less members.

This is where 'AM' can help us out - a LOT !

If we use it wisely and in-line with how it was designed, it will remove a lot of boring and tedious tasks / work.

WARNING - Care - do not try to 'join' two existing classes, there is no point, we can do this in a different way.

Later in this section we see how to bring together FIVE separate classes into one, all having been mapped.

This all sounds good to me ;-0)

Here are some words from Jimmy himself :-

==========================================================================================================

Well then guys, from that list above it sounds as if we all ought to be using 'AM' and most of the time too ;-0)

I will certainly apply it to MVC and WPF for a start.

Here is some more information :-

=======================================================

Yes, this above suggests I for one need to look into Lists, Nested Mapping, and Conditional

Mapping to name but a few topics.

However, one thing at a time, we will get to all the really useful stuff as soon as possible.

PHH - 14th. & 17th. September 2014.

PHH - 1st. January 2015.


What an experienced user had to say

My friend and Colleague Nick Friend had this to say :-

.......................

So it's just a question of the style of use of AM.

This is the sort of thing that I do... in virtually every case I have objects with common naming of fields,

so AM works on "auto-pilot", simply matching fields with the same name and type.

If you want to make some adjustment (e.g. I sometimes replace child object with a null when returning

data to the DB, or in the DB I store an 'int' and I want to pass that to an equivalent 'enum'), you can

use the "ForMember" syntax.

[ .. check out the use of 'Ignore()' in a later sub-section .. ]

Example......

class Class1
{
public string Var1;
public string Var2;
public int MyEnumValue;
public MyOtherClass MyObject;
}

class Class2
{
public string Var1;
public string Var2;
public MyEnum MyEnumValue;
public MyOtherClass MyObject;
}

Mapper.CreateMap<Class1,Class2>().ForMember( c2 => c2.MyEnumValue, m => m.MapFrom(c1 => (MyEnum)c1.MyEnumValue) );

Then use like this in the code body :-

Class2 newtargetobject = Mapper.Map<Class1,Class2>(sourceobjectclass1);

In this case 'Var1', 'Var2' and 'MyObject' all get moved automatically (same name and type), and I use 'ForMember'

to cast the 'int' in 'SourceClass' to the equivalent 'enum' value in 'TargetClass'.

Mapper is STATIC, so really you only need to set up each pair of mappings once, then you can simply call Mapper.Map whenever you want.

To map back (the other way) it would be :-

Mapper.CreateMap<Class2,Class1>().ForMember(c1 => c1.MyEnumValue, m => m.MapFrom(c2 => (int)c2.MyEnumValue));

Then use like this in the code body :-

Class1 newtargetobject = Mapper.Map<Class2,Class1>(sourceobjectclass2);

*** Notice *** that the parameter input is reversed, because we start with a different class object, 2 not 1.

See if that above gets you on the right road - it diod for me, it opened up the whole topic area, and made me

able to write this whole 'Appendix B' section.

============================================================================

One of my early comments :-

"I have to confess that at the moment it is not that obvious why we need to have the second class and object,

but no doubt it will become very obvious soon ;-0) "

However, I can say I used Nick's code above to make my own working first demo app in WPF. This can

be seen in the following sub-section entitled "A Simple example of use."

Enjoy your learning trip, I did mine ...............

PHH - 14th. September 2014.

PHH - 1st. January 2015.


How to get it and the documentation

Once again we need a link and URL to get our foot in the door.

Here is a useful link :-

https://github.com/AutoMapper/AutoMapper

=================================================================================================================

Okay folks the above does work in the console, BUT, it feels a bit primitive, there is a better way ;-0)

We will deal with the 'NuGet' manager method soon - first keep on reading.

The link to help you acquire this is :-

http://docs.nuget.org/docs/start-here/installing-nuget

=============================================================================================================================================

If you wish to drive your AutoMapper install from the web source, then go and use this link :-

http://automapper.org/

============================================================================================

Here is what I did with a working project of mine open in the Visual Studio IDE :-

[ .. notice my project was entitled 'Guestbook2' .. ]

==============================================================================================================================

You get enough message detail to indicate when you have been successful with the download and install.

This old fashioned way of downloading places the required DLLs in a folder under the selected project.

We now need to find then and add them to the References node (or folder).

Right click the References node and from the context menu select to 'Add' a new Reference - here is what I saw :-

=============================================================================================================

You will need to navigate to the correct folder ('packages') within the project being used (see Guestbook2 for my example).

If all seemingly goes well, then to get REAL proof go to the References node in the SE pane and expand it, as seen below :-

=======================================================

Yep! these are the two assemblies (dlls) that you require.

And these are the two assemblies that 'using' directives will point to at the top of our code files.

Here is some more information on my VS set-up etc. :-

================================================================================

Okay then folks, we now have the 'AutoMapper' framework (the old fashioned way) so what

can we do with it ? And how do we know what can be done ?

We need some documentation ...............

Wiki - Documentation etc. :

Once you get onto a genuine 'AM' site there are lots of links to follow to a 'wiki'.

Here is the one I am using right now :-

https://github.com/AutoMapper/AutoMapper/wiki

More on documentation later - just check out a few of these following image details :-

Samples for our use and learning :

======================================================================================================

==========================================================================================================

https://github.com/AutoMapper/AutoMapper/wiki/Getting-started

=======================================

Enough of documentation sources for the moment, lets do the download and install a modern way.

Try this out below, for a project you have open in the VS IDE, and showing in the SE pane.

Using - Manage 'NuGet' Packages :

The following section applies to the VS 2013 projects I have tried recently. The VS 2014 CTP3

installation seems to give me issues at the moment - so VS 2013 it is then folks ;-0)

Take your project and in the SE pane right click the project node, with this now in focus use

the menu bar and select 'Tools' then 'NuGet' Package Manager', and then further select

"Manage NuGet Packages for Solution..."

See the following image :-

======================================================================================

After the dialog screen appears, type into the search input box 'automapper' as seen in the

following image :-

=========================================================================================================================================================

Obviously, you need to click the 'Install' button to get things to kick into action.

Here is what shows when all is done - install over :-

========================================================================================================================

Now you need do no more - just go and check the References node in the SE pane.

My results from the above exercise look like this seen below :-

=============================================

When we code, and need the use of any 'AM' classes, we then need to add suitable 'using' directives.

Although we often call these 'statements', a "using statement" is actually something else.

So 'using directives' it is !

Check these 'using directives' that we need at the top of our code sections ...........

See what I am currently placing in my code files :-

=============================================================

Lines 16 and 17 are all that we need before we can get going with AutoMapper.

PHH - 14th. & 17th. September 2014.

PHH - 1st. January 2015.


Where do we Configure 'AutoMapper' ?

Here is something to read, digest, and get us going :-

===========================================================================================================

So far with my demo apps and experiments with WPF I have used only the STATIC method for setting up

mappings.

This is best done for most applications at the start or launch of the app. This could change when guys do

larger and more complex apps.

By doing the configuration at the start of many apps then the scope of the mapping will be across the whole

application.

Here is a small example of mine, the 'AllInTogether' class is the main window of a WPF project.

Check this out carefully :-

===========================================================================================================================

In the above image it is lines 57 - 59 which configure the mapping.

Other code has been collapsed as it does not need to be seen for what we are looking at and studying

at the moment.

Note that the 'Initialize' method is run once at the opening of the app when the Windows is instantiated

and shown.

What if we configure multiple times ? :

Well, if Jimmy has done his work well, we should be able to make multiple attempts at the same mapping

configuration without any issues or problems.

Lets see what happens when we try to make three similar mappings for the Purchase class pair.

Check this out and see the working app display :-

===========================================================================================================================

Yes, I know that just because the application runs does not say that all is well for other parts and in more complex

projects. But we don't get an error and the WPF binding seems to be OK.

Just use caution and good sense - as always ;-0)

A Possible Way Forward - Mapping :

If for most apps we need to set our mapping configurations early on in the execution process, then

why don't we keep all the mappings together in one method. Check this out below :-

===============================================================================================================

As we get more mappings we could make some commented sections to keep things tidy and organised.

Then when we launch the app we see the following code responsible for the launch - check this out :-

============================================================================================================

Notice that in the above code lines 33 through 48 need to be left to be executed, just before the loose coupling

is made in line 49 - that is because the data values and objects held within the class objects.

Although in our example the data in 'oPur' for example, is always the same, in a real life app it with be fluid or

dynamic in nature. Quite often coming from a database.

No doubt we will get more and better ideas as we explore 'AM' more fully, and also see examples from others.

PHH - 14th. & 17th. September 2014.

PHH - 1st. January 2015.


Getting a few things straight ...

New guys may get a bit mixed up with the function of 'AutoMapper' !

It simply 'maps' between two existing classes, it does NOT make the second class from the first one.

It is NOT a class creator.

So we need to manually make our second class, to which we wish to map the first.

This second class is where we add extra members (properties and fields) and/or leave some out.

It is also where we can change the data types of these members, if we so wish.

Obviously we usually design and make the first class ourselves ;-)

Or, we can use a class from a third party class.

Here is some advice after I have managed to code myself to my first ever 'AutoMapper' project or

solution success.

The 'AM' framework allows us to 'map' two different and existing classes, in a configuration sense / way -

NOT and action sense / way.

It also then allows us to use the mapping code to convert data (in an active way) from one object to data in

a second object, as long as the mapping for the object classes is configured, or known.

To go the other way (backwards / reverse) we need a second mapping for the two classes, but with 'Source'

and 'Target' classes reversed in the configuration.

The mapping is actually done at a 'Property' (or Field) level, and Types are often changed or swapped in the

mapping process.

We can even create extra properties (and fields), and make one up (a new one) from multiple existing members.

[ .. a member is a Property or a Field .. ]

Checkout the first simple example in a couple of sub-sections from here.

PHH - 14th. September 2014.

PHH - 1st. January 2015.


How do we use 'AM' ?

In the following text the 'type' refers to classes - source and destination, or source and target.

=========================================================================================================

These last few lines seem to me to partly mask that the 'action' is a data transfer or copying - USING - the

earlier 'mapping'.

So we have to read the creation process as :-

Mapper.CreateMap< "Source Object", "Target Object" >();

or

Mapper.CreateMap< "Source Object", "Destination Object" >();

Well guys, I think we can handle this OK ;-0) We need to do some experiments I feel.

AND - there are LOTs of small details to get our heads around - there always is ;-0)

Lets move on, see you in the next sub-section ................

PHH - 14th. September 2014.

PHH - 1st. January 2015.


Lambda expression - use with 'AM'

Do NOT panic !

Lambda expressions look complicated and difficult but are quite straight forward to use.

All we need do is see how they are applied, and then copy and adapt their use.

This is what I do and they work the majority of the time ;-0)

Lets look at a few lines of code which include some Lambda expressions - check these out :-

[ .. read as 'CreateMap< c1, c2 >() .. ]

===========================================================================================================

===========================================================================================================

[ .. this syntax is the same as the first, only symbol characters have been changed .. I personally prefer this .. ]

We can read line 36 (or 38) as ..... " for the property member in 'VM_Contact' named 'Fullname', map this to the two

member properties in 'Contact', joining 'Firstname' to 'Surname' with an added space between them."

The following image shows the two extra members (properties) beneath the dashed line - check this out :-

====================================================================

Making things a bit clearer - slightly better syntax :

In the following image you see syntax and symbol / variable name choice which I have copied

and adapted from published code.

However, I find there are a couple of things we can do to make the code easier to read and understand.

================================================================================

In the next sub-section below, we will see how we can replace the 'c1' and 'c2' and 'm' symbols

for something better.

For the moment, lets just see an alternative to 'Ignore' - check out line 50 below :-

===================================================================================

At this moment I am not sure of the difference between an 'Ignore()' and a 'UseValue(null)'

but in the example I am following I know that I wish to 'Ignore' the property, as I don't wish to

use a value, null or otherwise.

Lets move on .............

Lets improve 'c2' and 'c1' and 'm' :

Let us now take some time to explore the previous syntax to see if we can make it more clear to read.

Previously I think 'c1' and 'c2' were used to represent classes, 'class 1' and 'class 2', and then 'm' to

represent 'member' (field and/or property).

Let us now change things to be more suitable to what I am actually doing in my code samples.

In the 'CreateMap' method the inputs are 'Source' and 'Target' classes, so we can represent these quite

nicely with 's' and 't'.

Also, since I am dealing totally in terms of properties (and not fields) we can use 'p' in place of 'm'.

Check out the following 'adjusted' syntax to see how this now reads :-

============================================================================================================

To me this is a pleasant improvement, and does make coding life a bit easier.

WARNING - do be aware however, that 's', 't', and 'p' are just symbols and could actually be anything, as

long as the 'pattern' of use is correct - meaning that the symbols are placed in the correct part of the syntax / code.

So now we can see that 'ForMember' is used to specify a target property mapping, for possible source members,

that is fields or properties.

Check out the next small image to see some field mapping :-

What is the point of 'Ignore' or 'UseValue(null)' ? :

Because we have 'Auto' in the tool name of 'AutoMapper', then if we have two members (property or field) with

sufficiently similar names, the tool will do its job and make a mapping, so that data values will come across the

class boundary.

So when we know we do NOT wish to have a mapping and a copying take place, we MUST specify this with 'Ignore'

or 'UseValue(null)'.

If we do not do this then we may get some unpredictable results later on in the runtime.

lets move on a step or two ...........

Mapping Fields - and Public v Private :

PHH - 15th & 16th. September 2014.

PHH - 1st. January 2015.


A simple example of use

Like with so many other IT and software topics it is best to start with a simple but real

example, one that we code in ourselves.

Let us do this for our first 'AutoMapper' demo example.

Open up VS 2013 and close any open solution in the IDE.

Now start a new C# Windows WPF application which should look like that below :-

[ .. call it 'AutoMapperDemo1' .. ]

================================================================

Now click the project node in the SE pane to bring it into focus, and add the 'AutoMapper'

assemblies into the References folder/section by following the instructions in sub-section a

couple previous to here.

Now change the Window title by editing the XAML script - see below :-

[ .. also change the height and width .. ]

=============================================================================================

If you do everything right then you should be able to expand the References node and see this :-

==============================================

Okay then guys, lets start to create some code - make your main window C# file look

like that shown in the image below :-

============================================================

And in case you are new to WPF, the code file is shown in the SE pane after suitable

expansion of nodes - as shown below :-

===========================================

Okay then, next we need to go to our code editor and make an empty stub for two new

classes we are about to create - see the following image for the names of these classes :-

================================================================

We now need to fill out the new 'DataCustomer' class with some basic but meaningful properties.

Check out the details shown below :-

============================================================

To help you make the second class quickly, copy and paste the body of the class, and then

change the data types all to 'string' - here is what I have :-

==========================================================

You will notice that at the moment we have six properties with names duplicated in

the second class, so both classes are similar except for the property Types.

Lets now turn our attention to the 'Initialize' method, we need to type code referring to

classes within the 'AM' (AutoMapper) assembly - see below :-

=======================================================

Oh yes !! we need some 'using directives' to point to the required assemblies.

The behaviour of intellisense changes when we add lines 16 and 17 in the image seen below :-

=========================================================

And now our intellisense seems to work just right - study the details in the next image :-

============================================================================================================

And then more success when we go further still - check below :-

===============================================================

We can see from the tool-tip of the intellisense that we need two parameters which are suitable objects

of our classes seen above.

Study this carefully :-

==================================================================================================================

Okay folks, this completes to look like the following :-

===========================================================================

All well so far - BUT - we now need some data values ;-0)

So lets use the technique I often use in demo apps, a STATIC method within the class for which we

need some data values.

Study carefully the following :-

===========================================================

Oh! sorry, I have made a couple of changes, we now have a seventh property, that entitled 'Comment'.

So now we can use the 'Map' method of the 'Mapper' class to copy some data from one object to

the other - 'Source' to 'Target' objects - see below :-

==========================================================================================

Well, the above seems to work just fine - BUT - we can't see the results of the data copying. Note

that we ought not to call it a data transfer really, as the data still remains in the source, and we get

a second copy in the target object.

Viewing the Data Copying results :

Well guys, you know what they say !? 'Seeing is believing' in that case we need some GUI elements

on our WPF form so that we can bind some values to them.

Checkout carefully below to see the required XAML script :-

================================================================================

*** Note *** that the alternative syntax to "{Binding Path=DoB}" is "{Binding Dob}" with the

'Path=' dropped or not needed.

Obviously, this alternative syntax refers to all lines 16 through 22.

Okay then guys, almost there, now we have data values, and binding 'links' to UI elements,

where abouts do we make our 'loose coupling' ?

We need to carefully examine the following image details - see line 36 in particular :-

==============================================================================================================

Well, as you can see above, we do appear to have data values been shown on the UI surface.

So we have success with our first 'AM' project but we have used the most simple automatic mapping

and nothing else as such.

Before we move on to another sub-section, to explore the AM in more detail, lets take this opportunity

to add an extra feature into our existing simple application.

Adding an extra 'calculated' property to the Target class :

Okay then folks, lets look back and see what our simple mapping was in our sample so far - check this :-

==================================================================

Line 32 shows how simple it was !

Let us no add another (extra) property to the target class, one entitled 'FullName'.

Below are some details regarding the addition of this - see the intellisense, as well as line 66 :-

=================================================================================================================

In many ways this is like a calculated property, as it is made up from other separate properties

from the source class of object.

Lets study in detail the final code line - check below :-

======================================================================================================================================================

Line 31 basically reads ... "take from the source the property FirstName, and then a space, and then the

property entitled SecondName, and place the concatenated result in a property called 'FullName'

in the target class object.

We can shorten the line for easy use as seen below :-

[ .. also note the GUI display works well .. ]

================================================================================================================

You may also appreciate checking out the XAML editor and UI surface - check this below :-

=======================================================================================================

Okay then folks, its time to move on, we have been successful with making our first simple mapping, and

subsequent use of this mapping to copy data values from a source object to a target one.

In the final version of our app, the target class was no longer similar to the source class in regards

to the number of properties.

We need to make some experiments to allow us to explore just how the 'AM' works.

Lets move on to the next section where we will do some very interesting things ;-0)

See you there ................

PHH - 14th. & 15th. September 2014.

PHH - 1st. January 2015.


Our own more complex example

We need to investigate just what is going one behind the behaviour we have already seen

with AutoMapper working with our first simple example.

It is easy to understand that and 'auto' mapping can be done when property names are not

just similar, but identical - like in the last sub-section.

Lets move on to see how far the comparisons, and subsequent 'matches' go.

When does 'Auto' mean 'automatic' - or how hard does it try ? :

Let us make a new and third class, similar to our last target class, but add 'PHH_' to the

front of every property name.

Here is what we are going to try out - check the image below :-

========================================================================================================================

First of all, the important thing is line 38, all we have done to the mapping is change the target class name.

Obviously line 42 had to be changed to also be in-line with the class name change.

BUT - we can get fooled into thinking that nothing has worked, the mapping, and also no data copying.

However, we need to also change the binding details to all the UI text box elements - see below :-

=============================================================================================================================================================

Once we make the binding changes then all seems to work once more !

So this would suggest that the 'Auto' part of the mapping process sees 'PHH_Comment' as 'Comment',

and maps accordingly. Possibly because of the lack of an exact match, we would need to check that.

At first glance it seems like a good idea for 'AM' to match things up for us when they are not exactly

similar in property name - BUT - this may catch us out in the future if we don't exactly know what the rules

are that 'AM' plays to.

Time to move on and try some other things out as a 'voyage of discovery' .........

When does the 'Auto' fail us ? :

Lets try something obvious as a first try to break the 'Auto' thingy. Lets add an 'x' inside the name text

of a couple of properties - check this below :-

=================================================================

[ .. lets ignore the 'PHH_' for now in the explanation, take that as read .. ]

If we look at what has been blanked-out, we see that properties 'SecondxName', 'FirstxName',

and also 'CreditxValue' have failed to be mapped

Obviously, if the first and second names are not mapped then the FullName property will also

be left blank.

Well ! I hear you exclaim, "... that is not surprising ..." and I agree with you on that one.

However, what if we place the 'x' in the text strings such that the RHS of the property name is

still the complete name of that used in the Source class. Check out the next image fully :-

=========================================================================================================================

We get only one entry, and that is not surprising since we force the mapping in line 39 above.

But what if we actually did want to map these 'x' properties, in a similar way to that which we

did previously ? How do we do that ?

Making our own Mapping :

Ignoring the bindings in XAML script for the moment, lets look at the .NET code to see how we

can force the mapping which we require - check these details out thoroughly :-

=========================================================================================================================

Well guys, lines 40 through 46 seem to be the new stuff of ours.

Look in detail at line 42 to see that 'xComment' and 'Comment' are mapped.

Before we can test it out we have also to make changes to the bindings in our XAML script.

Here is what we need - check the details :-

==========================================================================================================

Actually, you can see that I have moved the text boxes so that they are closer together as well.

This gives the following runtime display :-

So the above is done by our own manual mapping - no 'Auto' in sight.

A final thought for this section, something to think upon, if we can force mappings which are not

'auto' or obvious, can we prevent ones which are 'obvious' ?

Lets start by using what we have above and try to 'ignore' a mapping - check this out below :-

=============================================================================================================

[ .. in the above image check lines 37 and 41 .. ]

Well, it may not be cancelling an 'auto' mapping but it looks like the way to do things when

we do need to NOT include a mapping of our choice. We will see more of this later.

For now we ought to quit while we are winning, and go and have some hot food ;-0)

See you in the next sub-section ..........

PHH - 14th. & 15th. September 2014.

PHH - 1st. January 2015.


What does 'Flat Copy' mean ?

If 'Flat' means the same as 'Shallow' then the opposite is 'Deep'.

If we are moving data around in our application, as well as reading and writing it to a back-end

data source, we MUST know exactly what is happening at layer boundaries, when we are most

likely to use 'AutoMapper' to make mapped copies.

=====================================================================

http://www.csharp411.com/c-object-clone-wars/

The following would suggest that 'AM' does not make a complete and separate 'copy', but since it

does a shallow or 'flat' copy then referenced objects must have their references 'passed through'.

=============================================================================================

=========================================================================

PHH - 19th. September 2014.

PHH - 1st. January 2015.


Cloning and Copying

WARING :- this can be a difficult topic to get straight in our heads and minds !!!

=============================================================================================

PHH - 19th. September 2014.

PHH - 1st. January 2015.


Enums - and all that jazz !

When it comes to the topic of 'Enum' we need to distinguish if it is the Enum property within another

class that we are considering, or the mapping of the Enum itself, or one to another Enum.

Lets start with an example of our own - an Enum within a business class, where the class is to be mapped

onto a similar custom / business class.

But first a simple 'Enum' - lets make a folder in the SE pane to contain any code files - check this out :-

======================================

And now if we look into the code file entitled 'OurEnums' we see the following :-

=================================================

Notice that the above image detail would suggest that we have created an 'enum' for the 'Person'

class.

[ .. I have called it 'ePersonType' as there is already a property in the 'PersonView' ]

[ class with a name of 'PersonType'.. ]

Let us now look thoroughly at the next image where I have shown the whole of the two 'paired'

classes - 'Person' and 'PersonView' :-

[ .. my own personal naming preference is 'Person' and 'VM_Person', but we are using web article stuff .. ]

========================================================================================

The new lines I have added to the existing pair of classes, are lines 20, 39, and 50.

And the line requiring editing was line 25, where we added a fourth input parameter.

Now lets take time out for a small but important diversion. Let us see how intellisense helps us with

selecting our enum 'value' from those possible from the defined code - check this out below :-

===================================================================================================

As you can see I have edited the static method in the Person class so that the newly added enum

parameters are used. This fits in with the constructor being edited and updated.

Okay then folks, we now need to see the calling code which brings this stuff altogether and shows us

something on the screen which suggest strongly to us that our code and general approach is working.

Study the following image details VERY carefully :-

==============================================================================================================

It is line 55 in which we use the 'eType' enum property value for display purposes.

Obviously, line 47 calls the method to make the screen display - and here is the result, just to remind you ;-0)

============================================

Looks good to me, we have to be doing something right.

So what can we summarize ? :

Well, possibly that we don't have to do anything special for enum types which are members (fields or properties)

of a custom or business class. The generalised mapping will handle it a-okay.

So basically, this means for the way I usually code things, the above will be sufficient for my project development.

If on the other hand we wish to map one enum with another one, then we do need a mapping, and

we now need to see the 'Jazz' child section from here.

See you in that sub-section ................

PHH - 17th. & 18th. September 2014.

PHH - 1st. January 2015.


the 'Jazz' !

======================================================================================

From Jimmy himself ! [ .. father of 'AutoMapper' .. ]

http://stackoverflow.com/questions/5631377/can-automapper-map-between-a-value-type-enum-and-reference-type-string

*** Remember *** the mapping is between any two types of object, not just custom/ business data classes.

================================================================================================================

http://automapper.codeplex.com/wikipage?title=Custom%20Type%20Converters

PHH - 18th. September 2014.

PHH - 1st. January 2015.


a simple 'Jazz' example

=========================================

PHH - 18th. September 2014.

PHH - 1st. January 2015.


Can we map collections and lists ?

Before we need to worry about List<> and ObservableCollection<> objects as properties

of our VM classes, we need to know just how to deal with them on their own.

By this I mean we need to know how to configure and action a collection of class items

as an object, then we can look into properties of other more complex classes.

If this is not clear, as I am sure it may not be, then we need the help of a simple example.

Lets follow the following URL / link and make it work for us in a simple app. - check this out :-

http://stackoverflow.com/questions/8899444/automapper-copy-list-to-list

Yes, we have two simple class definitions - see below :-

And we can map these in the way we have seen previously, no probs!

Study the next image details, thoroughly :-

As the web article says, the bit which is new, and harder to get right, is as shown beneath :-

[ .. this is the action part of the mapping .. ]

*** Note *** the 'people' object will be a List<Person> type object, and we need to create

this ourselves.

I think we should start a new simple WPF app and try some of this stuff for ourselves. Let's

do this now.

PHH - 1st. January 2015.


Using 'Converters' with AutoMapper

PHH - 17th. September 2014.

PHH - 1st. January 2015.


Can we map multiple Sources to one Target ?

This section is to cover the possibly misguided idea that we need to sometimes combine members from

more than one class into s 'super' class at the same stage as doing a 'mapping'.

Basically, there are other ways to do this which are simpler and which allow us to use AutoMapper as it

comes out of the box.

Here is a sample of what can be found, and what can thence be avoided - check this out :-

============================================================================================================================

So if we are to understand this correctly, we could join a Customer class to a Contact class, to a Order class,

all at the time of creating a mapping.

I have tried the related sample download and neither that nor the 'EnityMapper' class work. I get most things

to work from the internet, but not this.

However, there is no need to do this in this way, we can approach it like the sample I will show below, when

we actually put five classes into one 'super' class.

The way to go !? - make our 'Super' class from the existing ones :

Here is the way to go - below is a simple enough class definition, and it also contains properties

which are all five of different classes which have already been mapped and converted - static

and active AM processes.

Take a good luck at the following image details :-

================================================================================================

We can then easily access each of the members of the five public properties as shown below :-

===================================================================================================================

================================================================================

=============================================================================================================

===================================================================================

PHH - 15th. & 17th. September 2014.

PHH - 1st. January 2015.


Owain Wragg - EntityMapper

==============================================

======================================================================================================

PHH - 17th. September 2014.

PHH - 1st. January 2015.


working code and script

PHH - 17th. September 2014.

PHH - 1st. January 2015.


Some problems and issues - version related

Problems and Issues !?

==============================================================================================================

====================================================================================================================================================

======================================================================================================================================

PHH - 14th. September 2014.

PHH - 1st. January 2015.


Testing our Mappings

====================================================================================

PHH - 14th. September 2014.

PHH - 1st. January 2015.


Watch Demo .....

http://www.dnrtv.com/default.aspx?showNum=155

PHH - 14th. September 2014.

PHH - 1st. January 2015.


Appendix D - 'Cloning' and copying objects

Okay guys, the situation is simple - all the issues and problems come because when the 'literature' talks of

cloning and copying, it often means 'partial' copying and 'partial' cloning - that is what catches us all out ;-0((

Even when we see other Terms used like 'Deep' and 'Shallow' we sometimes see 'Deep' used in the literature

for just another 'level' of copying, and then we drop back to 'Shallow'.

After some 'stuff' from 'Jimmy' - father of 'AutoMapper' - we get some useful details from Jonathan Wood - check out

both of these to get an idea of the problem.

==============================================================================================

When it comes to copying 'Objects' we need to be VERY careful that we know what it is that we are

talking about.

What does copy mean ?, what is an 'Object' in this sense ? What is the difference between 'Clone' and copy ?

We also need then to know and understand about Types - value and reference types.

If we are not careful, and also not quite sure what we are doing, we can get into a right mess ;-0((

Here is something I Googled for - check it out :-

=============================================================================================================================

http://www.codeproject.com/Articles/36067/Shallow-and-Deep-Object-Copying

=====================================================================================================================

Yes, this all makes good sense.

BUT - even when I read his article in detail, and think about his examples, I don't think he gets it right, or goes

far enough - if it were as easy as his code suggests then surely there would be no issue at all to discus !? ;-0((

To my mind a 'Clone' is a complete copy, as deep as you can get. After all 'Clone' has a meaning in the English

language, just as 'Unique' does.

We can't have quite unique, or nearly unique, as we can't have part clone, or nearly a clone. It either is or it isn't.

Ying / Yang. Black/White, Yes/No, True/False - no halfway house in my book ;-0))

With these thoughts in mind let us move on to some of the detailed sub-sections to explore some of the related topics.

See you there .................

PHH - 20th. September 2014.

PHH - 1st. January 2015.


Making things VERY clear - 'which Object ? '

Okay guys, there are objects and there are objects ;-0)

What makes on Object different from another, and when are Objects 'equal' or the same ?

If you are a bit of a newbie, and not done LOTS with objects, you may read the code syntax as much as

you would for simple variables.

Many older guys also may come originally from a time before objects, when a variable was equal (or not) to

another variable, and all we were comparing was the 'value' of those variables.

Now in today's world, when everything seemingly is an Object, then this simplistic approach is no longer

useful. In fact it can be a TRAP to the unwary coder / developer.

We can have two different Objects, both instantiated and based on the same class, with identical property values,

and yet these two Objects are not equal. In fact the concept is not that helpful - yes, we would like to know if they

are the same Object, or in fact two different and separate Objects.

Enter the #HashCode concept / idea :

Okay folks, this is important, VERY important, but not at all difficult. ;-0)

Let us introduce the idea that every Object (or Reference type) is held in memory and has a unique Hash Code.

Well, unique at any one time for Objects in the same scope, so we need to be careful what we say about Hash Codes.

Let us now see a code example for two Objects both of type "ObseravableCollection", strongly typed to 'Person'.

Line 74 and 76 shown below are where our two objects are created - check out the details below :-

================================================================================================================

Yes, we seem to have hit upon the right idea, since the two displayed 'HashCodes' are different, and are in existence

at the same time during the lifetime of the application. The app is small enough for us not to have to worry about

other issues related to duplicate hash-code values.

Before we go on to do some further exploration of hash codes, lets remind ourselves of the 'Person' class - see below :-

===========================================================================================

Yes, in the above image we can see the STATIC method which creates the collection, from fixed

values for the properties of nature 'value type'. Fixed values used each and every time.

Moving on ...................

What does the value of the 'HashCode' mean ? :

Well, in one sense we don't need to worry about the deeper understanding of the hash code (#code) and what it is,

or how it gets made.

What we do need to concern ourselves with is the fact that changing the code slightly in a developing app can cause the

value of the hash code to change.

Let us now edit and clean up our code somewhat, and then run the section again - check below and see that although

the numbers are still different, they are not what they were previously.

Study the following image carefully :-

==================================================================================================================

Now then folks, if we do nothing else than make a small change to our code, and insert line 92 below, and comment

the previous line, number 91, then run the application again, we see an interesting change to the output display.

Study the details shown below, carefully :-

=================================================================================================================

We even see that the hash code remains at 64479624 for both 'OC1' and 'OC2'.

This means that they are exactly the same Object, the same part of memory, and the same 'construct' within it,

are pointed to for OC1 and OC2.

This is not the case previously, when the hash code values were different, then there was two constructs in memory.

It also means that for this later case, if we change any data value on properties within OC1, then these changes are

obviously see in OC2, as they are the same entity. 'It is one !'

Lets move on a step or two ...........

How does this affect our 'ViewModel' ? :

Well folks, this one is easy to answer.

If we have editable data items being displayed on a View (or form) then we need to know if we are in fact changing

value types in the Cloned, or AutoMapped 'ViewModel' or in fact in collection item sub-properties which are outside

of the VM (or Presentation Model).

If we are going to say (and think) that we have 'layered' our project solution correctly. and separated our concerns,

or what other phrases we use, we DO need to know where the objects are that we are editing and changing their values.

I suggest that we can probably better do this by keeping our ViewModels simpler, and base them on simpler DataModels.

We can look at ways and strategies to keep things simple in another sub-section or two. For now lets get 'equal' !

And what about 'Equality' in all this ? :

Well guys, I knew it would come to this eventually ! Can we say is object A 'equal to' object 'B'.

And if we do what is it we are actually asking, and what does it mean as well ?

Check this out - the details in the following image :-

====================================================================================================

I think I have done in the above code, as many coders would do, and use the '==' equality test for comparison.

However, I feel we have been doing this already with our own hash code value comparisons.

Let's change the code and try to run it once more - checkout the following details :-

===========================================================================================

And once again, we are not surprised - the only thing that is not equal is the hash code value, all the values

of the collection item properties is exactly the same.

So for Reference types '==' means is it the same object? do the hash-code values match ?

PHH - 22nd. September 2014.

PHH - 1st. January 2015.


the 'ReferenceEquals' method

When it comes to comparing Objects - reference types and NOT value types - there is another way we

can go about checking to see if we have different objects.

As I say, lets make this simple and ignore the use of value types.

Read the following MSDN information and then we will run our own test code :-

==================================================================================================

===================================================================================

So this seems sensible, how does it look in practice ?

Check out our test code in the following image :-

===============================================================================================

In the above code we see line 102 uses the system STATIC method of 'Object.ReferenceEquals' to

determine if we have different objects being represented by 'OC1' and 'OC2' or whether they are the same

object.

The answer being 'False' is not surprising when we see the following code for our STATIC 'GetPeople'

method we created within our 'Person' class - check this out below :-

[ .. particularly line 202 where we see 'new' .. ]

==========================================================================================

However, if we change out test code as seen below, we get a difference result (or answer) and

it makes sense when we study the details - check this out now :-

===============================================================================================

Once again this is NOT surprising, but what if for some reason one of the objects exists from some

application code a long way away in other parts of the code - then this comparison is most useful.

Lets see how it goes for some mapped objects.

A more Meaningful Example - 'Mapping' :

Okay then guys, if we are not sure just what our 'mapping' code is doing for us, lets tray a simple test

example to see if we can help ourselves to determine just 'what is what'.

Check out the details shown below :-

==================================================================================================================

So the object called 'people' which is a typed List of 'PersonViews' is NOT the same object as the typed collection

which we have called 'personViews'. We have two different objects.

However, we still must be aware that when objects have properties which are reference types, and these type have

nested reference types, we can easily end up with reference pointers to objects in other 'holding' places. So we may

not have a 'Deep' copy - we need to be VERY careful as to how we go about designing our Models.

For now, with the existing example, lets do a comparison test to see if the first item in the List is a different object to

the first item in the 'ObservableCollection'.

Check this out thoroughly :-

============================================================================================================================

And if you are worried that assigning reference type (objects) may mess things up, then try this more

direct coding, different coding, same result - see below :-

=============================================================================================================================

Time to move on ..............

Lets go and learn some more good stuff, in the next sub-section.

See you there ....................

PHH - 23rd. September 2014.

PHH - 1st. January 2015.


Shallow vs Deep - Cloning

For 'simple' objects we see that a 'clone' is quite sufficient and seems to work just fine.

This is because a 'simple' object is one usually made of of fields and properties of value types, and/or strings.

These property types clone okay - BUT - the same process falls down (breaks down) when we have properties

of collections of business, or custom, types.

Unfortunately, these are the VERY objects that we have when we are doing MVVM and MVC work in our code.

If we are going to create and use 'ViewModel's, or 'Presentation Model's, then we MUST get our heads around cloning,

copying, and mapping of our objects.

We don't want to be messing with data within a collection in our View UI elements if in fact it is the same data as is

in the 'DataModel' used to form the 'ViewModel'. We need to know if there is a clean and clear 'separation' between

the two collections.

So to summarise, our problems seem to arise when we have objects within objects, nested.

A collection of even simple business class items, is in itself a referenced type, and in a standard copy (or shallow clone)

will have the references copied over, and not new objects made and newly referenced.

Yes, it can seem complex, confusing, or complicated.

However, once we get to thinking about it, it does become a lot clearer.

And a few well chosen and coded examples helps a lot to aid our understanding too ;-0)

*** Help at Hand !? *** Hash codes :

Although using what is know as 'Hash Codes' (hash as in #) with objects is not a perfect science, it

can aid us in our experimentation and exploration of Cloning & Copying.

Every 'Object' (which is just about everything in .NET) has a 'GetHashCode()' method.

===================================================================

Let us do a simple test to see how this may help us - check this out below :-

=================================================================================================================

Yes, we have two different hash code values - these are for two collection objects form by code in lines 74 and 76.

Although NOT guaranteed to be perfect or 100% definitive, it would appear that these two object as totally different

entities - two separate 'things'.

Now then folks, lets try a similar test on two 'things' which at first appear different.

Lets see the runtime results before we look at the code to make the two items.

Check out carefully the following details :-

===================================================================================================

Well, we can definitely see that we have two similar, or equal values for the hash codes.

So this may well be an indication that the object 'people' and that of 'personViews' is one and the same in memory.

Let us now look at the 'AutoMapper' code we have used to create these - check carefully below :-

================================================================================================================

In the above image (lines 35 & 39) we have coded a mapping from the 'Person' class to the 'PersonView' class, and also in

the reverse direction as well.

We have then on mapped a collection 'Person' items to a strongly typed List of 'PersonView' items.

Something must have worked as we can see from the runtime display shown below :-

============================================================================================

The object with variable name 'personViews' is being displayed in a message box by the following method,

check out all the details shown below :-

=======================================================================================================

So the property entitled 'Fullname', which is not within the Person class, is seen to be both present and

with values.

Now check the 'ToString' method for 'PersonView' as this is what is shown when the collection is bound

to the list box UI element :-

==================================================================================

Without a 'ToString()' method the basic XAML script produces something which looks like that

in the following image :-

============================================================================

And the XAML script is simple enough, with one binding set on line 9.

==============================================================================================

The binding shown in line 9 goes along with the loose couple set in the code (shown below) on line

68, where the 'DataContext' property is associated with the items collection - check it out now :-

==================================================================================

Enough of this example, lets move on ................

Let us spend a short time looking at the somewhat 'old fashioned' method of using 'MemberwiseClone'.

================================================================================================================================

================================================================================================================================

PHH - 20th. September 2014.

PHH - 1st. January 2015.


Deep Cloning for Objects

http://developerscon.blogspot.co.uk/2008/06/c-object-clone-wars.html

========================================================================================================

http://stackoverflow.com/questions/78536/deep-cloning-objects

PHH - 20th. September 2014.

PHH - 1st. January 2015.


Do we really need to Copy/Clone ?

PHH - 22nd. September 2014.

PHH - 1st. January 2015.


'MemberwiseClone' approach - example

PHH - 21st. September 2014.

PHH - 1st. January 2015.


the IClonable Interface

===========================================================================================================================

===============================================================================================================================

================================================================================================================================

===========================================================================================

=============================================================================================

PHH - 20th. September 2014.

PHH - 1st. January 2015.


When 'Deep' means 'Deeper' but not totally 'Deep' !

PHH - 21st. September 2014.

PHH - 1st. January 2015.


Deep (full) copy tool (framework)

Here is what MSDN has to say :-

http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx

=============================================================================================================

None of these REALLY appeal to me, too much like 'Do-it-Yourself' (DIY) in my book. We need a 'tool' in my

humble opinion.

Be CAREFUL, there is a lot of old and out of date 'stuff' out on the web ;-0((

After Googling and finding little on 'Deep' cloning of objects, I came by the following :-

[ .. at first it looked good - but .. read on .. ]

http://ox.no/software/copyable

=========================================================================================================================

I followed the links and did the dowload etc., etc..

Using the Source above (other gives a big red cross) - see below :-

======================================================================================================================================

And then I had what is shown below :-

=============================================================================================================

I downloaded and installed, and added to my References section in the SE pane.

=====================================

But when I tried it I could not get it to compile and/or run - see later in this sub-section.

First a bit more on Copyable ................

Explanation on Use :

http://ox.no/posts/extension-methods-for-copying-or-cloning-objects

===============================================================================================================

I don't get many failures with tools and frameworks and NuGet stuff !? ;-0((

So what's the problem ? Possibly ............

Problems - Age ? 2008 ?? :

It could be that its just too old - I can't find any / or much modern and up to date stuff on it.

Here are the directives I used :-

===================================================

And here is what I got when I tried a simple example :-

====================================================================================================================================

After the time I spent I basically lost faith in the above, it no longer 'felt right'.

So how about a more modern approach ? Here is one I found earlier, although there is still not much

to be found generally on the web.

More Modern - Lets try another Way :

Well here is a more modern way of going about Deep and Shallow cloning or copying of Objects.

It has to be modern as the working sample is for WinRT (Metro as was). below is the URL link :-

http://visualstudiomagazine.com/articles/2013/05/31/the-prototype-pattern-in-net.aspx

And now some motivating starter material from the same link :-

==============================================================================================================

===============================================================================================================

And the 'Get the Code Download' gives me this shown below :-

====================================================================================================================================

This loads into VS 2012 and runs OK. Here is the SE pane content :-

===========================================

=====================================================================

Well its a start, at least we have something running which looks possible - AND - it

does feel better than what else I have found and tried even before and including 'AutoMapper' itself.

So we had better give it a good try out, just to see what can be done.

Just so you can start to feel comfortable, here is some working code which produced the above :-

================================================================================

PHH - 20th. September 2014.

PHH - 1st. January 2015.


Every Object 'hash' its number !

Yes, Okay, the phrase is ... "Every object has its number ..." but seen as we are discussing unique 'hash'

codes for each unique object, the twist of phrase seems appropriate ;-0)

Let us do a short experiment with hash-codes.

We will first make a collection of business object (items) of type 'PersonView', we have seen this class

earlier in the other sub-sections, so no explanation of the following image is necessary - check this out :-

=============================================================================================

In the next image we see that on lines 66 and 68 we make a collection called 'personViews' and then

before making a loose coupling with the View, we list out all the object hash codes for each item in the

collection - the collection type is a strongly type List usually written as 'List<T>'.

Study the following details carefully :-

=====================================================================================================

Line 120 shown above gets the hash code for display, each and every object has a method called 'GetHashCode'.

Check out also that the values of these hash codes are all quite different, as we would expect.

===========================================================================================================================

PHH - 21st. September 2014.

PHH - 1st. January 2015.


Which 'hashes' should we follow and checkout ?

Well folks, this seemingly difficult question has a remarkably simple answer it would seem.

We can forget or ignore the properties of objects which are based on standard data types, those

belonging to the system, or basic framework.

So that leaves custom or business class objects to be tracked and checked. Objects like our

own Customer, Product, Contact, Order .... that sort of thing.

Why is this so ?

The BIG worry :

Our big worry when we use a tool like 'AutoMapper' or some other to clone and copy Objects, is that

deeper down, nested within the properties and sub-properties will be Reference type objects which are

pointed at by 'reference pointers' and NOT a complete copy or clone of the original.

So it is the Reference type objects which effectively create a 'node' to propagate a nested structure of objects.

If we follow and handle the Reference type objects then we will suitably deal with the issue, or problem in hand.

PHH - 22nd. September 2014.

PHH - 1st. January 2015.


Appendix E - managing 'Resources' in XAML

PHH - 10th. December 2014.


Appendix V - Vulcan with 'AutoMapper'

At this current moment Vulcan version 303f has just been released to VPS members to work

with Visual Studio 2013.

This means that is it now worth me doing some work to make suitable sample applications with

'AutoMapper' and Vulcan.

Since the AutoMapper support tool is a 'framework' then it should install into our VN3 projects, and

work just as well as it does with C#.

PHH - 20th. September 2014.


A first VN3 example and install of 'AM'

PHH - 20th. September 2014.


A more complex sample .....

PHH - 20th. September 2014.


Collections within our 'ViewModel's

PHH - 20th. September 2014.


Enums and VN3 / AutoMapper

 Top Previous

PHH - 20th. September 2014.