Wednesday, November 11, 2009

Silverlight Organization Chart - Part 3 - The Node

Now after we talked about retrieving the data from the XML file, and calculating the nodes positions, we need to talk about drawing and the first thing that we need to draw is the node itself.

In this post, please note that I’m using the “Silverlight Hebrew & Arabic Language Support” library.

My XAML file will look like that:

<UserControl xmlns:my="clr-namespace:System.Windows.BidiControls;assembly=BidiControls" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" x:Class="OrgChart.NodeBox"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Width="140" Height="80">

<Canvas x:Name="canvMain" MouseEnter="canvMain_MouseEnter" MouseLeave="canvMain_MouseLeave">

<Rectangle x:Name="recBorder" RadiusX="5" RadiusY="5" Stroke="CornflowerBlue" StrokeThickness="2">

<Rectangle.Fill>

<SolidColorBrush Color='#f2f3fd' />

</Rectangle.Fill>

</Rectangle>

<my:TextBlock TextAlignment="left" x:Name="tbEmployeeName" Width="130" Height="20" Foreground="Black" Canvas.Left="5" FontWeight="Bold"></my:TextBlock>

<my:TextBlock TextAlignment="left" x:Name="tbTitle" Width="130" Height="20" Foreground="Black" Canvas.Left="5"></my:TextBlock>

<my:TextBlock TextAlignment="left" x:Name="tbDepartment" Width="130" Height="20" Foreground="Black" Canvas.Left="5"></my:TextBlock>

<my:TextBlock TextAlignment="left" x:Name="tbExtension" Width="130" Height="20" Foreground="Black" Canvas.Left="5"></my:TextBlock>

<Canvas.Resources>

<Storyboard x:Name="mouseEnter">

<ColorAnimation

Duration='00:00:01'

To='#ffffcc'

Storyboard.TargetName='recBorder'

Storyboard.TargetProperty='(Shape.Fill).(SolidColorBrush.Color)' />

</Storyboard>

<Storyboard x:Name='mouseLeave'>

<ColorAnimation

Duration='00:00:00'

To='#f2f3fd'

Storyboard.TargetName='recBorder'

Storyboard.TargetProperty='(Shape.Fill).(SolidColorBrush.Color)' />

</Storyboard>

</Canvas.Resources>

</Canvas>



Where you will find a reference to the BidiControls for the Arabic support, a canvas with a border and four TextBlock to display the Name, Title, Department and the Extension and the values are assigned from the properties in the code behind.
Also there are two storyboards to change the background color on mouse hover.

The code behind will look like that:

namespace OrgChart

{

public partial class NodeBox : UserControl

{

private double _fontSize = 10;

public NodeBox(double scale)

{

_Scale = scale;

InitializeComponent();

tbEmployeeName.FontSize = _fontSize * Scale;

tbEmployeeName.SetValue(Canvas.TopProperty, 5 * scale);

tbEmployeeName.SetValue(Canvas.LeftProperty, 5 * scale);

tbEmployeeName.Height = 20 * scale;

tbEmployeeName.Width = 130 * scale;

tbEmployeeName.TextWrapping = TextWrapping.NoWrap;

tbEmployeeName.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 130 * scale, 20 * scale) };

// the same for all the controls on the canvas

}

// Control Properties to set the TextBlock Values

}

}



Where font size, width, height, the location and the clip area of each TextBlock must be adjusted based on the scale. Also the node border must be adjusted, the rounded corner radius and the thikness and the dimentions:

recBorder.StrokeThickness = 2 * scale;

recBorder.RadiusX = 5 * scale;

recBorder.RadiusY = 5 * scale;

recBorder.Width = this.Width * scale;

recBorder.Height = this.Height * scale;



Our next step will talk about drawing the nodes and the lines on the main control.

Sunday, November 01, 2009

Backup with DateTime

Want to make a batch file that is making backup to your SharePoint site and add to the file name a date? or add also the time?

Use this command in your batch file:

stsadm -o backup -http://siteurl -filename sitename%date:~-4,4%%date:~-10,2%%date:~-7,2%-%time:~0,2%%time:~3,2%.dat

This will make the command as:
stsadm -o backup -http://siteurl -filename sitename20091101-1159.dat

Where: 20091101 is the date yyyymmdd, and 1159 is HHMM

Silverlight Organization Chart – Part 2 – Calculations

Now we have the nodes list ready from the previous post, the second step is to start calculating where each node will be displayed. The below points will be called while loading the first time and then when the user resize the chart or open and close any node. For sure it will be better to just draw the chart with the new scale on resizing. And I’ll work on it to enhance its performance isA.


Point 1: Prepare the data


In this point we will start with the root node, and go to the child nodes then the sub child and so on. We need to set the level for each node, and the number of opened and closed sub nodes, also we will set the sub nodes order and the default allowed width for the second level. Also the total height will be calculated.

private void SetLevel(Person parent, int level)

        {

            // Set the node level

            parent.Level = level;

 

            // Calculate the total height based on the number of levels

            if (totalHight < levelHight * (level + 2))

            {

                totalHight = levelHight * (level + 2) ;

                MyCanvas.Height = totalHight;

            }

 

            // Select the closed items under this parent

            var resultN = from n in persons

                          where n.ManagerID == parent.ID && n.Opened == false

                         select n;

 

            Person[] nodesN = resultN.ToArray();

 

            // Get the closed nodes number

            parent.HiddenSubNodes = nodesN.Length;

 

            // Select the opend nodes under this parent

            var result = from n in persons

                         where n.ManagerID == parent.ID && n.Opened == true

                         select n;

 

            Person[] nodes = result.ToArray();

 

            // Get the Opend nodes number

            parent.SubNodes = nodes.Length;

 

            // Call the child nodes

            for (int i = 0; i < nodes.Length; i++)

            {

                nodes[i].NodeOrder = i + 1;

                nodes[i].MinChildWidth = buttonWidth + minHorizontalSpace;

                SetLevel(nodes[i], parent.Level + 1);

            }           

        }



Point 2: Calculations


In this point we will need to:
1. Calculate the width for each node based on the opened sub nodes. As you can see in the image, the minChildWidth for the blue node is not the same as the default.
2. Calculate the StartX for each parent node.
3. Calculate the X coordinate for each node based on the StartX of the parent and the node order.
4. Realign the parent node to be centered in the space allowed for its sub nodes.

private void CalculateWidth(Person parent)

        {

            if (parent.SubNodes > 0)

            {

                var result = from n in persons

                             where n.ManagerID == parent.ID && n.Opened == true

                             orderby n.NodeOrder

                             select n;

 

                Person[] nodes = result.ToArray();

                double minWidth = 0;

                for (int i = 0; i < nodes.Length; i++)

                {

                    CalculateWidth(nodes[i]);

                    minWidth = minWidth + nodes[i].MinChildWidth;

                }

 

                if (minWidth > parent.MinChildWidth)

                {

                    parent.MinChildWidth = minWidth;

                    if (MyCanvas.Width < minWidth)

                    {

                        MyCanvas.Width = minWidth;

                        totalWidth = minWidth;

                    }

                }

 

                // Calculate the startX for each node

                double start = parent.StartX;

                for (int i = 0; i < nodes.Length; i++)

                {

                    nodes[i].StartX = start;

                    nodes[i].X = nodes[i].StartX + nodes[i].MinChildWidth / 2;

                    CalculateWidth(nodes[i]);

                    start = start + nodes[i].MinChildWidth;

                }

 

                // realign the parent node to the middle of the child nodes

                if (nodes.Length > 1)

                {

                    parent.X = (nodes[0].X + nodes[nodes.Length - 1].X) / 2;

                }

                else // root element

                {

                    parent.X = nodes[0].X;

                }

            }

        }



After that we will just need to draw the nodes, we have the X coordinate and we have the Y Coordinate with can be calculated from the level multiplied by the level hight.

Wednesday, October 28, 2009

IE8 Cool ... حركات IE8

In the latest Riyadh community summit last week, Microsoft KSA has announced for a competition for IE8 plug-ins “IE8 Cool ... حركات IE8”

And the prizes for winners in the competition are:
1st Winner: Tech-Ed Middle East March 1 – 3 Dubai
2nd Winner: HTC HD2
3rd Winner: Xbox 360 Elite System

I have already some ideas, but if anyone can help me to go to Tech-Ed ME? :)

For more info about the competition visit the Facebook group

Monday, October 26, 2009

Silverlight Organization Chart – Part 1 – Read XML file

I’m sorry I did not post the details of how to do the Silverlight organization chart as was expected.

I’ll not go in details of how to create a Silverlight application; you can see these details here.

In my organization chart I make option either to read the nodes from XML file for read them from a web service (reading the data from Active Directory), I’m here will just talk about the XML file.

Point 1: the XML file

My XML file looks like this:

<?xml version="1.0" encoding="utf-8" ?>

<Persons>

  <Person>

    <ID>1</ID>

    <Name>Mostafa El Mashad </Name>

    <Title>CEO</Title>

    <Department> </Department>

    <Extension>1111</Extension>

    <Email>mostafa.elmashad@domain.com</Email>

    <ManagerID></ManagerID>

  </Person>

  <Person>

    <ID>2</ID>

    <Name>Ahmed Sadek</Name>

    <Title>HR Manager</Title>

    <Department>HR</Department>

    <Extension>1200</Extension>

    <Email>Ahmed.sadek@mydomain.com</Email>

    <ManagerID>1</ManagerID>

  </Person>

  <Person>

    <ID>3</ID>

    <Name>Hanan Youssef</Name>

    <Title>Sales Manager</Title>

    <Department>Sales</Department>

    <Extension>1300</Extension>

    <Email>hanan.youssef@mydomain.com</Email>

    <ManagerID>1</ManagerID>

  </Person>

</Persons>



and you can add as much as person nodes as you want.

Where:
ID: Is the identity of this person
Name: The person name
Title: His job title
Department: The department he is working in
Extension: Phone extension
Email: his email address
ManagerID: The identity value used in his manager data

In our example:
Mostafa – the CEO – he has no manager, so the ManagerID is blank
Hanan and Ahmed are reporting to Mostafa, so the ManagerID equal 1, which is Mostafa’s ID

Note: this XML file will be deployed with the XAP file at the end.


Point 2: The Person class

I’ll need to make a class to represent the Person object, and while reading the data from the XML file I’ll put it in an list of Persons.

public List<Person> persons = new List<Person>();

Also I’ll need some extra data to be stored with each person, like:
Level : The person level, in our example, Mostafa #1, Ahmed and Hanan #2
SubNodes: How many person are reporting to the current, 2 are reporting to Mostafa
HiddenSubNodes: The same as the SubNodes in case the node is not collapsed.
NodeOrder: The order of this node between the same level under the same parent
MinChildWidth: The display minimum width allowed for the child nodes
X: The X coordinate of the node on the screen, the Y position is calculated from the node level
StartX: The parent X
Opened : is this node displayed or not
Collapsed: Is this node’s child are displayed or not


Point 3: Reading the XML file

In the page load of my Silverlight control, I’ll call the method that will read the XML file:

private void LoadXMLFile()

        {

            WebClient xmlClient = new WebClient();

            xmlClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(XMLFileLoaded);

            xmlClient.DownloadStringAsync(new Uri("OrgChart_Data.xml", UriKind.RelativeOrAbsolute));

        }



void XMLFileLoaded(object sender, DownloadStringCompletedEventArgs e)

        {

            if (e.Error == null)

            {

                Person firstNode = Person.GetPerson("OrgChartRootNode", "LINK Development", "", "", "", "", "");

                firstNode.MinChildWidth = totalWidth;

                persons.Add(firstNode);

 

                XElement lobjDocument = XElement.Parse(e.Result.ToString());

 

                var Result = from view1 in lobjDocument.Descendants("Person")

                             select new Person

                             {

                                 Name = (string)view1.Element("Name"),

                                 ID = (string)view1.Element("ID"),

                                 ManagerID = (string)view1.Element("ManagerID"),

                                 Title = (string)view1.Element("Title"),

                                 Department = (string)view1.Element("Department"),

                                 Extension = (string)view1.Element("Extension"),

                                 Email = (string)view1.Element("Email")

                             };

 

                Person[] nodes = Result.ToArray();

 

                for (int i = 0; i < nodes.Length; i++)

                {

                    if (string.IsNullOrEmpty(nodes[i].ManagerID))

                    {

                        nodes[i].ManagerID = "OrgChartRootNode";

                    }

                }

                persons.AddRange(nodes);

                Start();

            }

        }






Here in my control, if any node did not has a ManagerID value, I’ll consider it as a parent node just under the organization root element.

In the last line of code, you will see a call to a Start method, which will start calculating and building the organization chart nodes. And we will talk about the calculations in a separate post soon isA.

Saturday, October 24, 2009

Otlob.com on mobile

I have an account on Otlob since 2001 and make all my orders through it in Egypt. But using Otlob in KSA is a problem, all the restaurants are closing between 30 to 60 minutes for praying four times a day and you cannot place an order and you have to wait all this time - And you will not see a message when actually your order will be delivered - currently it is 40 minutes fixed- which is the same if you are going to make your order and eat in the restaurant.

Another problems that is facing me while using Otlob web site in KSA is the address, as still in KSA there is no accurate addresses in many places, and for each address I want the food to be delivered to I have to make a profile, while in some places I don’t know what is the address but I can just describe it.

A lot of people come to KSA to do some tasks and then return back to their countries, and those are the most people whose needs to order fast foods, they did not have time, and they may not have any internet access to browse the Otlob website.

A mobile application (not a mobile website) is a good idea for this scenario, the user will download the application from the net, and he can select which restaurants he wants to download its menus. He can check this menu while he is in the taxi and offline for example.

He can also just check for the menu and go directly to the restaurant, but he knows already what the menu is and what are the prices, he may select to “prepare the order for me” service, to be able to go and eat it before the prayer time. He can also pass through and take it home.

For the addresses, GPS became available in every mobile, so the user can set an order and select to receive it in the location where he is now. He doesn’t need to make a new profile for these addressees, as he may be today in Riyadh and tomorrow in Jeddah and so on.

Preferred orders, will be much easier, as the mobile will display a reminder “Do you want to make the order now? It will be delivered after one hour”, he can select “Just prepare it for me, I’ll be there before the prayer time to take it home.”

Just ideas. And that is what I want from a mobile application.

What do you think? any ideas?

Friday, October 23, 2009

SharePoint4Arabs

A year ago, I met with Ayman El Hatab http://www.aymanelhattab.com/ before he joined ITWorx, then two weeks ago I found him on Twitter. He sent to me an email introducing http://www.sharepoint4arabs.com/ website, and I found it really interesting to make Arabic trainings, articles and video tutorials.

Till now, they are focusing on the end user; for example: What is SharePoint, how to make a site columns, content types, and managing site security.

I started with them by recording my first video “SharePoint Pages” talking about the Basic and the Web Part Pages, the related content types and its page layouts. And there will be soon another video that is talking about the “Publishing Pages” then “SharePoint MasterPages” and “Page Layouts” that will be in Arabic as well isA.

Hopefully this series help in introducing SharePoint to Arabic audience and give them their first step on using, customizing, managing SharePoint sites.

Waiting for SharePoint 2010

No date for releasing the software and no actual date as well for the beta version (possibly mid of November), but everyone is waiting.

But the good thing is that there is Development Hands-on Labs since the second day in the conference http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=c010fc68-b47f-4db6-b8a8-ad4ba33a35c5

Besides, there are ten modules to start developing on SharePoint 2010 http://msdn.microsoft.com/en-us/sharepoint/ee513147.aspx

As well, there will be a group of SharePoint 2010 courses (webcasts/offline) in December by a group of SharePoint MVPs (Andrew Connell is one of the instructors) http://www.andrewconnell.com/blog/

And today I have attended the Riyadh Community Summit, an event sponsored by Microsoft KSA and organized by three user groups in Riyadh:
1. Riyadh SharePoint User Group – http://www.rsug.net/
2. DevLifeStyle - http://www.devlifestyle.net/
3. CΏdeβettěЯ - http://www.codebetter.net/

The event was at Al Yamamah University where all the software events are currently happened there.

And it was really good to listen to someone talking about SharePoint 2010 at the same time as in #SPC09 (GDC09 will be in Riyadh isA 13-15 December)

BTW, at the end of today’s sessions, the two persons that were sitting beside me on both sides have won a 1 year access to http://www.microsoftelearning.com/ and for me I have received a book “Object Thinking” http://www.amazon.com/Object-Thinking-DV-Microsoft-Professional-David/dp/0735619654

Wednesday, October 21, 2009

Nice !!!

Nice #1:

This is the word that my son – 2 years - learned to say while patting on the cat; his mom told him to be nice with the cat and showed him how to pat smoothly, but he understand it as “pat a cat” = “Nice”.
http://www.facebook.com/photo.php?pid=8907036&id=610370569


Nice #2:

But I saw the word “Nice” in a blog, it was in the comments, and it was repeated many times plus some other words like “Extremely Interesting” and “Just Great”. I was happy to see these comments as the blog is related to a friend and a colleague and it was just his second post, but one comment stopped me, which is “You made some good points there” while the post was just a link to another website with two lines describing this link!

I started to check, who add this comment and I found that his name is redirecting to a loans website, and the surprise was that some other comments are added by the same user (same site URL) and most of the comments are added by someone just want to increase the number of the sites that referring to his site!


Nice #3:

I have received a link to http://www.personalizemedia.com/ in this page you will find a flash object with numbers that are changed so fast. It is the social media counter, it shows you how many new Twitter user, or how many video are watched now on YouTube, or how much Facebook collected from the Gifts. The user who post the article said that you can embed this counter in your site like this:



Very Nice!!!

But the first thing that I thought about is the number of hits to all this information sources; take into consideration that ANYONE can embed it anywhere, which means that extra number of hits; also it was very strange that this person know how to read all these updated information and with this high frequency, instantly I switched off my wireless connection, but the numbers still increasing!

Then I returned back to read and I found a link to the details page http://www.personalizemedia.com/garys-social-media-count/#more-1734 that his numbers are calculated based on facts, and not a real numbers.