Deepak's Blog

Exam 70-532: Developing Microsoft Azure Solutions Preparation & Flash cards

Recently I passed the 70-532 Developing Microsoft Azure Solutions certification from Microsoft, it was great to learn and earn certification in technology that is revolutionising the way IT works. I found it took more effort to source material to prepare, to help others I’ve listed articles, books and videos I referred during my preparation. Microsoft Virtual Academy I would recommend MVA to everybody, it has loads of courses on Azure which are updated regularly.

Courses which I couldn’t complete but I feel should help:

Ebooks Exam reference book from Microsoft Press: 70-532 Microsoft has provided lot of free ebooks on Azure which are available here Microsoft Ebooks Guidance checklists Good checklists which provide insight on getting most out of Azure.

Azure Documentation In addition to above references it is very helpful to go through the Documentation at Azure website, I found the documentation on MSDN to be more detailed. Flash cards Spending some time refreshing on previously studied material every day is suggested so you do not overwhelm yourself at the end trying to refresh your memory. I used Anki flash cards application which is intelligent,based on some algorithm which predicts when you will forget content in that card, enough to remind you to read. During my preparation I worked to prepare my flash card deck, If you would like to use it you can download from link below. Please note this deck is not complete nor sufficient to pass the exam. Azure.apkg Note: Remove .doc at end of file name and import into Anki application. You have to practice a lot to get comfortable designing and developing applications on Azure platform. I will keep updating this list as and when I find material. Hope this list helps you. Good luck with the test!

Advertisements

DataGridView – Stacked Header – Export to HTML/Excel

Done with implementing the stacked headers for DataGridView I was next asked to provide option to export data to Excel with same formatted headers.

I had to choose between .NET Office library or simple HTML table based approach to represent data.  I chose the later because Excel reads the HTML table well and I did not want to use heavy Office libraries.

HTML Table is a flat structure which uses rowspan and colspan to achieve the grouping. Visualizing grouping for large number of columns and varied levels of grouping becomes difficult.

Let us look at a sample to understand what has to be done to render the headers in the same grouped format. Consider the sample below:

<table border="1">
    <tr>
        <td colspan="3">Parent</td>
    </tr>    
    <tr>
        <td rowspan="2" >Child1</td>        
        <td colspan="2">Child Parent</td>
    </tr>
    <tr>
        <td >Child3</td>
        <td >Child4</td>
    </tr>
</table>

It renders as the table shown below:

From the example, we can see:

1. We need to have one row for each level of header.

2. Use colspan to span parent headers over its children.

3. For varied nesting, ex. first column has one level while second column has two levels. In First column use rowspan equal to the levels in the second column.

With the gained understanding I decided to use the same recursive technique as in painting but with an additional Dictionary to hold the <tr> elements for each level of header. I had to use Dictionary because I could not close each row as I had to traverse the entire header tree to complete each row.

Source Code

I’ve explained the source code via comments.

 public static class DataGridExporter
    {
        //Extension method to export data grid content to table format
        public static void ExportToHtmlOrExcel(this DataGridView dataGridView,
            string filePath, Header header)
        {
            StringBuilder strTable = new StringBuilder();

            //Begin the table element
            strTable.Append("&lt;table border=\"1\"&gt;");

            //Get number of levels which are valid, basically ones excluding empty string.
            //Empty string was used as a hack to avoid grouping of distant headers with same name.
            int noOfLevels = StackedHeaderGenerator.Instance.NoOfValidLevels(header);
            int temp;

            dtHeaderRows.Clear();

            //Generate the &lt;td&gt; tags for the headers
            GenerateHeader(dataGridView, header, 0, noOfLevels, out temp);

            //Sort the keys in the header as key represents the level.
            List&lt;int&gt; keys = dtHeaderRows.Keys.ToList();
            keys.Sort();
            foreach (int level in keys)
            {
                //Create a row for each level
                strTable.AppendFormat("&lt;tr&gt;{0}&lt;/tr&gt;", dtHeaderRows[level]);
            }

            //Export the data
            foreach (DataGridViewRow objRow in dataGridView.Rows)
            {
                strTable.Append("&lt;tr&gt;");
                foreach (DataGridViewCell objColumn in objRow.Cells)
                {
                    if (objColumn.Visible)
                    {
                        strTable.Append(string.Format("&lt;td align=\"center\"&gt;{0}&lt;/td&gt;", objColumn.Value));
                    }
                }
                strTable.Append("&lt;/tr&gt;");
            }
            strTable.Append("&lt;/table&gt;");

            StreamWriter writer = new StreamWriter(filePath);
            writer.Write(strTable.ToString());
            writer.Close();
        }

        //Dictionary to hold headers for each level.
        private static Dictionary&lt;int, StringBuilder&gt; dtHeaderRows = new Dictionary&lt;int, StringBuilder&gt;();

        //Generate the header row,column structure
        private static void GenerateHeader(DataGridView dataGridView, Header header, int iLevel, int noOfLevels, out int childCount)
        {
            //If this header does not have a child, it is leaf node.
            if (0 == header.Children.Count)
            {
                //Width is zero if the header is not visible.
                if (header.Width == 0)
                {
                    childCount = 0;
                    return;
                }

                //Used in arriving at the column span of the parent.
                childCount = 1;
                //Check if this level has been added into the header, if exists append the &lt;td&gt; to the same element.
                StringBuilder temp = dtHeaderRows.ContainsKey(iLevel) ? dtHeaderRows[iLevel] : new StringBuilder();
                temp.AppendFormat("&lt;td rowspan=\"{0}\"  align=\"center\"&gt;{1}&lt;/td&gt;", noOfLevels - iLevel, header.Name);
                dtHeaderRows[iLevel] = temp;
            }
            else
            {
                                int tempColumns = 0, count = 0;
                                //Generate &lt;td&gt; for each child.
                foreach (Header child in header.Children)
                {
                    GenerateHeader(dataGridView, child, header.Name == "" ? iLevel : iLevel + 1, noOfLevels, out tempColumns);
                    count += tempColumns;
                }
                //Total number of columns in this header. Used in colspan.
                childCount = count;
                if (header.Width != 0 &amp;&amp; header.Name != "")
                {
                    StringBuilder temp = dtHeaderRows.ContainsKey(iLevel) ? dtHeaderRows[iLevel] : new StringBuilder();
                    temp.AppendFormat("&lt;td colspan=\"{0}\"  align=\"center\"&gt;{1}&lt;/td&gt;", childCount, header.Name);
                    dtHeaderRows[iLevel] = temp;
                }
            }
        }
    }

You can find the complete StackedHeader component at DataGridView-Stacked Header.

DataGridView – Stacked Header

DataGridView forms an integral part of any application and with specific needs of the applications, harnessing power of DataGridView is essential. I faced a similar scenario in a project where we had a DataGridView having more than hundred columns generated dynamically. The columns are generated based on the hierarchy of the inputs (more than twelve different cases each having its own input hierarchy) with the Columns header text depicting the hierarchy ex. Component End 1 Input1, Component End 1 Input 2, Component End 2 Input 1, Component End 2 Input 2.

Having redundant text in column header is not user friendly requiring the user to read entire text to know what the input is for. We decided to have stacked headers where we group the inputs based on the hierarchy.

As we know the default Winforms DataGridView does not support Stacked Headers and going for a 3rd party Grid just for the Stacked Header was not of much value so I had to do this on my own.

The solution is divided into four steps:

  1. Since I already had the column header text generated based on the hierarchy I decided to use header text for grouping. For this I changed the header text to use ‘.’ to define hierarchy. ex: Component.End 1.Input1, Component.End 1.Input 2, Component.End 2.Input 1, Component.End 2.Input 2
  2. Generate a simple tree representing hierarchy of the columns.
  3. Measure width required by each group (considering columns width, visibility).
  4. Render the headers.

As a result of this exercise, developer can quickly convert the column headers to stacked header by changing the header text and using this one line of code to draw stacked headers.

StackedHeaderDecorator objRenderer = new StackedHeaderDecorator(objDataGrid);

This one line takes care of step 2, 3 and 4 of the DataGridView while leaving Step 1 to the user of this solution.

Code

The component consists of three classes and an interface.

Header

Represents a header and its children. As a whole it forms the representation of the headers as a tree which is rendered by StackedHeaderDecorator.

Properties

  • Children: Holds the children rendered under this header
  • Name: Name of the header, used by the renderer as the header text to be drawn.
  • X and Y: Left, Top location of the start of the header.
  • Width and Height: Size of the region taken by this header. This is set dynamically when the measuring of the header is done.
  • ColumnId: If this is a lowest header it is the id of the column it represents else it is the id of the first visible column in the Header in Children property.

Methods

AcceptRenderer

Accepts the renderer which renders this header. It first paints the children then self.

        public void AcceptRenderer(StackedHeaderDecorator objRenderer)
{
foreach (Header objChild in Children)
{
objChild.AcceptRenderer(objRenderer);
}
if (-1 != ColumnId && !string.IsNullOrEmpty(Name.Trim()))
{
objRenderer.Render(this);
}
}
Measure

Calculates the region required by the Header including its Children.

public void Measure(DataGridView objGrid, int iY, int iHeight)
{
Width = 0;
if (Children.Count > 0)
{
int tempY = string.IsNullOrEmpty(Name.Trim()) ? iY : iY + iHeight;
bool columnWidthSet = false;
foreach (Header child in Children)
{
child.Measure(objGrid, tempY, iHeight);
Width += child.Width;
if (!columnWidthSet && Width > 0)
{
ColumnId = child.ColumnId;
columnWidthSet = true;
}
}
}
else if (-1 != ColumnId && objGrid.Columns[ColumnId].Visible)
{
Width = objGrid.Columns[ColumnId].Width;
}
Y = iY;
if (Children.Count == 0)
{
Height = objGrid.ColumnHeadersHeight - iY;
}
else
{
Height = iHeight;
}
}

StackedHeaderDecorator

Decorates the DataGridView hooking into it several events which paint/refresh the header of the DataGridView.  It also enables DoubleBuffering on the DataGrid.

It uses an instance of implementation of IStackedHeaderGenerator to generate the headers. By default it uses the StackedHeaderGenerator implementation of IStackedHeaderGenerator which uses the HeaderText to generate the Header tree. You can pass your implementation of the Generator via the overloaded constructor.

These are the events handlers hooked to the DataGridView

        objDataGrid.Scroll += objDataGrid_Scroll;
objDataGrid.Paint += objDataGrid_Paint;
objDataGrid.ColumnRemoved += objDataGrid_ColumnRemoved;
objDataGrid.ColumnAdded += objDataGrid_ColumnAdded;
objDataGrid.ColumnWidthChanged += objDataGrid_ColumnWidthChanged;

All events other than PaintEvent just invalidate the DataGridView regions, so we will look into the PaintEvent Handler, RenderColumnHeaders and Render which do the heavy lifting.

PaintEvent Handler

Calculates the number of levels of stacking, sets the height of the ColumnHeader and calls RenderColumnHeaders.

       void objDataGrid_Paint(object sender, PaintEventArgs e)
{
iNoOfLevels = NoOfLevels(objHeaderTree);
objGraphics = e.Graphics;
objDataGrid.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
objDataGrid.ColumnHeadersHeight = iNoOfLevels * 20;
if (null != objHeaderTree)
{
RenderColumnHeaders();
}
}
RenderColumnHeaders

Fills the background rectangle of the column header then loops through each child measuring and rendering.

        private void RenderColumnHeaders()
        {
            objGraphics.FillRectangle(new SolidBrush(objDataGrid.ColumnHeadersDefaultCellStyle.BackColor),
                                      new Rectangle(objDataGrid.DisplayRectangle.X, objDataGrid.DisplayRectangle.Y,
                                                    objDataGrid.DisplayRectangle.Width, objDataGrid.ColumnHeadersHeight));

            foreach (Header objChild in objHeaderTree.Children)
            {
                objChild.Measure(objDataGrid, 0, objDataGrid.ColumnHeadersHeight/iNoOfLevels);
                objChild.AcceptRenderer(this);
            }
        }
RenderColumnHeaders

Renders the header, it checks if it is a leaf header or parent header. It uses the Clip feature of GDI+ to correctly draw the clipped header when user scrolls the DataGridView.

  public void Render(Header objHeader)
{
if (objHeader.Children.Count == 0)
{
Rectangle r1 = objDataGrid.GetColumnDisplayRectangle(objHeader.ColumnId, true);
if (r1.Width == 0)
{
return;
}
r1.Y = objHeader.Y;
r1.Width += 1;
r1.X -= 1;
r1.Height = objHeader.Height;
objGraphics.SetClip(r1);

if (r1.X + objDataGrid.Columns[objHeader.ColumnId].Width < objDataGrid.DisplayRectangle.Width)
{
r1.X -= (objDataGrid.Columns[objHeader.ColumnId].Width - r1.Width);
}
r1.X -= 1;
r1.Width = objDataGrid.Columns[objHeader.ColumnId].Width;
objGraphics.DrawRectangle(Pens.Gray, r1);
objGraphics.DrawString(objHeader.Name,
objDataGrid.ColumnHeadersDefaultCellStyle.Font,
new SolidBrush(objDataGrid.ColumnHeadersDefaultCellStyle.ForeColor),
r1,
objFormat);
objGraphics.ResetClip();
}
else
{
int x = objDataGrid.RowHeadersWidth;
for (int i = 0; i < objHeader.Children[0].ColumnId; ++i)
{
if (objDataGrid.Columns[i].Visible)
{
x += objDataGrid.Columns[i].Width;
}
}
if (x > (objDataGrid.HorizontalScrollingOffset + objDataGrid.DisplayRectangle.Width - 5))
{
return;
}

Rectangle r1 = objDataGrid.GetCellDisplayRectangle(objHeader.ColumnId, -1, true);
r1.Y = objHeader.Y;
r1.Height = objHeader.Height;
r1.Width = objHeader.Width  + 1;
if (r1.X < objDataGrid.RowHeadersWidth)
{
r1.X = objDataGrid.RowHeadersWidth;
}
r1.X -= 1;
objGraphics.SetClip(r1);
r1.X = x - objDataGrid.HorizontalScrollingOffset;
r1.Width -= 1;
objGraphics.DrawRectangle(Pens.Gray, r1);
r1.X -= 1;
objGraphics.DrawString(objHeader.Name, objDataGrid.ColumnHeadersDefaultCellStyle.Font,
new SolidBrush(objDataGrid.ColumnHeadersDefaultCellStyle.ForeColor),
r1, objFormat);
objGraphics.ResetClip();
}
}

There is one bug and several improvements I see in this code and I will work on them and update the articles.

Export to HTML Table

I’ve written a simple class which exports the grid data along with the grouped headers to html table which you can save into an Excel file. You can find the details in this article.

Bug

If you plan to use the default StackedHeaderGenerator for header generation then you have to know there is a bug in there which crops up if you have two top level headers with same name but do not represent consecutive columns then the header generated is incorrect. Since it uses ‘.’ separated header text to generate headers, you can add additional ‘.’s to get the correct header tree.

Download SourceCode. Please change the extension from .doc to .zip as WordPress does not allow exe’s or dll’s in uploads.

Note: The source code posted is not completely tested and polished, please use it diligently.

Editable Text Block in WPF

Introduction

Many applications require functionality to be able to edit text blocks when double clicked. This functionality is seen mostly in tree nodes like in Windows Explorer Tree. So I decided to create a control which allows the user to edit text blocks when double clicked or by using Function key F2.

Background

This article uses Adorners to show the text box when in edit mode.

Using the code

The EditableTextBlock extends the TextBlock (System.Windows.Controls.TextBlock) to provide the edit functionality.
The class diagram is as shown below:
Editabletextblock_CD.GIF

EditableTextBlock: Is the control which can be used directly to create an editable text block. The control has the following dependency properties through which the edit feature can be used.

Properties

IsInEditMode Is a Boolean property which as its name says when set to true enables the edit mode and false exits the edit mode.

MaxLength Is an integer which sets the MaxLength of the textbox which is shown when the control is in edit mode.
The other class EditableTextBlockAdorner is an Adorner which contains the text box shown when the EditableTextBlock is in edit mode.

Adorner is an element which can be added to the Adorner Layer of another UIElement.
It also allows you to extend functionality of the control, which is leveraged by the EditableTextBlock to provide edit functionality.

For more details on Adorners – http://msdn.microsoft.com/en-us/library/ms743737.aspx

EditableTextBlock Code:

Callback method when the value of the dependency property IsInEditMode changes:

private static void IsInEditModeUpdate(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    EditableTextBlock textBlock = obj as EditableTextBlock;
    if (null != textBlock)
    {
        //Get the adorner layer of the uielement (here TextBlock)
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(textBlock);

        //If the IsInEditMode set to true means the user has enabled the edit mode then
        //add the adorner to the adorner layer of the TextBlock.
        if (textBlock.IsInEditMode)
        {
            if (null == textBlock._adorner)
            {
                textBlock._adorner = new EditableTextBlockAdorner(textBlock);
                //Events wired to exit edit mode when the user presses Enter key or leaves the control.
                textBlock._adorner.TextBoxKeyUp += textBlock.TextBoxKeyUp;
                textBlock._adorner.TextBoxLostFocus += textBlock.TextBoxLostFocus;
            }
            layer.Add(textBlock._adorner);
        }
        else
        {
            //Remove the adorner from the adorner layer.
            Adorner[] adorners = layer.GetAdorners(textBlock);
            if (adorners != null)
            {
                foreach (Adorner adorner in adorners)
                {
                    if (adorner is EditableTextBlockAdorner)
                    {
                        layer.Remove(adorner);
                    }
                }
            }
            //Update the textblock's text binding.
            BindingExpression expression = textBlock.GetBindingExpression(TextProperty);
            if (null != expression)
            {
                expression.UpdateTarget();
            }
        }
    }
}

Using the EditableTextBlock:

<TreeView x:Name="tree" .. ItemsSource="{Binding PersonCollection}">
    <TreeView.Resources>
        <HierarchicalDataTemplate ..>
            <local:EditableTextBlock Text="{Binding Name, Mode=TwoWay}"
                    IsInEditMode="{Binding Edit, Mode=TwoWay}"/>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

Note: The Mode of binding (if any) with Text has to be TwoWay so that control can update the binding source when the value is edited in the edit text box.

Source Code: EditBlockTest (As WordPress has restrictions on file types added – Please change the extension from .doc to .zip)

Trigger based Rules Engine

Business rules form an integral part of many applications. Rules are usually conditional and the evaluation of the rules is triggered by the user input.

This can be explained better with an example:
Consider a simple application which accepts details of a person and determines if the person depending on his age can go out alone:

  • Name
  • Age
  • CanGoOutAlone

Rule:

  • If the age of the person is less than 15 he cannot go out alone else he can, however person “BAKTHA” is an exception and can go out alone irrespective of how old he is.

Different approaches to implement triggers and the rule itself which can come to our mind are:

  1. Coding in the view model
  2. Event handling
  3. Work flow Rules Engine

Each has some drawbacks:

  • Coding in the view model:  Code written in the view model tends to clutter the code file.
  • Event handling: UI Code is the simplest way to implement this code but changing the code is difficult, also sometimes the necessary events are not available.
  • Workflow rules engine: Needs to be triggered explicitly.

Additionally, except for Workflow Rules Engine the rules have to be coded and are not externalized (in Workflow Rule Engine though they are externalized, they are not meant to be edited by a simple xml editor and are verbose enough to prevent you from doing so).
First let’s understand what we require for a simple rule engine:

  • If the rule is conditional, like the one mentioned in the example, then the condition has to be evaluated before the rule has to be applied. – Condition Part
  • When the variables used in the condition changes the condition has to be evaluated and the rule has to be applied if the condition is satisfied. – Trigger Part
  • Action to be performed when the condition is satisfied. – Actual rule to be applied

Another way triggers can be implemented is by using Data Binding Framework provided by WPF.
WPF provides a powerful feature, Data Binding which allows binding CLR objects to the UI controls. I would delve much into Data Binding this article assumes you have some knowledge about data binding and dependency properties.
Why do we need data binding for this?
Data binding will provide the trigger which triggers the evaluation of the condition or execution of the action if there’s no condition.

Design:

Rules Engine

Rules Engine

Code:

Simple Rule:

<RULES>
<TRIGGERS>
<TRIGGER TYPE=”SETTER” ELSE_ACTION=”SETTER” PARAMETER=”false” PROPERTY_NAME=”CanGoOutAlone” VALUE=”true” BINDPROPERTY_NAME=”” PROPERTY_GROUP=””>
<CONDITIONS>
<CONDITION TYPE=”OR”>
<CONDITION TYPE=”AND”>
<CONDITION PROPERTY_GROUP=”OBJECT” PARAMETER=”” PROPERTY_TYPE=”int” PROPERTY_NAME=”Age” VALUE=”15″ CONDITION_TYPE=”IsGreaterThanOrEqualTo”/>
<CONDITION PROPERTY_GROUP=”OBJECT” PARAMETER=””  PROPERTY_TYPE=”string” PROPERTY_NAME=”Name” VALUE=”XYZ” CONDITION_TYPE=”IsNotEqualTo”/>
</CONDITION>
<CONDITION PROPERTY_GROUP=”OBJECT” PARAMETER=”” PROPERTY_TYPE=”string” PROPERTY_NAME=”Name” VALUE=”XYZ” CONDITION_TYPE=”IsEqualTo”/>
</CONDITION>
</CONDITIONS>
</TRIGGER>
</TRIGGERS>
</RULES>
<RULES>
 <TRIGGERS>
  <TRIGGER TYPE="SETTER" ELSE_ACTION="SETTER" PARAMETER="false" PROPERTY_NAME="CanGoOutAlone" VALUE="true" BINDPROPERTY_NAME="" PROPERTY_GROUP="">
   <CONDITIONS>
    <CONDITION TYPE="OR">
     <CONDITION TYPE="AND">
      <CONDITION PROPERTY_GROUP="OBJECT" PARAMETER="" PROPERTY_TYPE="int" PROPERTY_NAME="Age" VALUE="15" CONDITION_TYPE="IsGreaterThanOrEqualTo"/>
      <CONDITION PROPERTY_GROUP="OBJECT" PARAMETER=""  PROPERTY_TYPE="string" PROPERTY_NAME="Name" VALUE="XYZ" CONDITION_TYPE="IsNotEqualTo"/>
     </CONDITION>
     <CONDITION PROPERTY_GROUP="OBJECT" PARAMETER="" PROPERTY_TYPE="string" PROPERTY_NAME="Name" VALUE="XYZ" CONDITION_TYPE="IsEqualTo"/>
    </CONDITION>
   </CONDITIONS>
  </TRIGGER>
 </TRIGGERS>
</RULES>

Code

Trigger class

Dependency Property which fires the trigger:

The FireTrigger property is bound to the variable if the triger is unconditional. When the variable changes the binding framework invokes the TriggerCallback() method which triggers the execution of the rule.


///
 /// Gets or sets the fire trigger.
 ///
 /// The fire trigger.
 public object FireTrigger {
 get { return GetValue(FireTriggerProperty); }
 set { SetValue(FireTriggerProperty, value); }
 }

public static readonly DependencyProperty FireTriggerProperty = DependencyProperty.Register("FireTrigger", typeof(object), typeof(Trigger), new UIPropertyMetadata(null, TriggerCallBack));

///
 /// Call back method when the trigger fires.
 /// private static void TriggerCallBack(DependencyObject obj, DependencyPropertyChangedEventArgs e) { ((Trigger) obj).Execute();

}

The Execute method evaluates the condition and if the condition is satisfied then executes the true action or if the else action is specified then it is executed.


///
 /// Execute the trigger code.
 ///
 private void Execute()
 {
 bool blnIsConditionSatisfied = true;
 if (null != triggerCondition) {
 blnIsConditionSatisfied = triggerCondition.IsConditionSatisfied();
 }
 if (blnIsConditionSatisfied) {
 triggerAction.Action();
 }
 else if (null != triggerElseAction) {
 triggerElseAction.Action();
 }
 }

Condition Class

The condition class evalutes the condition. Several conditions can be joined by using logical condition classes And and Or which perform the logical operations of And’ing and Or’ing the conditions. Again, Dependency property is used to trigger the evaluation of the condition. As conditions involve variables the condition has to be reevaluated when there is a change in the variable involved, the RequeryTriggerCondition does exactly that, it reevaluates the entire trigger condition.


///
 /// Gets or sets the fire trigger.
 /// /// The fire trigger.
 private object RequeryTriggerCondition {
 get { return GetValue(RequeryTriggerConditionProperty); }
 set { SetValue(RequeryTriggerConditionProperty, value); }
 }

private static readonly DependencyProperty RequeryTriggerConditionProperty = DependencyProperty.Register("RequeryTriggerCondition", typeof(object), typeof(Condition), new UIPropertyMetadata(null, ConditionRequeryCallBack));

/// Call back method when the trigger fires.
 private static void ConditionRequeryCallBack(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
 var objCondition = (obj as Condition);
 if (objCondition != null && null != objCondition.Trigger) {
 objCondition.Trigger.RequeryTriggerCondition();
 }
 }

Then the action part

TriggerAction class

 public abstract class TriggerAction {
 public abstract void Action();
 }

Trigger Action class is an abstract class and has to be inherited to specify custom rules. the trigger is run it calls the Action() method of the class. Conclusion It is easy to develop a simple rules engine using the powers of Binding Framework to provide the triggers . It reduces the coding effort and externalizes the rules and the triggers which can be maintained easily. Points of Interest History

Code:http://www.codeproject.com/KB/dotnet/Trigger_based_Rule_Engine.aspx