Working with Windows Phone Controls

Exclusive offer: get 50% off this eBook here
Windows Phone 7.5 Application Development with F#

Windows Phone 7.5 Application Development with F# — Save 50%

Develop amazing applications for Windows Phone using F# with this book and ebook

$14.99    $7.50
by Lohith G.N. | June 2013 | Enterprise Articles Microsoft

Silverlight runtime for Windows Phone provides a variety of controls as part of the framework itself. This article by Lohith G.N., author of Windows Phone 7.5 Application Development with F#, is all about getting to know the controls supported by the framework and understanding how to work with those controls. We will go through each control, understand its usage, and finally learn how to write code to work with those controls.

(For more resources related to this topic, see here.)

Supported controls in Windows Phone

The following list will illustrate the different controls supported in Windows Phone. These controls are included in the System.Windows.Controls namespace in the .NET Framework class library for Silverlight:

  • Button: As the name goes, this is a button wherein a user interacts by clicking on it. On clicking, it raises an event.

  • HyperlinkButton: This is a button control that displays a hyperlink. When clicked, it allows users to navigate to an external web page or content within the same application.

  • ProgressBar: This is a control that indicates the progress of an operation.

  • MessageBox: This is a control that is used to display a message to the user and optionally prompts for a response.

  • TextBox: This is a control that allows users to enter single or multiple lines of text.

  • Checkbox: This is a control that a user can select or clear, that is, the control can be checked or unchecked.

  • ListBox: This is a control that contains a list of selectable items.

  • PasswordBox: This is a control used for entering passwords.

  • RadioButton: This is a control that allows users to select one option from a group of options.

  • Slider: This is a control that allows users to select from a range of values by moving a thumb control along a track.

Hello world in F#

The previous section gave us an insight into different controls available for Windows Phone applications. Before understanding how to work with them, let's create a Windows Phone "Hello World" application using F#. The following steps will help us create the application:

  1. Create a new project of type F# and C# Windows Phone Application (Silverlight)A solution with App and AppHost projects will be created:

  2. In the App project, we will have the main visual for the application called MainPage.xaml. If you open MainPage.xaml, you will notice that MainPage is actually a PhoneApplicationPage type. This is evident from the following XAML declaration:

    <phone:PhoneApplicationPage
    x:Class="WindowsPhoneApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.
    Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.
    Shell;assembly=Microsoft.Phone"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    xmlns:swc="clr-namespace:System.Windows.Controls;assembly=System.
    Windows"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markupcompatibility/
    2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True" mc:Ignorable="d"
    d:DesignHeight="696" d:DesignWidth="480">

    Note the x:Class attribute; this denotes that the XAML contains a counterpart class called MainPage available in the WindowsPhoneApp namespace. The MainPage class can be found in the AppLogic.fs file in the App project.

  3. Let us take a closer look at the UI itself. The main contents of the application is contained in a grid. A grid is a layout control that is used to define a flexible area that consists of rows and columns. The body contains three TextBlock controls. A TextBlock control, as the name suggests, is used to display a small block of text. We have three TextBlock controls on the page, one for ApplicationTitle, another for PageTitle, and the last one for Results. There is also an empty grid named ContentGrid. So this is where we will be creating our "Hello World" experiment. The XAML for the content is shown as follows:

    <Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
    <TextBlock x:Name="ApplicationTitle" Text="AN F# APPLICATION"
    Style="{StaticResource PhoneTextNormalStyle}"/>
    <TextBlock x:Name="PageTitle" Text="main page" Margin="-3,-8,0,0"
    Style="{StaticResource PhoneTextTitle1Style}"/>
    <TextBlock x:Name="Results" Text="" Margin="-3,-8,0,0"
    Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentGrid" Grid.Row="1">
    </Grid>
    </Grid>

    As you can see from the code, ContentGrid is empty. So let's place a TextBlock control and a Button element inside ContentGrid. The idea is to generate the text "Hello World" when we click on the button.

  4. First, let's take a look at the XAML portion of the "Hello World" experiment in MainPage.xaml:

    <Grid x:Name="ContentGrid" Grid.Row="1">
    <Grid.RowDefinitions>
    <RowDefinition Height="*"/>
    <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0"
    Name="txtMessage"
    Text="Click the button"
    HorizontalAlignment="Center"
    VerticalAlignment="Center"
    Style="{StaticResource PhoneTextTitle2Style}"/>
    <Button Grid.Row="1" Grid.Column="0"
    Name="btnSayHelloButton"
    Height="100" Content="Click to say Hello !" />
    </Grid>

    Pay attention to the TextBlock element and the Button names. We have the TextBlock control named as txtMessage and Button named as btnSayHelloButton.

  5. Now the second part of this experiment is to wire up the button's Click event with an event handler in the MainPage class. In the AppLogic.fs file, find the MainPage type and add the following code:

    // Bind named Xaml components relevant to this page.
    let txtMessage : TextBlock
    = this?txtMessage
    let btnSayHelloButton : Button
    = this?btnSayHelloButton
    //Wire Click Event
    do btnSayHelloButton.Click.Add(fun _ ->
    txtMessage.Text <- "Hello World !")

  6. First we create a reference to the text block and the button. Then we add an event handler to the button's Click event. In F#, the way we add event handlers is by writing a function using the fun keyword. The _ (underscore) tells the F# compiler to ignore the parameters of the function and then we define the statement of a function. On button click, we just change the text of the text block to say "Hello World !". Well, that's all there is to this "Hello World" experiment.

    Notice the use of the ? operator. This is not F#-specific code. Rather, the project template creates a module in the AppLogic.fs file called Utilities. There, ? is defined as an operator that can be used for dynamic lookup of XAML object names for binding purposes.

    The code snippet of the operator is shown as follows:

    /// This is an implementation of the dynamic lookup operator
    f//or binding Xaml objects by name.
    let (?) (source:obj) (s:string) =
    match source with
    | :? ResourceDictionary as r -> r.[s] :?> 'T
    | :? Control as source ->
    match source.FindName(s) with
    | null -> invalidOp (sprintf "dynamic lookup of Xaml
    component %s failed" s)
    | :? 'T as x -> x
    | _ -> invalidOp (sprintf "dynamic lookup of Xaml component
    %s failed because the component found was of type %A instead of
    type %A" s (s.GetType()) typeof<'T>)
    | _ -> invalidOp (sprintf "dynamic lookup of Xaml component
    %s failed because the source object was of type %A. It must be a
    control or a resource dictionary" s (source.GetType()))

  7. Now let's build and run the project. Windows Phone Emulator will be invoked by Visual Studio to deploy the app we just built. You will see a text block with the text Click the button and a button with the text Click to Say Hello !. When the button is clicked, the text block will show the text Hello World !. The screenshots of the final output are shown as follows:

Working with the Button control

A button, as the name goes, is a rectangular control that allows a user to click on it, and when clicked, raises a Click event. We can write listeners for this Click event and add an event handler for the Click event. When the Click event occurs, the event handler will be notified and we can run our business logic against the button click—whatever logical thing we need. Let's see how to work with the button control.

Create a project and add three buttons in the XAML code. For the first button, we will set its properties from the XAML itself. For the second button, we will set the properties from the code. For the third button we will set its properties in its Click event. The XAML code snippet is shown as follows:

<Button Grid.Row="0"
Name="btnFirstButton"
Content="First Button"
Width="300"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Background="Orange"
Foreground="Black"/>
<Button Grid.Row="1"
Name="btnSecondButton"
Content="Second Button"
/>
<Button Grid.Row="2"
Name="btnThirdButton"
Content="Third Button"
/>

For the second and third button, except for its Content attribute, nothing is set in XAML. The properties for the second button is set on the page load event in the MainPage class. The properties for the third button is set on the click of the third button in an event handler. Now let us see the F# code snippet for this in the MainPage class:

//Handle Page Loaded event to set properties for Second Button
do this.Loaded.Add(fun _ ->
btnSecondButton.Width <- 300.0
btnSecondButton.Height <- btnFirstButton.ActualHeight
btnSecondButton.Content <- "Runtime Text"
btnSecondButton.Background <- greenColorBrush
btnSecondButton.Foreground <- yellowColorBrush
)
//Handle Click event on Third button to set properties
do btnThirdButton.Click.Add(fun _ ->
btnThirdButton.Width <- 300.0
btnThirdButton.Height <- btnFirstButton.ActualHeight
btnThirdButton.Content <- "Button Clicked"
btnThirdButton.Background <- redColorBrush
btnThirdButton.Foreground <- whiteColorBrush
btnThirdButton.VerticalAlignment <- VerticalAlignment.Center
btnThirdButton.HorizontalAlignment <- HorizontalAlignment.
Center
)

One thing to learn from here is—whatever properties can be set from XAML, the same can also be set from the code. The preceding demo shows how at page load and with event handlers, a control's properties can be changed at runtime. The screenshot of the final output is shown as follows:

Working with the Checkbox control

As mentioned earlier, Checkbox is a control that allows a user to select or clear an option. We can use a Checkbox control to provide a list of options that a user can select, for example a list of settings to apply in an application. The Checkbox control can have three states namely Checked, Unchecked, and Indeterminate.

To demonstrate this control usage, let's build a demo that contains two checkboxes. The first checkbox demonstrates the Checked and Unchecked states. The second checkbox demonstrates the Checked, Unchecked, and Indeterminate states. We will handle the Checked event when checkboxes are checked, and the Unchecked event when checkboxes are unchecked. The XAML code snippet for this demo is shown as follows:

<Grid x:Name="ContentGrid" Grid.Row="1">
<StackPanel>
<!--Two State Checkbox-->
<CheckBox x:Name="chkBox1" Content="Two State" />
<!--Three State Checkbox-->
<CheckBox x:Name="chkBox2"
IsThreeState="True"
Content="Three State" />
<!-- Message text block -->
<TextBlock x:Name="txtMessage" />
</StackPanel>
</Grid>

As you can see, we have two checkboxes stacked vertically one below the other. StackPanel is a layout control, which, as its name goes, just stacks its children content either vertically or horizontally. The second checkbox has a Boolean property named IsThreeState set to true. That means this checkbox will have three states – Checked, Unchecked, and Indeterminate. Checkboxes expose Checked, Unchecked, and Indeterminate events. We will wire up event handlers for these events and write out a message to the txtMessage text block as seen in the code snippet. The following is the code snippet where we handle the events:

let checkBoxOne : CheckBox = this?chkBox1
let checkBoxTwo : CheckBox = this?chkBox2
let txtMessage : TextBlock = this?txtMessage
let UpdateMessage message =
txtMessage.Text <- message
do checkBoxOne.Checked.Add(fun _ ->
do UpdateMessage "Two State Checkbox Checked"
)
do checkBoxOne.Unchecked.Add(fun _ ->
do UpdateMessage "Two State Checkbox UnChecked"
)
do checkBoxTwo.Checked.Add(fun _ ->
do UpdateMessage "Three State Checkbox Checked"
)
do checkBoxTwo.Unchecked.Add(fun _ ->
do UpdateMessage "Three State Checkbox UnChecked"
)
do checkBoxTwo.Indeterminate.Add(fun _ ->
do UpdateMessage "Three State Checkbox Indeterminate"
)

We first get a reference to the checkbox controls. Then we wire up the Checked and Unchecked events. For the second checkbox, since it supports the Indeterminate state, we wire up the Indeterminate event too. When you run the app and select or clear any checkbox, a message will be shown in the text block. The screenshot of the output is shown as follows:

Working with the Hyperlink control

Hyperlink is a control that presents a button control with a hyperlink. When the hyperlink is clicked, it will navigate to the URI specified, which can be an external web page or content within the app. We specify the URI to navigate through the NavigateUri property. The XAML code snippet for this control is shown as follows:

<HyperlinkButton
Content="Click here to learn about Silverlight"
NavigateUri=http://www.silverlight.net
TargetName="_blank" />

The same effect can be obtained using code. On page load, we would have to just set the NavigateUri property, and when the user clicks on the hyperlink button, he will be navigated to the set URI.

Working with the ListBox control

A ListBox control represents a list of selectable items. It basically displays a collection of items. More than one item in a ListBox control is visible at a time.

As part of the demo app, we will create a listbox and fill it with available color names. When an item is selected in the listbox, we will set the background of the listbox to the selected item. The XAML code snippet is shown as follows:

<Grid x:Name="ContentGrid" Grid.Row="1">
<ListBox x:Name="lstColors" />
</Grid>

The code to fill up the listbox with the names of the colors along with the event handler to handle the listbox's SelectionChanged event is shown as follows:

let colorsListBox:ListBox = this?lstColors
// Fill ListBox with Color names
let props = (typeof<Colors>).GetProperties()
do props |> Seq.iter (fun p - > colorsListBox.Items.Add(p.
Name)|>ignore)
// ListBoxOnSelectionChanged
do colorsListBox.SelectionChanged.Add( fun _ ->
let str = colorsListBox.SelectedItem :?> string
if str <> null then
let clr = (typeof<Colors>).GetProperty(str).
GetValue(null,null) :?> Color
colorsListBox.Background <- new SolidColorBrush(clr)
)

For filling up the listbox with color names, we iterate through the public properties of the System.Windows.Media.Colors class. The Colors class implements a different set of predefined colors. We fill the listbox with the names of the predefined colors by adding them to the Items collection of the listbox.

To handle item selection change, we handle the SelectionChanged event. First, we get the SelectedItem property, and since we know it's a string in our case, we convert it into a string. Then we get the Color property by making use of the string that we converted from SelectedItem. Once we get the color, we set the background of the listbox to the color selected.

The final output of this demo is shown as follows:

Working with the MessageBox control

In this section we will take a look at the MessageBox control. This control displays a message to the user and optionally prompts for a response. The MessageBox class provides a static Show method, which can be used to display the message in a simple dialog box. The dialog box is modal and provides an OK button.

A code to work with the MessageBox control is shown next. Note that this can be worked with only from the code and not from the XAML. First, we show a message box with the ok and cancel button. When a user clicks on the ok button, we show a simple message box with just the ok button.

let mutable messageBoxResult:MessageBoxResult
= MessageBoxResult.None
let messageBody = "Would you like to see the simple version?"
let messageCaption = "MessageBox Example"
do messageBoxResult <- MessageBox.Show(
messageBody,
messageCaption,
MessageBoxButton.OKCancel)
if(messageBoxResult = MessageBoxResult.OK) then
MessageBox.Show("No caption, one button.") |> ignore

The final output of this demo is shown as follows:

Working with the PasswordBox control

PasswordBox, as the name suggests, is used to enter a password in applications. The user cannot view the entered text; only password characters that represent the text are displayed. The password character to be displayed can be specified by using the property PassowrdChar.

Add PasswordBox, Button, and TextBlock in the XAML code. The idea is to enter some text in the PasswordBox control, and on clicking the button show the password text in the text block. The XAML for this demo is shown as follows:

<Grid x:Name="ContentGrid" Grid.Row="1">
<StackPanel>
<PasswordBox x:Name="pwdBox" MaxLength="8"
<Button x:Name="btnShowPassword"
Content="Click to show Password" />
<TextBlock x:Name="txtPassword"/>
</StackPanel>
</Grid>

The code to handle the button click and display the password entered in the text block is shown as follows:

let passwordBox : PasswordBox = this?pwdBox
let passwordShowButton : Button = this?btnShowPassword
let passwordTextBlock : TextBlock = this?txtPassword
do passwordShowButton.Click.Add(fun _ ->
passwordTextBlock.Text <- passwordBox.Password
)

The password box contains a property called Password, which can be used to read the entered password. The final output of the demo is shown as follows:

Working with the ProgressBar control

The ProgressBar control is used to display the progress of an operation. This is often used in UI layouts to indicate a long running operation. One of the requirements of the Windows Phone app is to include a progress bar and show a progress animation whenever a task is a long-running task in any application. The progress bar can have a range between Minimum and Maximum values. It also has an IsIndeterminate property, which means no Minimum and Maximum value is set and the progress bar displays a repeating pattern. This is predominantly used in XAML and its visibility is controlled by the code. The XAML code snippet is shown as follows:

<ProgressBar x:Name="pg1" Value="100" Margin="10"
Maximum="200" Height="15"
IsIndeterminate="False" />
<ProgressBar x:Name="pg2" Margin="10" Height="15"
IsIndeterminate="True" />

Working with the RadioButton control

RadioButton is a control, which represents a button that allows a user to select a single option from a group of options. A RadioButton control is usually used as one item in a group of RadioButton controls. RadioButtons can be grouped by setting their GroupName property. To group radio buttons, the GroupName property on each of the radio button should have the same value. RadioButtons contain two states, namely selected or cleared. RadioButtons have the IsSelected property, which will let us know if a radio button is selected or not.

Create three radio buttons in XAML. Two of them will be grouped and one will be ungrouped. We will listen for the Checked event on the radio buttons and update a text block with the appropriate message. The XAML code snippet is shown as follows:

<Grid x:Name="ContentGrid" Grid.Row="1" Margin="12">
<StackPanel>
<TextBlock Text="First Group:" Margin="5" />
<RadioButton x:Name="TopButton"
Margin="5"
GroupName="First Group"
Content="First Choice" />
<RadioButton x:Name="MiddleButton"
Margin="5"
GroupName="First Group"
Content="Second Choice" />
<TextBlock Text="Ungrouped:" Margin="5" />
<RadioButton x:Name="LowerButton"
Margin="5"
Content="Third Choice" />
<TextBlock x:Name="choiceTextBlock" Margin="5" />
</StackPanel>
</Grid>

As you can see, the first two radio buttons have their GroupName property set whereas the last radio button does not have any GroupName set. We will wire up the Checked event on all three radio buttons and update the text block with information such as which radio button was clicked. The code snippet is shown as follows:

let topButton : RadioButton = this?TopButton
let middleButton : RadioButton = this?MiddleButton
let lowerButton : RadioButton = this?LowerButton
let choiceTextBlock : TextBlock = this?choiceTextBlock
let UpdateMessage (radioButton : RadioButton) =
choiceTextBlock.Text <- "You Chose: " +
radioButton.GroupName + " " +
radioButton.Name
do topButton.Checked.Add(fun _ ->
do UpdateMessage topButton
)
do middleButton.Checked.Add(fun _ ->
do UpdateMessage middleButton
)
do lowerButton.Checked.Add(fun _ ->
do UpdateMessage lowerButton
)

The output from this demo is shown as follows:

Working with the Slider control

The Slider control represents a control that lets users select from a range of values by moving a thumb control along a track.

The Slider control exposes certain properties that can be set to customize the functioning of the slider. We can set the Orientation property to orient the slider either horizontally or vertically. We can change the direction of the increasing value with IsDirectionReversed. The range of values can be set using the Minimum and Maximum properties. The value property can be used to set the current position of the slider.

Add a Slider control to the XAML. Set its Minimum to 0 and Maximum to 10. When the user changes the position of the thumb on the slider, we will listen to the ValueChanged event on the slider and show the current value in a text block. The XAML snippet for the slider is shown as follows:

<TextBlock Text="Slider with ValueChanged event handler:" />
<Slider Margin="0,5,0,0"
x:Name="slider"
Minimum="0"
Maximum="10"
/>
<TextBlock Margin="0,5,0,20"
x:Name="txtMessage"
Text="Current value: 0" />

The code snippet is shown as follows:

let slider : Slider = this?slider
let txtMessage : TextBlock = this?txtMessage
do slider.ValueChanged.Add(fun _ ->
txtMessage.Text <-
"Current value: " + slider.Value.ToString()
)

As you can see, we set the Minimum and Maximum range in the XAML. From the code, we wire up the ValueChanged event. Whenever a user changes the value using the thumb on the slider, the ValueChanged event will be fired and we just read the current value of the slider and update a text block. The final output of this demo is shown as follows:

Working with the TextBox control

The TextBox control can be used to display single or multiline text. It is often used to accept user input in applications. This control is one of the most widely used controls for data input.

On a Windows Phone, whenever a textbox gets focus, an on-screen keyboard known as Software Input Panel (SIP) will be shown automatically by the Windows Phone OS. If we do not want the user to edit the text, we can set the IsReadOnly property on the textbox to true. This will prevent the user from typing anything in the textbox. We can read the value entered in a textbox using the i property. The XAML snippet for a simple textbox is shown as follows:

<TextBox x:Name="ReadOnlyTB"
IsReadOnly="True"
HorizontalAlignment="Left"
Height="35" Width="200" />

A screenshot of a simple textbox with SIP displayed when the textbox gets focus is shown as follows:

Summary

In this article, we took a lap around the supported controls for the Silverlight runtime on the Windows Phone platform. We looked at the XAML way of defining the controls and also how to programmatically work with these controls in the code. We learnt what properties each control exposes and how to wire up events supported by each control.

Resources for Article :


Further resources on this subject:


Windows Phone 7.5 Application Development with F# Develop amazing applications for Windows Phone using F# with this book and ebook
Published: April 2013
eBook Price: $14.99
Book Price: $24.99
See more
Select your format and quantity:

About the Author :


Lohith G.N.

Lohith G. N. who hails from Mysore, India and currently residies in Bangalore, India has over 12 years of software development experience. Currently he works as developer evangelist for Telerik in India and takes care of evangelism for the South Indian region. Lohith comes from a production engineering background and ended up in software development thanks to the FORTRAN language that he learnt during his graduation days. Well versed with the .NET platform, Lohith has experience building web applications, Windows applications, and service-oriented architecture. Lohith has spent close to a decade mostly in the services-based industry and is well versed with the agile method of software development.

Lohith is also a two time Microsoft Most Valuable Professional (MVP) in the area of ASP.NET/IIS. He was awarded this prestigious award from Microsoft in 2011 and 2012. Lohith often writes on ASP.NET/ODATA and maintains his own blog at http://kashyapas.com. He can be reached on Twitter and his Twitter handle is @kashyapa. To know more about Lohith you can check out http://about.me/kashyapa. Lohith is also one of the user group leads for the Bangalore DotNet user group – one of the most active user groups in India. He is a regular speaker at his local user groups.

Books From Packt


Windows Phone 7 Silverlight Cookbook
Windows Phone 7 Silverlight Cookbook

Windows Phone 7.5 Data Cookbook
Windows Phone 7.5 Data Cookbook

Windows Phone 7 XNA Cookbook
Windows Phone 7 XNA Cookbook

Windows Phone 7.5: Building Location-aware Applications
Windows Phone 7.5: Building Location-aware Applications

PhoneGap 2.x Mobile Application Development Hotshot
PhoneGap 2.x Mobile Application Development Hotshot

Android Application Security Essentials
Android Application Security Essentials

Microsoft XNA 4.0 Game Development Cookbook
Microsoft XNA 4.0 Game Development Cookbook

Microsoft Silverlight 5 Data and Services Cookbook
Microsoft Silverlight 5 Data and Services Cookbook


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
5
k
D
1
E
i
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software