Monday, February 11, 2008

Web application access mapped network folder

Asp.Net runs in a process as runned by aspnet_user, so web application by default has little privilege accessing OS's file system, and have no right to access network mapped folders.

If requested to do that, you just need to change the user of the process. This can be done by changing machine.config file of the Asp.net version installed and being used for your website.

In , defines the process. by default the user is not specified. you can explicitely specify a username as following:



or you even can specify a password attribute.

Wednesday, January 23, 2008

Create logs in database with EntLib

INTRODUCTION
This lab is demonstrating Logging Block of Enterprise Library 3.0. Specifically it sets up
a logging to database framework. The following 5 steps are all needed for this job.

STEP 1: Set the configure entries
The sample configuration is as follow.

<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</configSections>

<loggingConfiguration name="Logging Application Block" tracingEnabled="true"
defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add databaseInstanceName="Connection String" writeLogStoredProcName="WriteLog"
addCategoryStoredProcName="AddCategory" formatter="Text Formatter"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="Database Trace Listener" />
</listeners>
<formatters>
<add template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=2.9.9.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
name="Text Formatter" />
</formatters>
<categorySources>
<add switchValue="All" name="General">
<listeners>
<add name="Database Trace Listener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="All" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors &amp; Warnings">
<listeners>
<add name="Database Trace Listener" />
</listeners>
</errors>
</specialSources>
</loggingConfiguration>

<connectionStrings>
<add name="Connection String" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database1.mdf;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>



STEP 2: COPY AND CREATE REFERENCE FOR ENTLIB 3.0
Create a folder EntLib3 under the website and copy the assmplies, the add reference for the website.

The assemblies and files used:
Microsoft.Practices.EnterpriseLibrary.Common.xml
Microsoft.Practices.EnterpriseLibrary.Common.dll
Microsoft.Practices.EnterpriseLibrary.Data.xml
Microsoft.Practices.EnterpriseLibrary.Data.dll
Microsoft.Practices.EnterpriseLibrary.Logging.Database.xml
Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll
Microsoft.Practices.EnterpriseLibrary.Logging.xml
Microsoft.Practices.EnterpriseLibrary.Logging.dll
Microsoft.Practices.ObjectBuilder.dll


STEP 3: THE CODE SAMPLE FOR WRITING INTO LOG

// import EntLib assembly's namespace
using Microsoft.Practices.EnterpriseLibrary.Logging;

// write an log entry by the Logger class
Logger.Write("Test","General");


STEP 4: CREATE BACKEND DATABASE STRUCTURE
There are three tables need to be created:

- Category
- CategoryLog
- Log

/****** Object: Table [dbo].[Category] Script Date: 01/16/2008 00:12:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Category](
[CategoryID] [int] IDENTITY(1,1) NOT NULL,
[CategoryName] [nvarchar](64) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED
(
[CategoryID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]


/****** Object: Table [dbo].[CategoryLog] Script Date: 01/16/2008 00:17:56 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[CategoryLog](
[CategoryLogID] [int] IDENTITY(1,1) NOT NULL,
[CategoryID] [int] NOT NULL,
[LogID] [int] NOT NULL,
CONSTRAINT [PK_CategoryLog] PRIMARY KEY CLUSTERED
(
[CategoryLogID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
USE [C:\EXAMPLES2\ENTERPRISE LIBRARY\LOGGING\LOGTODATABASE\LOGTODATABASE\APP_DATA\DATABASE1.MDF]
GO
ALTER TABLE [dbo].[CategoryLog] WITH CHECK ADD CONSTRAINT [FK_CategoryLog_Category] FOREIGN KEY([CategoryID])
REFERENCES [dbo].[Category] ([CategoryID])
GO
ALTER TABLE [dbo].[CategoryLog] WITH CHECK ADD CONSTRAINT [FK_CategoryLog_Log] FOREIGN KEY([LogID])
REFERENCES [dbo].[Log] ([LogID])

/****** Object: Table [dbo].[Log] Script Date: 01/16/2008 00:18:49 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Log](
[LogID] [int] IDENTITY(1,1) NOT NULL,
[EventID] [int] NULL,
[Priority] [int] NOT NULL,
[Severity] [nvarchar](32) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Title] [nvarchar](256) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Timestamp] [datetime] NOT NULL,
[MachineName] [nvarchar](32) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[AppDomainName] [nvarchar](512) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[ProcessID] [nvarchar](256) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[ProcessName] [nvarchar](512) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[ThreadName] [nvarchar](512) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Win32ThreadId] [nvarchar](128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Message] [nvarchar](1500) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[FormattedMessage] [ntext] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED
(
[LogID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

STEP 5: CREATE THE ACCESSING STORED PROCEDURES
They are:
- AddCategory
- ClearLogs
- InsertCategoryLog
- WriteLog

--AddCategory
CREATE PROCEDURE [dbo].[AddCategory]
-- Add the parameters for the function here
@CategoryName nvarchar(64),
@LogID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @CatID INT
SELECT @CatID = CategoryID FROM Category WHERE CategoryName = @CategoryName
IF @CatID IS NULL
BEGIN
INSERT INTO Category (CategoryName) VALUES(@CategoryName)
SELECT @CatID = @@IDENTITY
END

EXEC InsertCategoryLog @CatID, @LogID

RETURN @CatID
END

--ClearLogs
CREATE PROCEDURE [dbo].[ClearLogs]
AS
BEGIN
SET NOCOUNT ON;

DELETE FROM CategoryLog
DELETE FROM [Log]
DELETE FROM Category
END

--InsertCategoryLog
CREATE PROCEDURE [dbo].[InsertCategoryLog]
@CategoryID INT,
@LogID INT
AS
BEGIN
SET NOCOUNT ON;

DECLARE @CatLogID INT
SELECT @CatLogID FROM CategoryLog WHERE CategoryID=@CategoryID and LogID = @LogID
IF @CatLogID IS NULL
BEGIN
INSERT INTO CategoryLog (CategoryID, LogID) VALUES(@CategoryID, @LogID)
RETURN @@IDENTITY
END
ELSE RETURN @CatLogID
END

--WriteLog
CREATE PROCEDURE [dbo].[WriteLog]
(
@EventID int,
@Priority int,
@Severity nvarchar(32),
@Title nvarchar(256),
@Timestamp datetime,
@MachineName nvarchar(32),
@AppDomainName nvarchar(512),
@ProcessID nvarchar(256),
@ProcessName nvarchar(512),
@ThreadName nvarchar(512),
@Win32ThreadId nvarchar(128),
@Message nvarchar(1500),
@FormattedMessage ntext,
@LogId int OUTPUT
)
AS

INSERT INTO [Log] (
EventID,
Priority,
Severity,
Title,
[Timestamp],
MachineName,
AppDomainName,
ProcessID,
ProcessName,
ThreadName,
Win32ThreadId,
Message,
FormattedMessage
)
VALUES (
@EventID,
@Priority,
@Severity,
@Title,
@Timestamp,
@MachineName,
@AppDomainName,
@ProcessID,
@ProcessName,
@ThreadName,
@Win32ThreadId,
@Message,
@FormattedMessage)

SET @LogID = @@IDENTITY
RETURN @LogID

Other issues:
1. Add more categories
It may be important to define a number of categories for logs
this can be done by the configuration file.


<categorySources>
<add switchValue="All" name="General">
<listeners>
<add name="Database Trace Listener"/>
</listeners>
</add>
<add switchValue="All" name="MyCategory">
<listeners>
<add name="Database Trace Listener"/>
</listeners>
</add>
<add switchValue="All" name="MyCategory2">
<listeners>
<add name="Database Trace Listener"/>
</listeners>
</add>
</categorySources>



Once new categorySources defined, we can use it in code where to write a log:

// indicate which category that this log belongs to
Logger.Write("This is my test", "MyCategory2");

the EntLib code will create database record for the categories and the mapping records between logs and categories.

2. define custom fields
if we are not only logging a message, we'd like to log information composed by a number of fields, we can use ExtendedProperties.

LogEntry ent = new LogEntry();
ent.ExtendedProperties.Add("key1", "value1");
ent.ExtendedProperties.Add("key2", "value2");
ent.Categories.Add("MyCategory2");
Logger.Write(ent);


these collection will be serialized to a string and stored to FormattedMessage column of Log table.
the format of the string is defined by a text formatter in configure file:

<formatters>
<add template="Timestamp: {timestamp}&#xD;&#xA;
Message:{message}&#xD;&#xA;
Category: {category}&#xD;&#xA;
Priority: {priority}&#xD;&#xA;
EventId: {eventid}&#xD;&#xA;
Severity: {severity}&#xD;&#xA;
Title:{title}&#xD;&#xA;
Machine: {machine}&#xD;&#xA;
Application Domain: {appDomain}&#xD;&#xA;
Process Id: {processId}&#xD;&#xA;
Process Name: {processName}&#xD;&#xA;
Win32 Thread Id: {win32ThreadId}&#xD;&#xA;
Thread Name: {threadName}&#xD;&#xA;
Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"

type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null"
name="Text Formatter" />

Monday, January 14, 2008

Notes on Class Diagram

Called Class diagram, it is really modeling types and their relationships in a system, not just classes[1]. These types, specifically named as classifier, includes

- classes
- interfaces
- data types (structs, enums, etc.)
- components

Class diagram manifests the static aspect of a system, or a domain conceptually.

Notation of an element

A Class is represented by:
- name
- attributes (optional)
- operations (optional)

the format of defining an attribute is:
visibility attributeName:type=defaultValue{isNullable}

the format of defining an operation is:
visibility operationName(parameterList):returnType

Each parameter is defined as:
direction parameterType
where direction = {in|out}

visibility = {+|-|#|~}
respectively indicates public, private, protected, package.

static attributes and operations are indicated with an underline.

An abstract class is indicated by italicizedclass name

An interface is indicated with <> text above the name of the interface.

The Relationship
The relationhsip demonstrated in a class diagram aims to discover and express the structural aspect of collabrations, as opposed to behaviourial aspect.

some relationships are stated differently in different books. generally the relationships can be categorized into three kinds:

- Generalization
- Association
- Others

Generalization includes extention and implementation(some books called realization). The former refers to that a class extends from another class (including abstract class), the latter refers to a class implements an interface.

figure 2: implementation and extention

Association Relationship
Association relationship represents that two or more elements conceptually associate with each other. for example, a person owns a car, a car has an engine, a student registers in courses and so forth. [3] discriminates association relationships into five types:

- uni-directional
- bi-directional
- reflexive
- aggregation
- composition

In a class diagram, uni-directional association is represented by a solid line with an arrow head indicating the direction, bi-directional association uses a solid line. based on [3], reflexive association uses a solid line. I would like add anarrow head so that it is easier to read the association with role information.

aggregation uses a solid line with an unfilled diamond, while composition uses a solid line with filled diamond.

figure x shows the notations of above five associations

Obviously, multiplicity gives the possible number of instances that could be associated, while roles clarifies the association in terms of real world.

Worth to notice, to determine which type of association to use is totally based on conceptual context of the domain, not relies on code implementation. For example, both aggregation and composition can be implemented with an collection attribute in the whole class, the only difference is that the elements in the collection of a composition whole has no other classes reference to them, while for aggregation, it is not guaranteed.

Others category includes dependency. If a class uses another class in its implementation or as a parameter, this sort of relationship neither belongs to generalization nor belongs to association, it is called dependency relationship. The notation for it is a dash-line and an arrow head indicating the direction.

figure 3:

References:
[1] Information System Analysis and Design, University of Toronto, lecture of CSC340
[2] UML basics: The class diagram, IBM website.

Monday, December 31, 2007

ASP.Net Page Designing Strategy

ASP.Net 2.0 brought in an important concept about building a web page, the master page. In fact, master page is an overall concept, it includes master page and nested master page(s) ( can be multi-layer). In this artical, I will examine the elements that build up a multi-layer page structure and the inter-accessability among them. A multi-layer page structure is broadly used in creating a consistent web site.

[1] Define a master page

To define a master page, first we need to add a Master directive to a .master file at it's first line. .Net recognizes a master page by the file name extention and the directive declaration so as to find the bebind code of the MasterPage class. See the code snippet bellow.

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="RootMaster.master.cs" Inherits="RootMaster" %>

Next, we create the behind code for the master page. It is nothing but a class derived from System.Web.UI.MasterPage.

// the RootMaster.master.cs
public partial class RootMaster : System.Web.UI.MasterPage
{
}


Once these are done, we start to design the master page layout and define placeholder(s). All design elements outside the placeholder(s) are shared among pages that derives from this master page.

<!--
master page defines content placeholder(s) which are going to be filled in nested master pages or pages.
-->
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
<asp:contentplaceholder id="ContentPlaceHolder2" runat="server">
</asp:contentplaceholder>

Note, the HTML page specific elemtents such as <head>, <title>, <body>, <form> and so forth are only showing in master page. Nested master pages and pages are just defining content for filling the placeHolders. From this sense, only master page is a page, while nested master page and page are just page assemblies.


[2] Nested master page
The great thing of nested master page is that it bring the flexibility to create multi-level of sharing page element. Concretely, it define page contents filling the place holders in master page, at the mean time, it defines new place holder in a new level of specifics.

Like defining master page, nested master page has .master file name extention. In this file, we need to set it's master page attributes by writing Master dirctive at the first top line. see bellow.

<%@ Master ClassName="NestedMaster" Language="C#" MasterPageFile="~/RootMaster.master" AutoEventWireup="false" CodeFile="NestedMaster.master.cs" Inherits="NestedMaster" %>

Compareing with that in the master page, We noticed that this declaration has a new attribute of MasterPageFile which has the value refering to the parent master page.

At this point, we may wonder how the code behind defines the NestedMaster class. the following code snippets shows just that.

public partial class NestedMaster : RootMaster
{
}

Here we noticed that nested master page class inherits the parent master page class rather than System.Web.UI.MasterPage.


Next, let's look at how nested master page fill place holders defined in parent master page and define new place holder(s)

<asp:content ContentPlaceholderID="plcHolderMain" id="MainContent" runat="server">
<DIV class="clsSectionHeader"></DIV>
<asp:contentplaceholder id="plcHolderSearch" runat="server">
</asp:contentplaceholder>

<DIV class="clsSubSectionHeader">SEARCH RESULTS <asp:Label Runat="server" ID="lblSrchFilter"></asp:Label>
</DIV>

<asp:contentplaceholder id="plcHolderResults" runat="server">
</asp:contentplaceholder>
</asp:content>

The code snippet above defines content filling the place holder of "plcholderMain" and defines two new smaller place holders "plcholderSearch" and "plcHolderResult".

[3] Multi-layer nested master page
Theoratically, nested master page has unlimited levels. It gives fine grain control when developing complex-layout web page.

Defining a lower level of nested master page is no different as defining a first level nested master page aforementioned except that the declarive in .master file has MasterPageFile set to the parent nested master page instead of the root master page; the bebind code class inherits parent master class rather rather than the RootMaster class.

<%@ Master ClassName="SubNestedMaster" Language="C#" MasterPageFile="~/NestedMaster.master" AutoEventWireup="false" CodeFile="SubNestedMaster.master.cs" Inherits="SubNestedMaster" %>

public partial class SubNestedMaster : NestedMaster
{
}


[4] Define pages inherited from master/nested master page
There are no difference between defining a page with master page of master and a page with master page nested master. what we need to do is set the MasterPagerFile property of Page directive to right .master file. In the following directive, the page set it's master to RootMaster.master which is a master page

<%@ Page Language="C#" MasterPageFile="~/RootMaster.master" AutoEventWireup="true" CodeFile="ModelPage.aspx.cs" Inherits="ModelPage" Title="Untitled Page" %>

In code behind file, we only need define our page class that inherited from System.Web.UI.Page.

public partial class ModelPage : System.Web.UI.Page
{
}

[5] The interaccessability
Because master page, nested master page and page end up rendering one physical page, it is essential to ensure that controls, which may distributed in different type of "pages", can communicate with each other.

However, It makes sense that we only examine elements in lower level "page" accessing elements in higher level "page". Not the reverse.

[5.1] Access master page and nested master page from a page
As shown in the following code adopted from ModelPage's code behind, we casts the page's Master object to RootMaster
type and then access a user custom control defined in that master page.

((UserControls_ModelUserControl1)((RootMaster)Master).UC1).CustomName = "Click Me";


The Master property of a page refers to the MasterPage object the page declared. Even this.Master represent an object of System.Web.UI.MasterPage, it actually is our extended and customized MasterPage object.


But, by default a control in a master page or nested master page is "protected", how come we can access it in a page? In fact we exposed the controls that supposed to be accessed from outside of the page. As shows in the following code.


public UserControls_ModelUserControl1 UC1
{
get { return this.ModelUserControl1_1; }
}

Another way to access a control is using FindControl method of the MasterPage class. .Net's Control class has the method. See the following code.

((UserControls_ModelUserControl1)(Master).FindControl("ModelUserControl1_1")).CustomName = "found Click me";

If we don't want to cast the default MasterPage object to our custom master page, like ((RootMaster)Master) mentioned before, we can use MasterType page directive indicating the compiler the specific master page so that not use the default master page type.


<%@ MasterType TypeName ="RootMaster" %>

then the accessing code will be

((UserControls_ModelUserControl1)(Master).UC1).CustomName = "Click Me";



[5.2] Access master page and nested master page from a nested master page

Due to a nested master page extends a master page or a parent nested master page, so the access should be straight forward through "this".

Regarding page accessability, what we examined above is actually a static model. A question left in my mind is that what about dynamically loaded controls in master page or nested master page? I will look at it in detail in another artical.


In this artical, I discussed one essential aspect of ASP.Net's web page designing model, the master page strategy. As we can see, multi-layer nested master page implements the real nature of element sharing in a web application and brings power to building consistent web site.

WPF Fundamentals

1. Introduction
Window Presentation Foundation, also named Avalon, is Microsoft's flagship for next generation application UX(user experience) development. It's UI model eliminates the difference of UI elements used in Web page rendering, Windows applications and smart devices. In addition, 3D graphics and animation features are incorporated in this framework so as to create rich user experience for Windows Vista. Also, vector graphics rendering ensures quality for different image size and resolution equipments.


2. XAML
Up front of WPF is XAML - Extensible Application Markup Language, a new markup language standard brought in along with WFP by Microsoft used to describe and define UIs.

Like Asp.net web page, XAML not only has the power for designing layout, it also supports themes and skins to build application-wide consistent pages. Themes and skins are defined as styles.

A XAML document usually refers to two namespaces (see the following code snippet), where XAML schemas are defined. The XAML compiler uses this schema to validate and parse XAML documents.

<Page x:Class="WPFProject.Page1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
...
</Page>


3. The WPF Stack
Like most other frameworks, WFP runs on a layered manner. The topmost layer, called Presentation Framework layer, runs on top of Presentation Core layer. These two layers have all the classes of managed code that are controlled by the next layer, the CLR. Under CLR are milcore, User32, and DirectX. They call OS kernel and provide the system support for the top levels

4. WPF Application
The System.Windows.Application class is a framework for defining a WPF application. It exposed programming handlers to customize all aspects accross your application's lifecycle.

... the handlers

System.Windows.Application's StartupUri property is where we can specify the start UI page to run. The following snippet specifies the starting page in XAML tag and with code.

<Application x:Class="WPFProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="whatever.xaml"
>
</Application>

or in behind code:

this.StartupUri = "whatever.xmal";


A WPF application instance can he hosted in a standalone commandline application or in XBAP(XAML Browser Application), a IE embeded application

Visual Studio 2005 provides a choice for a WPF project to be compiled to a console application, Windows applicaiton or a class library.


5. New Programming Features
5.1 Dependency Property
5.2 Attached Property
5.3 Routed Events
5.4 Animation coding

The details of these topics are exmined in another artical.

6. Questions
What is Site of Origin?
How to define and use Resources
A WPF application can be compiled into a class library, in which circumstance and how to access and incorporate the XAML pages?
What is provided by milcore(see 3: The WPF stack)?
How to use databinding in XAML?