Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
501 views

WPF Simplified Build Windows Apps Using Csharp and Xaml

This document introduces the authors of the book. It provides biographies of Mahesh Chand, Rikam Palkar, and Sundaram Subramanian, describing their backgrounds and experiences in software engineering and contributions to C# Corner. It also outlines the contents of the book, which covers topics like WPF applications, XAML, layouts, windows, resources, templates, and controls.

Uploaded by

Földi Zoltán
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
501 views

WPF Simplified Build Windows Apps Using Csharp and Xaml

This document introduces the authors of the book. It provides biographies of Mahesh Chand, Rikam Palkar, and Sundaram Subramanian, describing their backgrounds and experiences in software engineering and contributions to C# Corner. It also outlines the contents of the book, which covers topics like WPF applications, XAML, layouts, windows, resources, templates, and controls.

Uploaded by

Földi Zoltán
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 789

About The Authors

Mahesh Chand
Founder C# Corner. Founder & CEO Mindcracker Inc. Investor, Advisor, and Board member of several
startups and non-profit foundations.

“I would like to thank Rikam P., Sundram S., Vinoth R., Archie Vankar, Praveen Kumar, and the entire C#
Corner team.”

- Mahesh Chand, Garnet Valley 2022

Rikam Palkar
Rikam is on a mission to make the world a better place by writing scalable code. As a software engineer,
he has designed apps for desktop, web, and mobile platforms. Since childhood he was fond of
computers, and his curiosity to open every computer led him to find his passion for programming. He
fell in love with the idea of how humans are making computers work.

His experience as a front-end developer gave him insights on UI and UX norms, how the difference
between 2 pixels can have an impact on user's experience, and why Save and Cancel buttons are aligned
next to each other. What is a dirty flag, why do we need a busy indicator? He learnt many UI norms from
the most popular UI framework out there, WPF. He mastered the framework, and wants to share his
years of experience in this book, WPF simplified.

If he's not spending time coding or hiking you will find him writing articles. That is his way of giving back
to the engineering community, He is the recipient of Most Valuable Professional, Member of the
Month, Member of the Year, awards from C# Corner, and also has won multiple corporate awards.
People have published his articles in different languages (Polish, German, Arabic, Chinese).
His passion gets him excited about the future of engineering and he's doing his bit to shape the world of
technology.

1 @ C# Corner
Sundaram Subramanian (Technical Reviewer)
Sundaram Subramanian is a Software Developer and Tech Geek. Being honored 4 times as the Most
Valuable Professional from the popular C Sharp Corner, PA, and also as Most Valuable Blogger from
TutorialsLink Delhi.

As a Programmer, he has technical ascendancy reposes in the expert knowledge of .NET CORE, ASP.NET
MVC, ADO.NET, WEB API, BLAZOR programming languages with an amenable vision on client’s
requirements. As a Full Stack Developer, he is also expert in fostering web forms on the web pages using
MVC Razor, Angular, HTML, Bootstrap, jQuery, and CSS envisions the pliability that matters the most in
design and development forte.

As per the book is concernerd, “Easy to understand the WPF concepts for beginners. The concepts are
explained neatly and as simple as possible. Not Boyle for beginners but also for the experienced
professionals to freshen up the concepts.”

- Sundaram Subramanian

2 @ C# Corner
Contents
Chapter 1: Introduction to WPF 7
Getting started with WPF using Visual Studio 2019 8
Prerequisites 8
What is WPF 8
Create a new project in Visual Studio 9
Understanding project and files 13
Designing User Interfaces at compile/design time 14
Designing User Interfaces at Run-time 21
WPF Application Types 25
WPF App 25
WPF Browser App 25
WPF User Control Library 29
WPF Custom Control Library 37

Chapter 2: Application Model 485


Application Design 39
Application Components 40
Application-level Resources 46
Application Events and Lifetime 51
Application Data Files 57
Show multiple Windows at startup in WPF 58
Adding a Splash Screen to a WPF Application 59
Getting Command Line Arguments 60

Chapter 3: XAML Language 62


Purpose of XAML 62
The Root Elements 64
Namespaces 65
XAML Markup and Code-Behind 66
Elements and Attributes 67
Content Property 68
Events 74
Container, Parent and Child Controls 75
Shapes 77
Brushes 80
Special Characters in XAML 82
Styling Controls 83
Collection Elements 93

Chapter 4.1: Layouts 99


WPF Layout System – An Introduction 99

3 @ C# Corner
Size, Width, and Height 102
Margins 105
Padding 106
Horizontal and Vertical Alignment 107
Content Alignments 112
Dealing with Percentage Size in WPF 114
Panels 117
Canvas 120
DockPanel 126
Grid 129
StackPanel 145
WrapPanel 149

Chapter 4.2: Windows, Pages and Dialogs 160


Windows 160
Modal Window 172
Window Border Style 176
Pages 187
Navigation 193
Frame 200
WPF Dialog Boxes 202
MessageBox Dialog 202
OpenFileDialog 208
SaveFileDialog 210
PrintDialog 211

Chapter 5.1 Resources 212


Implementing Resources 212
Scope of Resources 214
Application Resources 215
Page or Window Resources 216
Control/Panel Resources 216
Local Resources 217
Resource Dictionary 218
Static and Dynamic Resources 222

Chapter 5.2 Templates in WPF 228


Control Template 228
Content Template: Data Template 232
ItemsTemplate 236

Chapter 6: WPF Controls and Elements 240


AccessText 240

4 @ C# Corner
Button 242
Calendar 257
Checkbox 271
ComboBox 275
DataGrid 290
DatePicker 299
Expander 307
FlowDocumentReader 311
Frame 315
GroupBox 320
Imaging 324
Label 331
ListBox 335
Data Binding 346
Data Binding with a Database 350
Data Binding with XML 353
Data Binding with Controls 355
ListView 359
GridView 370
Menus 376
PasswordBox 386
Popup 389
ProgressBar 406
RadioButton 411
RichTextBox 416
ScrollViewer 421
Slider Control 426
Tab Control 432
TextBlock 441
TextBox 448
Dispatcher Timer 458
ToolTip 461
TreeView 467
ViewBox 478

Chapter 7.1: Find Controls by Name in WPF 483

Chapter 7.2: Building Transparent Controls 486

Chapter 8: Graphics and Media 489


Shapes 490
Line 497
Rectangle 498

5 @ C# Corner
Ellipse 500
Path 502
Polygon 507
Polyline 508
3D Graphics 511
Brushes 515
Solid Brush 516
GradientBrush 518
Radial Gradient Brush 523
Image Brush 528
Drawing Brush 529
Visual Brush 533
Transparent Brushes 538
Brushes and Controls 541
Pen 545
Imaging 550

Chapter 9: Printing in WPF 565


Basic Printing 565
Advanced Printing 571

Chapter 10: Programming Ink in WPF 575


InkCanvas 575
DrawingAttributes 581
EraserShape 583
Strokes 583

Chapter 11: Programming Speech in WPF 584


Speech Synthesis 585
Speech Recognition 595
Grammar and GrammarBuilder 598

Chapter 12: Documents and Typography in WPF 604


TextElement and TextElementCollection 605
Block and BlockCollection 607
Flow Document 608
RichTextBox 645
Figure 650
Floater 653
Bold, Underline, Italic 656
Hyperlink 658
LineBreak 660
Run 661

6 @ C# Corner
Fixed Document 663

Chapter 13: Data Access in WPF 666


13.1 : ADO.NET Entity Framework 668
13.2 : Web API 688
13.3 : WCF 720
13.4 : LINQ to SQL 741
13.5 : Dapper 759
13.6 : ADO.NET 770

7 @ C# Corner
CHAPTER 1. INTRODUCTION

Getting started with WPF using Visual Studio 2022

Windows Presentation Foundation, also known as WPF is a sub-system of .NET family for building a
Windows desktop application. WPF uses XAML as its user interface scripting language and C# as its code-
behind programming language. In other words, all user interfaces such as windows, pages, controls,
menus, and navigations are written in XAML and their code-behind is written using C# language.

This chapter is a swift taste of WPF and its capabilities. In this chapter, you will gain an understanding of
how to build your first WPF application using C# and Visual Studio 2022.

Prerequisites

Prerequisites for building WPF applications include the following:

1. Visual Studio 2022 Community or other editions


2. C# and Object-Oriented Programming concepts
3. Understanding of XAML language and its syntaxes

1. Visual Studio 2022 Community, developed by Microsoft, is a fully-featured, extensible, free and one
of the most popular IDEs for building various software applications for desktop, Web, cloud,
libraries, and mobile. You may download Visual Studio 2022 Community from the URL specified in
the references section of this chapter or just Google it. Please make sure to download and install
Visual Studio 2022 or other editions if you do not have it before you proceed further. Make sure to
select the .NET Desktop development option from available packages. Which will install all basic
libraries and configurations that you need to develop a WPF application.

2. C# is a programming language developed by Microsoft. If you’re not familiar with C#, please find a
link for the free C# Programming book in the references section.
Note: We are using C# 9, for all the examples used in the book.

3. XAML stands for Extensible Application Markup Language is a scripting language to build user
interfaces for windows client applications. XAML has similar syntaxes as XML.

To learn XAML in-depth, find a reference for an eBook at the end of this chapter.

8 @ C# Corner
What is WPF

WPF is a UI framework, designed to create attractive graphical user interfaces for Windows desktop.
WPF is a part of Microsoft’s .NET ecosystem and gets installed as a part of .NET and Visual Studio. WPF
applications are developed using Visual Studio IDE.

WPF is not a replacement for Windows Forms. WPF was developed to replace Windows Forms but some
developers and businesses did not want to give up Windows Forms. Today, both Windows Forms and
WPF are supported in Visual Studio to build windows client applications. You can also use Windows
Forms controls in WPF and vice versa.

WPF is modern, fast, and more dynamic. WPF provides a rich set of 2D and 3D graphics as well as
multimedia controls. It is a set of rich controls, advanced layouts, and beautiful styles and themes. WPF
also supports advanced features such as navigation controls, upgraded rendering process, and flexible
data binding.

Hello, WPF!
Let’s create a simple Hello WPF application using Visual Studio 2022 Community.

Create a new project in Visual Studio


Create a new project in Visual Studio by opening Visual Studio and selecting New Project. When you
open Visual Studio 2022, you will see on the left side a list of your previous projects. On the right side,
you will see various options including Create a new project. See Figure 1.

9 @ C# Corner
Figure 1

Select Create a new project on the above screen.

Figure 2
On the next screen, you can filter based on a language, a platform, and a project type.

10 @ C# Corner
Select C#, Windows, and Desktop from the dropdowns respectively. See in Figure 2.

In the available WPF templates, you will notice there are two templates for WPF App – WPF Application
(.NET Framework) and WPF App (.NET).

.NET Framework and .NET are the different versions of the .NET family; .NET Framework is the older so
we are ignoring .NET Framework here. We will use .NET only.

Note: .NET 6.0 is the latest version of .NET.

After clicking on a Next Button you will be directed to a configuration screen as shown in Figure 3, It has
the following fields.
● In the Project Name text box, type the name of your project. We are naming our project
HelloWPFSample. You can name your project as you desire.
● The Location text box lets you browse a folder where you would like to create your new
application.
● The Solution is a container for one or more projects in Visual Studio, you can even change the
solution name by first unchecking the checkbox which says “Place the solution and project in
the same directory” and which will enable the Solution Name text box.

Figure 3

11 @ C# Corner
Tip: If you are developing a project in the .NET Framework, then you will have one more field to select
the version of .NET Framework. As shown in Figure 4. Select .NET Framework 4.8 or older and newer
versions in the framework version dropdown as per your project’s requirements.

Figure 4
Now click the Create button. This action creates a WPF project with some necessary files already added
inside a project. Figure 4 shows the default Visual Studio solution.

12 @ C# Corner
Understanding project and files

Figure 5

As you can see from Figure 5, there are 4 major sections. Such as 1. UI Designer, 2. XAML Editor,
3. Solution Explorer, and 4. Properties.

1. The UI Designer is a window where you can drag and drop elements from a toolbox. We can set
layouts such as grid or wrap panel etc. and can arrange other UI elements inside the layout
panel. As soon as you drag an element from the toolbox and drop it to the designer, you will
notice that the XAML code is automatically written for you by the designer.

2. XAML Editor: code for each UI element is present inside a XAML file, using XAML editor we can
position, align, style UI elements, add animations etc.

3. The Solution Explorer is like a tree view that lists all the projects which are created under the
same solution and all the files of those projects. By default, you will see there are 3 nodes
created by default for your project – Dependencies, App.xaml, and MainWindow.xaml.
● Dependencies is where we can add references to this project.
● The App.xaml file is an application file which stores resources which are applicable
across the entire application. We are going to discuss this in more detail in the following
chapters.
● In this chapter, our focus is on MainWindow.xaml. The MainWindow.xaml represents
the current Window that you see in the designer. As you can see in Figure 4, the XAML
editor has a Window and a Grid. These are UI elements; they have been added to the
XAML file by default.

4. Properties window: This window has different properties & events related to UI elements. We
will learn about Properties window in more detail in coming sub-chapters.

13 @ C# Corner
In WPF, each UI element can be represented in two ways.
1. At design-time: By a XAML element, This can be achieved in further 2 ways.
a. Drag and drop controls from the Toolbar.
b. Manually typing a code for each UI control in XAML editor.
2. At run-time by a code-behind class.
For example, the XAML editor represents a window at design-time. If you manually add elements
into XAML, they will immediately appear on the window, the developer doesn’t have to run the
project to see the changes while the code-behind C# class represents a window at run-time, any
control added from code-behind won’t be available on windows at design time, one has to run the
project to see the changes.

1. Designing User Interfaces at compile/design time

a. Drag and drop controls from the Toolbar.

If you click on the Toolbox tab in the left side of your screen, you will see a Toolbox that lists all the
available WPF controls as you can see in Figure 6.

Figure 6

Now to add controls to MainWindow, simply drag and drop controls from Toolbox. We are going to
drag and drop a Button, a TextBox, and a ListBox control from Toolbox to MainWindow. After moving
and placing controls around, my MainWindow looks like Figure 7.

14 @ C# Corner
Figure 7

Now one thing you may have noticed when you were dragging and positioning these controls in
MainWindow. The designer was writing XAML code for you. After placing these controls the same as
Figure 7, the XAML code looks like Listing 1.
<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Height="300" Width="500">
<Grid x:Name="OuterGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Name="textBox1"
Height="30"
HorizontalAlignment="Left"
Margin="5 10 0 0"
Width="207" />
<Button Name="button1"
Content="Button"
Height="30"
HorizontalAlignment="Left"
Margin="0 10 0 0"
Width="115"
Grid.Column="1"/>
<ListBox Name="listBox1"
Height="102"

15 @ C# Corner
HorizontalAlignment="Left"
Margin="5 10 0 0"
Width="360"
Grid.ColumnSpan="2"
Grid.Row="1"/>
</Grid>
</Window>
Listing 1

As you can see from Listing 1, there is separate XAML element for each of these controls i.e. Button,
TextBox, and ListBox. Each element also has Name, Width, Height, Margin, VerticalAlignment, and
HorizontalAlignment attributes set for these controls.

Finally, let’s just build and run the solution. The output would look like Figure 8.

Figure 8

Now here comes the best part. The XAML editor fully supports Intellisense. For example, the moment I
started typing <Butt.. , you will see Button element is automatically loaded in Intellisense (see Figure 9).
So you don’t have to rely on the designer completely. You can even manually write your XAML code if
you like.

16 @ C# Corner
Figure 9

Similarly, we can also edit and change existing XAML manually. You will also notice that as soon you edit
XAML, your UI will be updated automatically with your changes.

b. Manually typing a code for each UI control in XAML editor.

Experienced WPF developers leave the habit of dragging and dropping UI controls from
Toolbox, and start typing code for each control manually, this gives a better understanding of
control and its various properties. You will catch this habit with practice. It is not different from the
first approach, the code is the same. The only difference is that you code it with sound knowledge.
Next, step is to add properties of these controls at design time. There are two ways to add properties.

1. Using properties window

2. Manually typing a code for each property in XAML editor

1. Using the properties window.


To see the properties of an element. We need to select that control in the UI designer or a XAML
editor and then press the F4 key. This will trigger the properties window to show. As per Figure 10,
you can see the red highlighted section are the properties window for a Button.

17 @ C# Corner
Figure 10

Now there are 2 tabs – Properties and Events. (Highlighted part in the right-hand corner in Figure 10).

These fields are used to set properties and events for a control respectively. Figure 11 shows how you
can change the Content property of a Button to Add Item. And Figure 10 shows how you can add a Click
event handler to the Button.

18 @ C# Corner
Figure 11

Figure 12

After making these changes in the properties window. If you check the XAML code for Button, you will
see the content attribute is changed and a click attribute is added as shown in Listing 2.

<Button Name="button1"
Click="AddItemClick"

19 @ C# Corner
Content="Add Item"
Height="30"
HorizontalAlignment="Left"
Width="107"
VerticalAlignment="Top"/>

Listing 2

Second approach: Manually typing a code for each property in XAML editor

Another way we can set the properties is by coding manually. where you can directly code in XAML for
each property. So what if you don’t remember the name of each property? no worries we got
Intellisense to rescue. It is the same as coding manually for each control. If you know which properties
to use you can code them directly and avoid navigating to the Properties window.

We have just created a UI so far. So obviously, our application won’t be functional.

Now let’s take a look at the MainWindow.xaml.cs file that is the code-behind file for MainWindow.xaml.
The class code is listed in Listing 3 where first some lines are namespace references, followed by a
partial class named MainWindow who has a default constructor. After that, you will see the
AddItemClick event handler is added for the Button click event.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace HelloWPFSample
/// <summary>
{ /// Interaction logic for MainWindow.xaml
/// partial instance of a MainWindow class
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// Constructor of a MainWindow
/// </summary>
public MainWindow()
{
InitializeComponent();
}
/// <summary>
/// Event-handler for Button click's event

20 @ C# Corner
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddItemClick(object sender, RoutedEventArgs e)
{

}
}
}

Listing 3

Now, let’s add an event handler to the Button. This code adds a Textbox’s content to the ListBox control
when the button is clicked. We do this by adding a single line of code as you can see in Listing 4 where
we simply call ListBox.Items.Add method and pass TextBox.Text as a parameter.
private void AddItemClick(object sender, RoutedEventArgs e)
{
listBox1.Items.Add(textBox1.Text);
}
Listing 4

Build and Run


Now let’s build and run our application by pressing F5.

If you type any text in the TextBox and click the Add Item button, you will see that entered text will be
added to the ListBox and output will look like Figure 13.

Figure 13

2. Designing User Interfaces at Run-time

As we said earlier in this chapter, we have two choices to design our user interfaces. Using XAML at
design-time and using C# classes at run-time. In most of the cases, you will end up mixing both of them.

21 @ C# Corner
You will end up in designing some interfaces at design-time that would not change no matter what and
you would create user interfaces at run-time that will change dynamically.

Now let’s create the same UI using WPF code-behind.

First, let’s comment out our XAML code that creates TextBox, Button, and ListBox controls. The
commented XAML looks like Listing 5. Also, note that we have added the Name attribute of Grid to
RootLayout. This is very important. Because we are going to use this name to add children to the Grid.
The code-behind class accesses XAML elements by their name. This confusion will be clear once we
understand the code in listing 6.

<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="500">
<Grid x:Name="OuterGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!--<TextBox Name="textBox1"
Height="30"
HorizontalAlignment="Left"
Margin="5 10 0 0"
Width="207" />
<Button Name="button1"
Content="Button"
Height="30"
HorizontalAlignment="Left"
Margin="0 10 0 0"
Width="115"
Grid.Column="1"/>
<ListBox Name="listBox1"
Height="102"
HorizontalAlignment="Left"
Margin="5 10 0 0"
Width="360"
Grid.ColumnSpan="2"
Grid.Row="1"/>-->
</Grid>
</Window>
Listing 5
Basically, we will create a TextBox, Button, and ListBox at run-time and then we need to add these
controls to the Grid as children.

First of all, let’s add three variables each for TextBox, Button, and ListBox. After that, create a method
and name it CreateDynamicUI which is responsible for initializing TextBox, Button, and ListBox controls

22 @ C# Corner
and setting their properties. As you can see from the code in Listing 6, we can also add event handlers
on button1.Click event in the code itself by using a RoutedEventHandler and passing a method as a
parameter.

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{

#region Constructor
/// <summary>
/// Constructor of a MainWindow
/// </summary>
public MainWindow()
{
InitializeComponent();
}
#endregion

#region UI Properties
/// <summary>
/// The TextBox control
/// </summary>
protected TextBox textBox1;

/// <summary>
/// The Button control
/// </summary>
protected Button button1;

/// <summary>
/// The ListBox Control
/// </summary>
protected ListBox listBox1;
#endregion

#region Methods
/// <summary>
/// This method creates UI controls and set their properties
/// </summary>
private void CreateDynamicUI()
{
// Create a TextBox
textBox1 = new TextBox();
textBox1.Name = "textBox1";
textBox1.Width = 207;
textBox1.Height = 28;
textBox1.Margin = new Thickness(13, 17, 0, 0);
textBox1.HorizontalAlignment =
System.Windows.HorizontalAlignment.Left;
textBox1.VerticalAlignment =
System.Windows.VerticalAlignment.Top;
// Add to Grid

23 @ C# Corner
RootLayout.Children.Add(textBox1);

// Create a Button
button1 = new Button();
button1.Name = "textBox1";
button1.Content = "Add Item";
button1.Width = 107;
button1.Height = 30;
button1.Margin = new Thickness(235, 15, 0, 0);
button1.HorizontalAlignment =
System.Windows.HorizontalAlignment.Left;
button1.VerticalAlignment =
System.Windows.VerticalAlignment.Top;
button1.Click += new RoutedEventHandler(AddItemClick);
// Add to Grid
RootLayout.Children.Add(button1);

// Create a ListBox
listBox1 = new ListBox();
listBox1.Name = "listBox1";
listBox1.Width = 327;
listBox1.Height = 102;
listBox1.Margin = new Thickness(15, 57, 0, 0);
listBox1.HorizontalAlignment =
System.Windows.HorizontalAlignment.Left;
listBox1.VerticalAlignment =
System.Windows.VerticalAlignment.Top;

// Add children to the Grid


RootLayout.Children.Add(listBox1);
}
#endregion

#region Event-Handlers
/// <summary>
/// Event-handlder for add button's click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddItemClick(object sender, RoutedEventArgs e)
{
listBox1.Items.Add(textBox1.Text);
}
#endregion
}
Listing 6
Now, let’s call the CreateDynamicUI method on MainWindow’s constructor as you can see in Listing 7.
The output will be the same as Figure 11.

public MainWindow()
{
InitializeComponent();
CreateDynamicUI();
}
Listing 7

24 @ C# Corner
WPF Application Types
WPF allows you to create the following four types of applications.

1. WPF App
2. WPF Browser App
3. WPF User Control Library
4. WPF Custom Control Library

The WPF app template allows you to create a windows standalone application. A WPF Browser App
template allows you to create a windows app with browser support including browser navigation and
uses a browser to show the contents. WPF User Control Library is used to create reusable WPF controls
and WPF Custom Control Library is used to create third party WPF.

WPF App
Up above we have seen how to create a complete WPF App. When we created the HelloWPFSample
app in our previous section. A WPF standalone app is a traditional desktop application. The application
type is an executable assembly (.exe) that runs on a Windows OS. A user interface in this kind of
application is usually a window.

WPF Browser App


A WPF Browser App also known as XBAP application is a traditional desktop application with navigation
support by using a browser like navigation buttons. You may build this kind of application to provide
back and forward navigation support that will allow users to move back and forth within while
navigating through user interfaces. A user interface in this kind of application is usually a page.

Don’t let the Browser name in this application type confuses you. This application type still is an
executable assembly(.exe) that runs on a local machine. The only difference is how the user interfaces
look and how the application keeps track of the history of navigation.

Let’s build a WPF Browser App. Create a New Project in Visual Studio 2022 and select WPF Browser App
in the project templates, as per Figure 14.

Note: We are developing this app in .NET Framework because .NET doesn’t support WPF Browser App at
the time we are writing this book.

25 @ C# Corner
Figure 14
When you build a project. First thing you will notice is that there are no MainWindow.xaml. Instead, you
will see Page1.xaml has been added to the project.
<Page x:Class="WpfBrowserApp1.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfBrowserApp1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="Page1">
<Grid>

</Grid>
</Page>
Listing 8

As you can see in Listing 8, unlike Window.XAML, the Page.XAML does not have Width and Height
properties. However, there is DesignHeight and DesignWidth of the page. These 2 properties use to
maintain this width and height during the design time. When you run the application, it will be a full
Browser window anyway.

mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"


Now, let’s add a few controls to this application. We have added a Button, a TextBox, and a ListBox
control by dragging and dropping them from the toolbox to the page. After adjusting their locations
and layout, my page UI looks like Figure 15.

26 @ C# Corner
Figure 15

By default, the XAML designer does not specify the name for controls. As we learnt the importance of
naming in previous topics i.e. to access UI control’s references in code behind, we must set their Name
property. Let’s set a Name property of Button, TextBox and ListBox controls to Button1, TextBox1, and
ListBox1 respectively.

And also change the Content property of Button to Add Item.

The final XAML code would look like Listing 9.

<Grid x:Name="OuterGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Name="textBox1"
Height="30"
HorizontalAlignment="Left"
Margin="5 10 0 0"
Width="207" />
<Button Name="button1"
Content="Button"
Height="30"
HorizontalAlignment="Left"
Margin="0 10 0 0"
Width="115"
Grid.Column="1"/>
<ListBox Name="listBox1"
Height="102"
HorizontalAlignment="Left"

27 @ C# Corner
Margin="5 10 0 0"
Width="360"
Grid.ColumnSpan="2"
Grid.Row="1"/>
</Grid>

Listing 9

Next, double click on Button to add a click event handler for this button.

Now we need to add the logic to fill ListBox items. Write one line of code that is listed in Listing 10 on
the button click event handler. This code simply takes the TextBox.Text property and adds it to a ListBox
using ListBox.Items.Add method.

private void button1_Click(object sender, RoutedEventArgs e)


{
listBox1.Items.Add(textBox1.Text);
}
Listing 10

When you run the application, you will notice the URL of the Web Browser looks like this:
file:///C:/Books/Book%20WPF/Chapter%201%20Introducing%20WPF/BrowserAppSample/BrowserAppS
ample/bin/Debug/BrowserAppSample.xbap

As you can see in Listing 8, a Page hosts the main window in an XBAP application. When you add some
text and click on an Add Item button, you will see the text is being added to the ListBox as shown in
Figure 16. You will also notice that this application is running in a Web Browser and has Home, Refresh,
Back, Next and other browser functionality.

28 @ C# Corner
Figure 16

WPF User Control Library


A UserControl is another type of window, the purpose of UserControl is reusability. It compiles into a
dynamic linked library (DLL) that can be referenced by other projects. That means the output of
UserControl is DLL that can be reused in the same or other projects.

What is DLL?
It stands for Dynamic-link library. It is a collection of classes (code and data) that can be shared
between Windows applications. Let’s say, we need one reusable application to browse files on a system.
From the UI perspective, there will be a browse button to select a file from a location and a label to
display the selected file name.

One way to do this is to copy and paste the same code every time you need this functionality. Or you
can simply build a user control and use that control every time you need that functionality. That means
you only once have to develop such an app and can reuse it as per requirements. We can reuse such
functionalities within the same application as well as in different applications.

And we can achieve this with the WPF User Control Library. This section has two parts. In the first part,
we will build a WPF User Control which will create a DLL file for us. In the second part, we will discuss
how to use this DLL in other WPF applications.

The XamlFileBrowser Control


Let’s name our application. XamlFileBrowser sounds great. This app allows users to browse files on their
machine. Follow the same steps as usual. Create a new project in Visual Studio 2022 and select WPF
User Control Library from Installed templates. Click the next button, as shown in Figure 17.

29 @ C# Corner
Figure 17

Specify the name for your project. Then click the Create button.

Figure 18

This action creates the WPF User Control Library App.

30 @ C# Corner
You will see UserControl1.xaml file has been added to the project. The contents of the control look like
Listing 11 where you can see the root element of the control is UserControl instead of a window.

<UserControl x:Class="XamlFileBrowser.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XamlFileBrowser"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>

</Grid>
</UserControl>

Listing 11

Designing the XamlFileBrowser Control

Let’s add a Button and a TextBox element to this user control by dragging and dropping these controls
from Toolbox or you can code manually as well. Then change the names of the TextBox and the Button
controls to FBCTextBox and FBCButton respectively. After adjusting the size of controls and page, the
final design of the user control looks like Figure 19.

Figure 19

You may have noticed from Figure 14; We even have changed the background color of the page to Light-
blue by using a Background property of user control.

Now double click on Textbox to add TextChanged event-handler for Textbox and double click on a
button to add a click event-handler for Button. The final XAML code would look like Listing 12.

<UserControl x:Class="XamlFileBrowser.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XamlFileBrowser"
mc:Ignorable="d"
d:DesignHeight="35" d:DesignWidth="400" Background="Light Blue">
<Grid x:Name="OuterGrid">
<TextBox Name="FBCTextBox"
Height="50"
HorizontalAlignment="Left"
Margin="5,5,0,0"

31 @ C# Corner
Text="TextBox"
TextChanged="FBCTextBox_TextChanged"
TextWrapping="Wrap"
Width="284" />
<Button Name="FBCButton"
Click="FBCButton_Click"
Content="Browse"
HorizontalAlignment="Left"
Margin="300,5,0,0"
Height="50"
Width="83" />
</Grid>
</UserControl>

Listing 12

Now, let’s add logic in the code-behind of user control.

First, Let’s add a public property and name it as FileName then add getter and setter which will return
and set the text of the FBCTextBox control. The property code is listed in Listing 13:

public string FileName


{
get => FBCTextBox.Text;
set => FBCTextBox.Text = value;
}
Listing 13

Now, on the FBCButton’s click event-handler, we need to add logic to browse files from the system. It
can be done with OpenFileDialog control and finally assign FileName property, as per Listing 14.

private void FBCButton_Click(object sender, RoutedEventArgs e)


{
var openFileDlg = new Microsoft.Win32.OpenFileDialog();
if (openFileDlg.ShowDialog() == true)
this.FileName = openFileDlg.FileName;
}

Listing 14

In the end, we need an event. Let’s call it FileNameChanged and map it to the TextChanged event of the
TextBox as listed in Listing 15. Notice that we have set e.Handle to true. This indicates that the event-
handler has already executed an event, so it wouldn’t need to be processed any further.

public event EventHandler<EventArgs> FileNameChanged;


private void FBCTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
e.Handled = true;
FileNameChanged?.Invoke(this, EventArgs.Empty);
}

32 @ C# Corner
Listing 15

In this User Control, whenever you type a filename or browse a file from the system, the public
FileName property will be updated with the text of the TextBox and we can use this FileName property
to display the name of the file.

That’s it. Now build the application that will create XamlFileBrowser.dll for us.

Then go to the bin folder of this project to locate this DLL. This is the library we are going to use in our
other WPF applications whenever we need a File Browser control.

XAMLFileBrowser User Control’s Host Application

Using a WPF User Control in XAML is pretty simple. First, add a reference for a DLL and then update the
namespace.

Let’s create a WPF application in the same solution.

Right-click on the Solution name in Solution Explorer and select Add >> New Project as you can see in
Figure 20.

Figure 20

33 @ C# Corner
On the next step, select WPF Application from the Project Templates and give the application a name
XamlFileBrowserHostSample as you can see in Figure 21.

Figure 21

Click on a Create Button to proceed.

First thing you want to do is Right-click on the XamlFileBrowserHostSample project and select “Set as
Startup Project”, as shown in Figure 22. This is important because when the solution has multiple
projects, we need to ensure that solution knows which project to execute first when we run the project.

Figure 22

Now we’re going to add a reference to the XamlFileBrowserHostSample. Right-click on the


“Dependencies” and select “Add Project Reference” dialogue is shown in Figure 23.

34 @ C# Corner
Figure 23

After clicking on Add Project Reference Menu, it will open a dialogue box where you will be shown a list
of DLLs. simply select a DLL from the list or you can browse the DLL from the system if it is not listed. For
our project, we have XamlFileBrowser.dll available on the list. So we need to select the same and click
on an OK button. Which will add the DLL to XamlFileBrowserHostSample project. Follow instructions as
per Figure 24.

Figure 24

Now build the solution by hitting F6.

35 @ C# Corner
At last, XamlFileBrowser user control will be available to use. In the MainWindow.XAML file, type
xmlns:UC= in the windows root element attributes and at the bottom of the available namespace, you
will see XamlFileBrowser. Select that from the list, as shown in Figure 25.

Figure 25

This action will add the following line to the XAML file.

xmlns:UC="clr-namespace:XamlFileBrowser;assembly=XamlFileBrowser"

Now we can use namespace UC to create our user control’s instance. As shown in Listing 16 where we
have added a User Control, and also sets its Name, Width, Height, and Margin attributes and finally sets
its FileNameChanged event-handler. We also need to add a Label control to display the name of the file.

<Grid x:Name="OuterGrid">
<UC:UserControl1 Name="FileBrowserUserControl"
FileNameChanged="FileBrowserUserControl_FileNameChanged"
Height="35"
Margin="26,12,77,264"
Width="400"/>
<Label Name="label1"
Content="Label"
Height="33"
HorizontalAlignment="Left"
Margin="24,67,0,0"
VerticalAlignment="Top"
Width="408" />
</Grid>
Listing 16

Listing 17 shows how FileNameChanged event-handler used to display FileName in the Label.
private void FileBrowserUserControl_FileNameChanged(object sender, EventArgs e)
{
label1.Content = FileBrowserUserControl.FileName;
}
Listing 17

Now if you Build and Run the application, the output would look like Figure 26. If you click on the
Browse button, it opens the OpenFileDialog control and lets you browse and select a file. The selected
file name is added to the label.

36 @ C# Corner
Figure 26

WPF Custom Control Library


WPF allows you to build custom controls. A custom control is developed for third-party developers to
customize and then use them in their applications. For example, you could build a cool WPF Chart
control and sell that as a control to developers who wish to build similar functionality. Then that chart
control can be reused as per developer’s requirements and they can customize its style, themes, colors,
and other properties.

To create a Custom Control Library, you need to select the WPF Custom Control Library as you can see in
Figure 27. We will discuss custom controls in more detail in the coming chapter.

Figure 27

37 @ C# Corner
Summary
This chapter is an introduction to WPF. In this chapter, we saw how to create our first WPF application
using Visual Studio 2022. We also saw various application types and Visual Studio templates. In the end,
we learned how to build simple WPF applications.

In the next chapter, we are going to focus more on the application model supported by WPF and have
an in-depth look at various components of a WPF application.

References
Download Visual Studio here: https://www.visualstudio.com/

Learn more about the Visual Studio here: https://visualstudio.microsoft.com/vs/getting-started/

Free C# book: http://www.c-sharpcorner.com/ebooks/programming-csharp-for-beginners

Free XAML programming book: http://www.c-sharpcorner.com/ebooks/programming-xaml

.NET Framework vs. .NET : https://www.c-sharpcorner.com/article/difference-between-net-framework-


and-net-core/

Learn .NET 5: https://devblogs.microsoft.com/dotnet/introducing-net-5/

38 @ C# Corner
Chapter 2: Application Model
In this chapter, we will learn the WPF application model and application life cycle.

Application Design
Figure 1 shows a typical WPF application design. A WPF application is a combination of one or more
windows. Each window could consist of controls, common dialogs, custom and third-party controls. The
controls may include menus and tabs, container controls, data-bound controls, windows common
dialogs and so on.

Figure 1

The layout panels such as a grid or stack panels are container controls, which means they can host other
container controls or other WPF controls.
● Parent control: A container that hosts other controls is called a parent control.
● Child control: A control which gets hosted within a parent control is called a child control.
Child control further may host more child controls and can become their parent control. For example, a
ListBox control can host CheckBox, Label, TextBox etc.
Unlike traditional windows forms, In WPF each control can be accessed and managed individually
without interfering with their parent control.

39 @ C# Corner
Application Components
1. App.xaml
Each application in WPF has an App.xaml file and its code-behind App.xaml.cs file.

The App.xaml consists of controls and resources that can be applied to the entire application. Resources
such as styles whose scope has been spread across the application.

On the other hand, the App.xaml.cs file hosts the application related code logic such as application
events.

If you double click on the App.xaml file in solution explorer, it will open the file as shown in Figure 2. As
you can see, the App.XAML begins with an “Application” tag which has attributes such as x:Class and
StartupUri. x:Class specifies the name of your application and StartupUri states the window which loads
first when the application starts. So if you need to change your startup window at design-time in XAML,
this is the place where you can change it.

Figure 2

Expand App.xaml in solution explorer to see App.xaml.cs file shown in Figure 3, Double-click on
App.xaml.cs to open the file. This is where we are going to write our application related code. You will
also notice a partial class named App, which is derived from an Application class.

Figure 3

40 @ C# Corner
There is one more partial class which is by default hidden from developers. If you select any method
from the dropdown as shown in Figure 4. This will open another instance of a partial class which is
shown in yellow highlighted color.

Figure 4

Once you open a file named App.g.i.cs, you can navigate to any method by selecting a method name
through the drop-down box (refer Figure 5). E.g. Select the InitializeComponent method to go to its
implementation.

Figure 5

The second part of the partial App class that looks like Listing 1.

41 @ C# Corner
namespace WPFSample {
/// <summary>
/// App
/// </summary>
public partial class App : System.Windows.Application {

/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {

#line 5 "..\..\..\App.xaml"
this.StartupUri = new System.Uri("MainWindow.xaml",
System.UriKind.Relative);

#line default
#line hidden
}

/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]

[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks",
"4.8.1.0")]
public static void Main() {
HelloWPFSample.App app = new HelloWPFSample.App();
app.InitializeComponent();
app.Run();
}
}
}

Listing 1

As you can see from Listing 2, there is the Main method that creates an instance of
HelloWPFSample.App class and calls InitializeComponent and Run methods.

public static void Main() {


HelloWPFSample.App app = new HelloWPFSample.App();
app.InitializeComponent();
app.Run();
}
Listing 2

On the InitializeComponent method, you will see StartupUri is set to the MainWindow.xaml.

this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);

So if you need to change your startup window at run-time, this is the place where you can do so.

42 @ C# Corner
Current Application Instance
The Current is a static property which gets the Application object for the current AppDomain from
anywhere within that application.
Application curApp = Application.Current;

MainWindow
Application.MainWindow property gets or sets the main window of the application. The code snippet in
Listing 3 gets the MainWindow from a Current property & sets it to the new Window object.
Application curApp = Application.Current;
Window mainWnd = curApp.MainWindow;

Listing 3

The code snippet in Listing 4 sets MainWindow property in XAML.


<Application x:Class=" HelloWPFSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="App_Startup">
<Application.MainWindow>
<NavigationWindow x:Name='MainNavigationWindow'
Source=" MainWindow.xaml"
Visibility="Visible"/>
</Application.MainWindow>
</Application>
Listing 4

Application Level Data


Funny thing is, there is a property named Properties, which sets the data that can be available across
the application. We can save the data in the form of key-value. This is the same as application-state in
ASP.NET where we can store any application-level data that later can be accessed from anywhere within
that application.

As per the code snippet in Listing 5, we are adding two data items to Properties. Here, “Login” and
“Password” are the keys. And “DonJoe” and “12345” are their assigned values.

void App_Startup(object sender, StartupEventArgs e)


{
this.Properties["Login"] = "Peter";
this.Properties["Password"] = "12345";
}

Listing 5

43 @ C# Corner
Once this data is added to Application.Properties, it is available to use anywhere within the application.
The code snippet in Listing 6 shows how to access this data.

string uid = Application.Current.Properties["Login"].ToString();


string pwd = Application.Current.Properties["Password"].ToString();

Listing 6

You can even store objects or collections in the Properties. Let’s do one example. In Listing 7, we have
created an Author class.
using System;
using System.Collections.Generic;
using System.Text;

namespace HelloWPFSample
{
/// <summary>
/// The Author Classs
/// </summary>
public class Author
{
/// <summary>
/// Constructor of Author
/// </summary>
/// <param name="name"></param>
/// <param name="age"></param>
/// <param name="bookName"></param>
public Author(string name, Int16 age, string bookName)
{
this.AuthorName = name;
this.AuthorAge = age;
this.PublishedBook = bookName;
}

/// <summary>
/// The property name
/// </summary>
private string name;
/// <summary>
/// The property AuthorName
/// </summary>
public string AuthorName
{
get { return name; }
set { name = value; }
}

/// <summary>
/// The property age
/// </summary>
private Int16 age;
/// <summary>
/// The property AuthorAge
/// </summary>
public Int16 AuthorAge

44 @ C# Corner
{
get { return age; }
set { age = value; }
}

/// <summary>
/// The property book
/// </summary>
private string book;
/// <summary>
/// The property PublishedBook
/// </summary>
public string PublishedBook
{
get { return book; }
set { book = value; }
}
}
}

Listing 7

Listing 8 shows how you can use Properties to save the new instance of an Author inside an
App_Startup method. The key here is CurrentAuthor and the value is the object itself.
void App_Startup(object sender, StartupEventArgs e)
{
// Create and store an object in Properties
Author author = new Author("Peter", 33, "Programming");
this.Properties["CurrentAuthor"] = author;
}
Listing 8

Now let’s see how to access CurrentAuthor. The code snippet in Listing 9 shows how to retrieve the
Author instance from the Properties.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
Author curAuthor =
(Author)Application.Current.Properties["CurrentAuthor"];
string name = curAuthor.AuthorName;
Int16 age = curAuthor.AuthorAge;
}
Listing 9

Using this approach, we can save data at the application level and access it anywhere within the
application.

45 @ C# Corner
Application-level Resources
Resources are the values or data that is stored temporarily somewhere in the application so that we can
reuse them later when we need them. Resources property gets or sets a collection of application-scope
resources such as styles and brushes or data. By setting Resources property on the application level, you
can make these resources available for the entire application.

We will learn about resources and style in more detail in chapter 5.1 and 5.2. For now, let’s understand
what is a style? and what is a brush? In brief.

A style:
The concept of styles in WPF is the same as CSS in web development. Styles are used for formatting
purposes. They make the UI look more attractive and user-friendly by giving rich looks to the controls.

A brush:
In WPF brush is used to define a color, you can define the background, foreground, border color etc. of
any UI element in WPF with the brush, one need to use either of these brush type SolidColorBrush,
LinearGradientBrush, RadialGradientBrush or ImageBrush. We will learn about brushes in more detail in
chapter 3.

For example, this code snippet in Listing 10 adds a SolidColorBrush and a style resource to the
Application.
Note: Syntax for the comments in xaml. <!-- Some Text -->
<Application x:Class="WPFSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="App_Startup"
ShutdownMode="OnLastWindowClose">
<Application.Resources>
<!-- YellowSolidBrush -->
<SolidColorBrush x:Key="YellowSolidBrush" Color="Yellow"/>

<!-- Style for Submit Button -->


<Style x:Key="SubmitButtonStyle"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="100"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Content" Value="Submit"/>
</Style>
</Application.Resources>
</Application>
Listing 10

Now I can access these resources on any window or page of the application. These resources are
accessed with their keys.

46 @ C# Corner
For example, if you have a TextBlock and you wish to set the Background property of the TextBlock to
the Yellow color. Then all you have to do is to use a key of the resource i.e YellowSolidBrush in this
example and bind it as a StaticResource. The StaticResource has the ability to store data that we define
as a resource. The static resource does not change once they are assigned and they are applied at the
compiled time only. We will learn about StaticResource in more detail in an upcoming chapter on
Resources.

<TextBlock x:Name="TextBlockBrush"
Background="{StaticResource YellowSolidBrush}"
Text="Main Window" />

Let’s use that style resource as well, say you also have a button, and you want to use style defined in
side App.xaml. Again use StaticResource to apply a style to the button.

<Button x:Name="SubmitButton"
Style="{StaticResource SubmitButtonStyle}"/>

Finding Resources
We saw how resources are associated with a key. And we can use these keys to find resources as well.
Method FindResource is the way to do so. If a resource is found, then it returns it as an object. If the
resource is not found, then it throws an exception. You must cast the returned object to the respective
resource type before using it. The FindResource method first searches for the resources at the
application level. If the resource is not found in the application resources, then it looks in the system
resources including SystemColors, SystemFonts, and SystemParameters.

The code snippet in Listing 11 uses the FindResource method to find YellowSolidBrush and converts the
object to a SolidColorBrush.
{
try
object res = Application.Current.FindResource("YellowSolidBrush");
SolidColorBrush yellowBrush = (SolidColorBrush)res;
}
catch (ResourceReferenceKeyNotFoundException resExp)
{
MessageBox.Show("Resource not found." + resExp.Message);
}
Listing 11

If a resource’s not found, then the FindResource method will throw an exception. If you wish to get rid
of this exception, then you can even use the TryFindResource method. It does the same job as
FindResource except it does not throw an exception when a resource is not found.

The code snippet in Listing 12, shows how TryFindResource method is used to find YellowSolidBrush
and if the resource is found then it converts the object to a SolidColorBrush.

object res = Application.Current.TryFindResource("YellowSolidBrush");


if (res != null)
{ SolidColorBrush yellowBrush = (SolidColorBrush)res;
}

47 @ C# Corner
Listing 12

ShutdownMode
ShutdownMode property gets or sets the events on which you wish to close your application. It is a type
of enumeration and this enum has the following three values:

Figure 6

● OnLastWindowClose: An application shuts down when either the last window closes or the
Shutdown method of application is called.

● OnMainWindowClose: An application shuts down when either the main window closes or the
Shutdown method of application is called.

● OnExplicitShutdown: An application shuts down only when the Shutdown method is called.

The code snippet in Listing 13 sets ShutdownMode at design-time in XAML.

<Application x:Class="WPFSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="App_Startup"
ShutdownMode="OnLastWindowClose"/>

Listing 13

The code snippet in Listing 14 sets ShutdownMode at run-time via code-behind.


Application curApp = Application.Current;
curApp.ShutdownMode = ShutdownMode.OnLastWindowClose;

Listing 14

Shutdown Method
Shutdown method stops the application immediately regardless if close-event is fired or not. Shutdown
method implicitly calls window-close or MainWindow-close events if Shutdown mode is set to

48 @ C# Corner
OnLastWindowClose, OnMainWindowClose respectively. The code snippet in Listing 15 gets the current
application instance and calls the Shutdown method.
Application curApp = Application.Current;
curApp.Shutdown();
Listing 15

StartupUrI
We know that StartupUri specifies a window which becomes the first screen to appear when the
application starts. Let’s see how the same can be achieved at run-time. The code snippet in Listing 16
sets the StartupUri of application to SecondWindow.xaml. Now when you run your application it will
start with SecondWindow.
Application curApp = Application.Current;
curApp.StartupUri = new Uri("SecondWindow.xaml", UriKind.RelativeOrAbsolute);

Listing 16

Window
So far, we have been working with window.xaml. When we create a project, by default
MainWindow.XAML gets added. MainWindow.XAML is an instance of a window which gets added to the
WindowCollection. As the application grows we keep adding more windows to the application. each
window instance automatically gets added to the WindowCollection.

Note: windows which are created by worker threads are not added to the WindowCollection. And a
window reference is automatically removed from the collection before its Closed-event is raised.

The code snippet in Listing 17 loops through all window objects in an application and displays their titles.

foreach(Window window in Application.Current.Windows)


{
MessageBox.Show(window.Title);
}
Listing 17

Managing Cookies
A cookie is a piece of data that is stored on a user’s machine. Cookies are usually used by a WPF browser
application. There are two types of cookies – session cookies and persistent cookies.

1. Session cookies store data which is available during the application’s session and this data is
deleted once the session expires.

2. Persistent cookies, on the other hand, are stored in a temporary Internet files folder and can be
available for a longer time. The lifetime of these cookies is not dependent on session; instead , it
can be set within the cookie data itself, by specifying an expiration date and time.

49 @ C# Corner
A cookie data is stored in the form of a name-value pair. Here is an example of cookie data.
● “UserName=DonJoe”

If a cookie data has expiration date and time followed by a semicolon, then it is considered as a
persistent cookie.

● Format for a persistent cookie.


NAME=VALUE; expires=DAY, DD-MMM-YYYY HH:MM:SS GMT

● Here is an example of persistent cookie data.


“UserName=DonJoe; expires=Friday, 10-Dec-2010 00:00:00 GMT”

To create a cookie on users’ machines we can use the Application.SetCookie method. This method takes
two parameters – a Uri and a string. The first parameter, the Uri, specifies a location where the cookie
will be created at and the second parameter is a cookie data.

Code snippet in Listing 18 creates two cookies using the SetCookie method. One is a session cookie and
the other is a persistent cookie.

string simpleCookie = "CSCUser1=DonJoe";


string cookieWithExpiration = "CSCUser2=DonJoe;expires=Mon, 1-Mar-2021
00:00:00 GMT";

Uri simpleCookieUri = new Uri(@"C:\Junk\SimpleCookie");


Uri persistenetCookieUri = new Uri(@"C:\Junk\PersistentCookie");

Application.SetCookie(simpleCookieUri, simpleCookie);
Application.SetCookie(persistenetCookieUri, cookieWithExpiration);

Listing 18

Application.GetCookie method retrieves cookie data from the specified Uri.


The code snippet in Listing 19 uses the GetCookie method to get the cookie data and displays it in a
MessageBox.
Uri cookiePath = new Uri(@"C:\Junk\SimpleCookie");
string cookie = Application.GetCookie(cookiePath);
MessageBox.Show(cookie);

Listing 19

Load Component
Application.LoadComponent method loads a XAML file that is to be found at a specified URI. The code
snippet in Listing 20 uses Application.LoadComponent method to load SecondWindow.xaml.
object comp = Application.LoadComponent(
new Uri("C:/MyProject/SecondWindow.xaml",
System.UriKind.RelativeOrAbsolute));

Listing 20

50 @ C# Corner
Run Method
The Run method is responsible for starting the application. The code snippet in Listing 21 creates an
application’s instance and calls the Run method.

Application app = new Application ();


app.Run();
Listing 21

The Run method can also take a window instance as a parameter, allowing this window to be a startup
window of the application. The code snippet in Listing 22 creates an application instance and calls the
run method which takes a window object as a parameter.

Application app = new Application ();


app.Run(new Window1());
Listing 22

Application Events and Lifetime


The WPF application incorporates all the events that take place from the start of the application until
the application closes.

Startup-event
When a WPF application starts, it first executes the Run method. Which triggers the startup event? This
event is only called once in the lifetime of an application and you may want to use this event to initialize
most of the application data members that are necessary for an application to start. Some of the
activities you may want to perform on a Startup event handler are getting command-line arguments,
opening the main window, and initializing application resources and properties.

The code snippet in Listing 23 shows how “attribute: Startup” is used to define the startup-event
handler in XAML.
<Application x:Class="AppModelSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="Application_Startup"/>
Listing 23

The definition of Application_Startup event handler is listed in Listing 24.

public partial class App : Application


{
private void Application_Startup(object sender, StartupEventArgs e)
{

}
}
Listing 24

51 @ C# Corner
The following code in listing 25, gets the command line arguments and sets application-level properties.
We are also creating a window and starting our app with this window. At the end of this chapter, we
have covered command-line arguments.
using System;
using System.Collections.Generic;
private void Application_Startup(object sender, StartupEventArgs e)
{
// Get CommandLine Arguments
bool fullScreen = false;
foreach (string arg in e.Args)
{
if (arg == "")
fullScreen = true;
}

// Set Application level data properties


this.Properties["Login"] = "DonJoe";
this.Properties["Password"] = "pwd";

// Create a Window, set its properties and display it


SecondWindow window = new SecondWindow();
if (fullScreen)
{
window.WindowState = WindowState.Minimized;
}
window.Show();
}
Listing 25

Activated and Deactivated events


Single WPF application consists of loads of UI screens, which means it has many windows each
represented by XAML file. When the application loads, it first calls the Run method that decides which
Window to load first and then that window becomes the foreground window and other Windows
becomes the background window. By default, MainWindow.XAML is the one that gets called first. Which
makes it a foreground Window and it fires the Activated event. When the MainWindow becomes a
background Window, the Deactivated event is fired.

The code listed in Listing 26 defines the Startup event handler in XAML.
<Application x:Class="AppModelSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup"
Activated="Application_Activated" Deactivated="Application_Deactivated"/>

Listing 26

The definition of Application_Startup event handler is listed in Listing 27.


private void Application_Activated(object sender, EventArgs e)
{

52 @ C# Corner
}

private void Application_Deactivated(object sender, EventArgs e)


{

}
Listing 27

Following code displays MessageBox for Activated and Deactivated events.

private void Application_Activated(object sender, EventArgs e)


{
MessageBox.Show("Activated event fired.");
}

private void Application_Deactivated(object sender, EventArgs e)


{
MessageBox.Show("Deactivated event fired.");
}

Listing 28

SessionEnding-event
When a user logs off or shuts down the application, the window’s SessionEnding-event gets fired.
SessionEnding event is not raised in a console application or a XAML browser application (XBAP).

The code listed in Listing 29 defines the SessionEnding event handler in XAML.
<Application x:Class="AppModelSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
SessionEnding="Application_SessionEnding"/>

Listing 29

The definition of Application_SessionEnding event handler is listed in Listing 30.

public partial class App : Application


{
private void Application_SessionEnding(object sender,
SessionEndingCancelEventArgs e)
{
}
}
Listing 30

We can utilize this event with some creative ideas, for example in The Microsoft word, if you try to close
a document without saving then it shows a pop-up which asks you to save your data before closing a
file. Following code in Listing 31 displays a message box with yes and no buttons when the
SessionEnding event is raised. If the user selects No, the application cancels the SessionEnding.

53 @ C# Corner
private void Application_SessionEnding(object sender,
SessionEndingCancelEventArgs e)
{
string msg = string.Format("{0}. Do you want to close this session?",
e.ReasonSessionEnding);
MessageBoxResult result = MessageBox.Show(msg, "Session Ending Event
Fired.", MessageBoxButton.YesNo);

if (result == MessageBoxResult.No)
{
e.Cancel = true;
}
}
Listing 31

Exit-event
Exit-event occurs just before the applications shut down. This the best place to close tasks and release
resources which are no longer necessary. For example, you can use this event to uninitialized data
members that were initialized on application startup events.

The code listed in Listing 32 defines the Exit event handler in XAML.
<Application x:Class="AppModelSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Exit="Application_Exit"/>
Listing 32

The event-handler for an Application_Exit event handler is listed in Listing 33.

public partial class App : Application


{
private void Application_Exit(object sender, ExitEventArgs e)
{

}
}
Listing 33

DispatchUnhandledException-event
By default, a WPF application catches unhandled exceptions and notifies the users by using a dialog box
or automatically shutting down the application. However, it is always a good practice to avoid forceful
closing of the application. And this can be achieved by handling the exception. To do so, you must
implement DispatchUnhandledException.

The code listed in Listing 34 defines the DispatcherUnhandledException-event in XAML.

54 @ C# Corner
<Application x:Class="AppModelSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
DispatcherUnhandledException="Application_DispatcherUnhandledException"/>

Listing 34

The definition of DispatcherUnhandledException-event handler is listed in Listing 35.


public partial class App : Application
{
private void Application_DispatcherUnhandledException(object sender,
System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{

}
}
Listing 35

Following code in Listing 36 shows where to handle an exception. We are showing MessageBox if there
is an exception occurred in your app. In this example it is an arithmetic exception: divide by zero.
private void Application_DispatcherUnhandledException(object sender,
System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
// Do something about the exception
MessageBox.Show("Exception occured while dividing by zero!");
e.Handled = true;
}
Listing 36

Usually, you will get the following dialog-box from your application if there is an exception.

Figure 7

The figure shows the MessageBox, whenever the application throws an exception which is not handled.
We will learn about MessageBox in more detail in chapter 4.2

55 @ C# Corner
Figure 8

Window Loaded & Unloaded events


Loaded event is fired whenever the window is rendered i.e. finish loading all the UI elements on a
screen, this event can be used to set external attributes of UI controls. Whereas Unloaded event is fired
when control has been uninitialized from a visual tree. This event can be used to release window specific
resources.

Following code shows how we can set Loaded and Unloaded events from XAML.
<Window x:Class="HelloWPFSample2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample2"
Loaded="Window_Loaded"
Unloaded="Window_Unloaded"
Title="MainWindow" Height="450" Width="800">

Listing 37

Listing 38 shows how these events are handled in code-behind.


private void Window_Loaded(object sender, RoutedEventArgs e)

{
//initialize window specific resources here.
}

private void Window_Unloaded(object sender, RoutedEventArgs e)


{
//release window specific resources here.
}
Listing 38

Other Events
LoadCompleted, Navigated, Navigating, NavigationFailed, NavigationProgress, NavigationStopped, and
FragementNavigation are some events available in the Application class. These events are useful in WPF

56 @ C# Corner
Browser applications that require and use navigation functionality. You will not need these events in a
typical Windows client application. We will be discussing these events in our following chapters.

Application Data Files


Most of the applications need to work with data in the form of images, text, XML files, videos or
audio etc. These files are called application data files. Application data files are divided into 3
major categories.

● Resource Files: Resource files are data files that are compiled into assemblies including
an executable or a library. It generally contains styles, constant values.

● Content Files: Content files are standalone data files that have an explicit association
with an assembly such as an image.

● Site of Origin Files: Site of origin files are standalone data files that have no association
with WPF assemblies. An assembly has no idea about the site of origin files.

Loading Resource Files


Application.GetResourceStream method loads a resource data file that is located at a given
URI and returns a resource stream. The code snippet in Listing 39, reads a resource file from the
root folder of the application and loads information in a StreamResourceInfo object.
Uri uri = new Uri("/ResourceFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetResourceStream(uri);

Listing 39

Loading Content Files


Application.GetContentStream method loads a content data file that is located at a given URI
and returns a resource stream. The code snippet in Listing 40, reads a content file from the root
folder of the application and loads information in a StreamResourceInfo object.
Uri uri = new Uri("/ContentFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetContentStream(uri);

Listing 40

Loading Set of Origin Files


Application.GetRemoteStream method loads a site of the origin data file that is located at a
given URI and returns a resource stream. The code snippet in Listing 41, loads a site of the
origin data file from the root folder of the application and loads information in a
StreamResourceInfo object.

57 @ C# Corner
Uri uri = new Uri("/SOOFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetRemoteStream(uri);

Listing 41

Show multiple Windows at startup in WPF


Sometimes we may come across a requirement, where we need to start an application with
multiple windows. Listing 42 shows App.xaml where the StartupUri is set to MainWindow.xaml.
That means, when your application runs, MainWindow.xaml is the first Window to be shown.
<Application x:Class="WPFSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>

</Application.Resources>
</Application>

Listing 42

Now let’s say, you need show one more window, Let’s call it SecondWindow.xaml. You have
both of these windows to be shown when the application starts.

This can be achieved by calling SecondWindow on the application startup event. We need to
add Startup="App_Startup" to App.xaml.
<Application x:Class="WPFSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Startup="App_Startup">
<Application.Resources>

</Application.Resources>
</Application>
Listing 43

The code snippet in Listing 44 shows an event-handler for App_Startup event. Here we can
create an instance of SecondWindow, then set its position by using Top and Left properties and
call its Show method to make it appear. Even though 2 Windows are shown at a time, Windows
specified in StartupURI gets activated by default.
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
SecondWindow mainWindow = new SecondWindow();
mainWindow.Top = 100;
mainWindow.Left = 400;
mainWindow.Show();

58 @ C# Corner
}
}

Listing 44

Now if you run the application, you will see two Windows. See Figure 9

Figure 9

Using the same approach, you can show as many windows you would like on the application
startup event.

Adding a Splash Screen to a WPF Application


In traditional Windows client applications, it is often required to show a company image or
copyright information before an actual application starts. This image is called a splash screen.
One more use of a splash screen is, to show the user some helpful information while your
application is fetching its initial required data.

It is very easy to add a splash screen to a WPF application. Just follow these simple steps.

Step 1. Add an Image to Project

First, you need to find an image that you would like to use as a splash screen. Once you have
the image, add it to your project by right-clicking on the project name and then select Add
Existing Item menu. Browse the file and add it to the project.

Step 2. Set Build Action

Now Right-click on the Image name and select Properties menu item. On the Properties
window, you will see Build Action property. By default, “None” is selected as Build Action in the
dropdown as you can see below. See Figure 10.

59 @ C# Corner
Figure 10

Now you need to select the SplashScreen option from the drop-down. See Figure 9.

Step 2. Build and Run

That’s it. Now when you build and run your project, you will see a splash screen appear before
the application.

Getting Command Line Arguments


To get command-line arguments of a WPF application, you need to check command-line
arguments on Application_Startup event handler.

The following code snippet shows the Application Startup event handler. As you can see from
this code, the second parameter of the Startup method is StartupEventArgs. The Args property
of StartupEventArgs returns an array of strings that are the command line arguments passed to
the application.
private void Application_Startup(object sender, StartupEventArgs e)
{
// CommandLine Arguments found?
if (e.Args.Length > 0)
{
// Loop through all command-line arguments
// which is an array of strings
foreach (string arg in e.Args)

60 @ C# Corner
{
MessageBox.Show("Arg =" + arg);
}
}
}

Listing 45

Summary
In this chapter, we learned about the application model of a WPF application. And we covered
the startup events and how to get information about a WPF app.

61 @ C# Corner
Chapter 3: XAML Language
This chapter discusses the Extensible Application Markup Language (XAML). It is a scripting language
used to create user interfaces for Windows. XAML was introduced as a part of Microsoft .NET
Framework 3.5. Officially speaking, XAML is a new descriptive programming language developed by
Microsoft to write user interfaces for next-generation managed applications.

XAML is used to build user interfaces for Windows and Mobile applications that use Windows
Presentation Foundation (WPF) and Windows Runtime.

This chapter is an introduction to the XAML language. In this chapter, we will learn how to define XAML
elements, create controls and build screens using XAML Controls. By the end of this chapter, you will be
able to create user interfaces using XAML.

Purpose of XAML
The purpose of XAML is simple, to create user-interfaces using a markup language that looks like XML.
Most of the time, you will be using a designer to create your XAML but you’re free to directly build a UI
by coding manually.

A typical user interface developed for Windows has a window or page as a parent container with one or
more child containers plus other UI controls. Figure 1 shows a window with its child controls which are
two Radio Button controls, a Button control, a TextBox control and one TextBlock control.

Figure 1

XAML allows us to represent the parent containers and child controls using markup script elements.
Each UI control is represented by a XAML element. In Chapter 1, we have seen how we build user
interfaces at design-time and run-time. XAML gives us this flexibility to build user interfaces at both
design-time as well as run-time.

62 @ C# Corner
Hello XAML
XAML uses the XML format for its UI elements and their attributes. Each element in XAML represents an
object which is an instance of a type (class, enumeration etc). The scope of a type is defined as a
namespace where a class is physically present. It could be present in an assembly (DLL) of the .NET
library.

Similar to XML, a XAML element syntax always starts with an opening angle bracket (<) and ends with a
closing angle bracket (>). Each element has a start tag and an end tag. For example, a Button object is
represented by the <Button> object element. The code snippet in Listing 1 represents a Button object
element.

<Button></Button>

Listing 1

Alternatively, you can use a self-closing format to close the bracket. The code snippet in Listing 2 is
equivalent to Listing 1.

<Button />

Listing 2

The TextBlock control of XAML is used to display text. The code snippet in Listing 3 creates a TextBlock
control with its content “Hello XAML”.

<TextBlock>Hello XAML</TextBlock>

Listing 3

Alternatively, you can even use the Text attribute of TextBlock to specify the text to be displayed. Mostly
we are going to use Text property.
<TextBlock Text="Hello XAML" />

Listing 4

The attributes of these UI elements represent the properties of those elements. The code snippet in
Listing 5 sets width, height, foreground and some font-related properties of a TextBlock.

<TextBlock x:Name="OrangeText"
FontWeight="Bold"
FontSize="15"
FontFamily="Verdana"
Foreground="Orange"
Height="50"
Text="Hello XAML"
Width="100" />

63 @ C# Corner
Listing 5

The output looks as in Figure 1.

Figure 1

The Root Elements


Each XAML document must have a root element. The root element usually works like a container, all the
namespaces are defined inside a root element plus it also defines the basic properties of a window such
as height and width etc. Three most common root elements are <Windows />, <Page />, and
<UserControl >. The <ResourceDirectory /> and <Application /> are other two root elements that can be
used in a XAML file.

The Window element represents a Window container. The code snippet in Listing 6 shows a Window
element with its Height, Width, Title and Name attributes. The x:Name attribute of an element
represents the ID of an element used to access that element in the code-behind and XAML both. The
code snippet also sets xmlns and xmlns:x attributes that represent the namespaces used in the code.
The x represents the name of a namespace, which is used to access any class within that namespace.
Where the x:Class attribute represents the code-behind class name.

<Window x:Class="HelloXAML.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
</Window>

Listing 6

The Page element represents a page container. The code snippet in Listing 7 shows a page container.
The code also sets the FlowDirection attribute that represents the flow direct of the contents of the
page.

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WPFApp.Page1"
x:Name="Page"
WindowTitle="Page"
FlowDirection="LeftToRight"

64 @ C# Corner
Width="640" Height="480"
WindowWidth="640" WindowHeight="480">
</Page>
Listing 7

The UserControl element represents a user control container. The code snippet in Listing 8 shows how a
user control container looks like.

<UserControl x:Class="HelloXAML.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
</UserControl>

Listing 8

Namespaces
The code snippet in Listing 9 has two attributes as a part of the root element. Both xmlns and xmlns:x
are used to define namespaces which need to be loaded in this window.

Here x is the alias given to a namespace, you can change it to any word or letter which makes sense to
your application. For example, if I have a Styles namespace I would call xmlns:styles rather than x.

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
…… >
</Window>

Listing 9

The xmlns attribute indicates the default XAML namespace, So any object of that namespace can be
directly used within a window without a prefix. The xmlns:x attribute indicates an additional XAML
namespace, which maps the XAML language namespace.
http://schemas.microsoft.com/winfx/2006/xaml.

Additionally, the prefix can be used for different purposes than just using it with the namespace. Here
we have x as a prefix and some common prefix syntaxes that are used in XAML are as follows.

● x:Key: Sets a unique key for each resource in a ResourceDictionary.


● x:Class: Class name provides code-behind for a XAML page.
● x:Name: Unique run-time object name of an instance that exists in run-time code after an object
element is processed.
● x:Static: Enables a reference that returns a static value that is not otherwise a XAML-compatible
property.

65 @ C# Corner
● x:Type: Constructs a Type reference based on a type name.

We will see these directives in action in the later parts of this chapter.

XAML Markup and Code-Behind


Since XAML is a markup language it may not be an ideal choice for writing lengthy code in a single file.
XAML provides an option to associate a XAML file with a code file such as C# or VB.NET. The code file (.cs
or .vb) can host all the backend code and presentation’s logic while the XAML file (.xaml) presents the
user interface (UI) screen. The code file associated with a XAML file is also known as code-behind.

We have seen in chapter 1, how one can build a UI at design-time by manually updating a XAML file or
can use code-behind file to build UI at run-time. Highlighted part in Figure 2 shows that
MainWindow.xaml is your UI screen, where we describe UI elements with various attributes and
MainWindow.xaml.cs is the code-behind file of a UI screen, where we can code in C# or VB.

Figure 2
Inline Code

You can also write your C# code in the XAML file itself is called inline coding. The x:Code directive is used
to write inline code in XAML. The code that is defined inline can interact with the XAML on the same
page.

The code listed in Listing 10 demonstrates the use of inline coding using x:Code. The code must be
surrounded by <CDATA[...]]> to escape the contents for XML, so that a XAML processor (interpreting
either the XAML schema or the WPF schema) will not try to interpret the contents literally as XML.

<Grid>
<TextBlock x:Name="OrangeText"
FontWeight="Bold"
FontSize="15"
FontFamily="Verdana"
Foreground="Orange"
Height="50"
Text="Hello XAML"
Width="100" />

<x:Code>

66 @ C# Corner
<![CDATA[
]]> // Put code here
</x:Code>

</Grid>
Listing 10

Note: We highly recommend not to use inline coding. It defeats the purpose of code maintainability.

Elements and Attributes


A type in WPF or Windows RT is represented by a XAML element. The <Page> and <Button> elements
represent a page and a button control respectively. The XAML Button element listed in Listing 11
represents a button control.

<Button />

Listing 11

Each of these elements such as <Page> or <Button> have attributes that can be set within the element
itself. An attribute of an element represents a property of the type. For example, a Button has Height,
Width, Background and Foreground properties that represent the height, width, foreground color and
background color of the button respectively. The Content property of the Button represents the text of
button control. The x:Name property represents the unique ID of a control that may be used to access a
control in the code behind.

The code snippet in Listing 12 sets the ID, height, width, background color, foreground color, font name
and size and content of button control.

<Button x:Name="ClickButton"
Background="Orange"
Content="Click Me"
FontFamily="Georgia"
FontSize="20"
FontWeight="Bold"
Foreground="Blue"
Height="50"
Width="200" />

Listing 12

Figure 3 is the result of Listing 12. As you can see, the button has a blue foreground and orange
background, with the size specified in the code.

67 @ C# Corner
Figure 3

Content Property
Each XAML object element is capable of displaying various content types. XAML provides a special
property called Content that is used to display the content of the element depending on the element’s
capabilities. For example, a Content property of a Button can either be a set to a string or an object or a
UIElement, or a container. However, the Content property of a ListBox is set using the Items property.

Note: Some XAML object elements may not have the Content property available directly. It must be set
through a property.

The code snippet in Listing 13 creates a Button control and sets its Content property to a string “Hello
XAML”.

<Button x:Name="ButtonContent"
Content="I am Content"
Height="50"
Width="200" />

Listing 13

Listing 14 is an alternative way to set the Content property of a Button.

<Button x:Name="ButtonContent"
Height="50"
Width="200" >
I am Content
</Button>
Listing 14

The output of Listing 13 looks like Figure 4.

Figure 4

68 @ C# Corner
A Button element can display other child elements as its content. The code listed in Listing 15 sets a
Rectangle element as the content of the Button.

<Button x:Name="ButtonOuter"
Height="80"
Width="200">
<Rectangle x:Name="RectangleInner"
Fill="LightSalmon"
Height="40"
Width="100" />
</Button>

Listing 15

Figure 5 illustrates how the output of Listing 15 would look.

Figure 5

Content property can also be a container or a parent element to host child elements. The code snippet
in Listing 16 sets a StackPanel container with 5 child elements as the content of the Button.

<Button x:Name="ButtonOuter"
Height="150"
Width="400">
<StackPanel x:Name="StackPanelMain"
Background="DarkGray"
Height="100"
Orientation="Horizontal"
Width="360">
<Ellipse x:Name="EllipseRed"
Fill="Red"
Height="60"
Margin="5 0 0 0"
Width="60" />
<TextBlock x:Name="TextBlockFirst"
Text="Red Circle"
TextAlignment="Center" >
<Run Text=" Red Circle"/>
</TextBlock>
<TextBlock x:Name="TextBlockBlankSpace"
TextAlignment="Center">

69 @ C# Corner
<Run Text=" "/>
</TextBlock>
<Rectangle x:Name="RectangleGreen"
Fill="Green"
Height="60"
Width="120" />
<TextBlock x:Name="TextBlockLast"
TextAlignment="Center">
<Run Text=" Green Rectangle"/>
</TextBlock>
</StackPanel>
</Button>

Listing 16

Figure 6 illustrates the output of Listing 16.

Figure 6

Finally, let’s combine all of these contents into one file. Listing 17 shows final MainWindow.xaml file
<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="500">
<Grid Name="RootLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<Button x:Name="ButtonFirst"
Content="I am Content"
Height="50"
Width="200" />
<Button x:Name="ButtonSecond"
Height="80"
Width="200"

70 @ C# Corner
Grid.Row="1">
<Rectangle x:Name="RectangleInner"
Fill="LightSalmon"
Height="40"
Width="100" />
</Button>

<Button x:Name="ButtonThird"
Height="150"
Width="400"
Grid.Row="2">
<StackPanel x:Name="StackPanelMain"
Background="DarkGray"
Height="100"
Orientation="Horizontal"
Width="360">
<Ellipse x:Name="EllipseRed"
Fill="Red"
Height="60"
Margin="5 0 0 0"
Width="60" />
<TextBlock x:Name="TextBlockFirst"
Text="Red Circle"
TextAlignment="Center" >
<Run Text=" Red Circle"/>
</TextBlock>
<TextBlock x:Name="TextBlockBlankSpace"
TextAlignment="Center">
<Run Text=" "/>
</TextBlock>
<Rectangle x:Name="RectangleGreen"
Fill="Green"
Height="60"
Width="120" />
<TextBlock x:Name="TextBlockLast"
TextAlignment="Center">
<Run Text=" Green Rectangle"/>
</TextBlock>
</StackPanel>
</Button>
</Grid>

</Window>
Listing 17
Figure 7 shows the output of Listing 17.

71 @ C# Corner
Figure 7
You can pretty much host any user interfaces as the content of a XAML element. Hence proving its feature
of flexibility.

Building UI at Run-time
The code snippet in Listing 18 uses code-behind to dynamically create the same UI as Figure 7.
// Button with string content
Button helloButton = new Button();
helloButton.Content = "I am Content";
helloButton.Height = 50;
helloButton.Width = 200;

// Button with a UIElement


Button buttonWithRectangle = new Button();
buttonWithRectangle.Height = 80;
buttonWithRectangle.Width = 200;

// Create a Rectangle
Rectangle LightSalmon = new Rectangle();
LightSalmon.Height = 40;
LightSalmon.Width = 100;
LightSalmon.Fill = Brushes.LightSalmon;
// Set Rectangle as Button.Content
buttonWithRectangle.Content = LightSalmon;

// Button with a Container, StackPanel


Button buttonWithStackPanel = new Button();
buttonWithStackPanel.Height = 150;

72 @ C# Corner
buttonWithStackPanel.Width = 400;
// Create a StackPanel and set its orientation to horizontal
StackPanel stackPanel = new StackPanel();
stackPanel.Height = 100;
stackPanel.Width = 360;

stackPanel.Orientation = Orientation.Horizontal;
// Create an Ellipse
Ellipse redEllipse = new Ellipse();
redEllipse.Height = 60;
redEllipse.Width = 60;
redEllipse.Fill = Brushes.Red;
// Add to StackPanel
stackPanel.Children.Add(redEllipse);

// Create a TextBlock
TextBlock textBlock1 = new TextBlock();
textBlock1.TextAlignment = TextAlignment.Left;
textBlock1.Text = "Red Circle";
// Add to StackPanel
stackPanel.Children.Add(textBlock1);

// Create a TextBlock
TextBlock space = new TextBlock();
space.TextAlignment = TextAlignment.Center;
space.Text = " ";
// Add to StackPanel
stackPanel.Children.Add(space);

// Create a Rectangle
Rectangle greenRectangle2 = new Rectangle();
greenRectangle2.Height = 60;
greenRectangle2.Width = 120;
greenRectangle2.Fill = Brushes.Green;
// Add to StackPanel
stackPanel.Children.Add(greenRectangle2);

// Create a TextBlock
TextBlock textBlock2 = new TextBlock();
textBlock2.TextAlignment = TextAlignment.Left;
textBlock2.Text = "Green Rectangle";
// Add to StackPanel
stackPanel.Children.Add(textBlock2);
// Set StackPanel as Button.Content
buttonWithStackPanel.Content = stackPanel;
// Add dynamic button controls to the Window
RootLayout.Children.Add(helloButton);
RootLayout.Children.Add(buttonWithRectangle);
RootLayout.Children.Add(buttonWithStackPanel);

Listing 18

73 @ C# Corner
Events
WPF controls support most commonly used events such as Click, GotFocus, LostFocus, KeyUp, KeyDown,
MouseEnter, MouseLeave, MouseLeftButtonDown, MouseRightButtonDown and MouseMove etc. An event
is specified in XAML and it is handled in code-behind or ViewModel class. An event handler executed when
the event is raised. We will learn about ViewModels in the coming chapters.

Let’s understand events with an example. Create a new WPF Application and add a Button and a TextBlock
control to the Window. Position and format the control the way you like. My final code is listed in Listing 19.

<Grid Name="RootLayout">
<Button x:Name="HelloButton"
Content="Click Me"
FontSize="16"
Height="40"
HorizontalAlignment="Left"
Margin="5"
VerticalAlignment="Top"
Width="150" />
<TextBlock x:Name="HelloTextBlock"
Background="LightGray"
FontSize="30"
Foreground="Orange"
Height="100"
HorizontalAlignment="Left"
Margin="5 50 0 0"
VerticalAlignment="Top"
Width="400" />
</Grid>

Listing 19

Let’s add Button’s Click event-handler. Inside a handler let’s add a logic to add text to the TextBlock. The
handler will be triggered on Button’s Click event. As shown in Listing 20, add the click event:
HelloButton_Click in XAML.

<Button x:Name="HelloButton"
Content="Click Me"
Click="HelloButton_Click"
FontSize="16"
Height="40"
HorizontalAlignment="Left"
Margin="5"
VerticalAlignment="Top"
Width="150" />

Listing 20

Now go to the code-behind and add the following code listed in Listing 21. Here we are updating the
Text of the TextBlock to “HelloButton is clicked.”.

74 @ C# Corner
void HelloButton_Click(object sender, RoutedEventArgs e)
{
HelloTextBlock.Text = "HelloButton is clicked.";
}
Listing 21

Build and run the application and click on the button, the output will change to Figure 8.

Figure 8

Container, Parent and Child Controls


XAML uses the tree presentation to represent its parent-child control’s relationship. Figure 9 is a typical
screen with a parent container, a child container and a few child controls.

75 @ C# Corner
Figure 9
The tree representation of Figure 9 is displayed in Figure 10.

Figure 10
As you can see from Figure 10, the Window root element has a child container, Grid. The Grid container
hosts a StackPanel, Button, TextBlock and TextBox. The StackPanel is also being used as a container for
two Radio Button controls.

The XAML presentation of Figure 10 is listed in Listing 22.

<Window x:Class="WPF_Hierarchy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:WPF_Hierarchy"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="780">
<Grid Name="RootLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel x:Name="StackPanelRadioButtons"
Background="#FFF1EFEF"
Height="43"
HorizontalAlignment="Left"
Margin="5"
Orientation="Horizontal"

76 @ C# Corner
VerticalAlignment="Top"
Width="462" >
<RadioButton x:Name="RadioButtonRedBackground"
Content="Red Background"
Margin="5"
Width="184" />
<RadioButton x:Name="RadioButtonGreenBackground"
Content="Green Background"
Margin="5"
Width="207"/>
</StackPanel>

<Button x:Name="ButtonLoadText"
Content="Load Text"
Height="26"
HorizontalAlignment="Center"
Margin="0 5 5 5"
VerticalAlignment="Top"
Width="131"
Grid.Row="1"/>

<TextBlock x:Name="TextBlockRedBackground"
Background="#FFEB4A4A"
Foreground="#FFF5F3F3"
Height="85"
HorizontalAlignment="Left"
Margin="5"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="462"
Grid.Row="2">
<Run Background="#FFEE3A3A"
Text="TextBlock"/>
</TextBlock>
<TextBox x:Name="LoadTextBox"
Height="29"
HorizontalAlignment="Left"
Text="TextBox"
TextWrapping="Wrap"
Margin="5"
VerticalAlignment="Top"
Width="317"
Grid.Row="1"/>
</Grid>

</Window>

Listing 22

Shapes
Note: we are going to cover shapes in more detail in the Graphics chapter. But to give you an idea of
what shapes are, let's see one simple example.

77 @ C# Corner
In XAML, each graphics shape, such as a line or a rectangle, is represented by an element object. For
example, the <Line /> element represents a line and the <Rectangle/> element represents a
rectangle shape. These elements have attributes that represent their properties. In.NET, each XAML
element object is associated with a type. For example, the Class Line and Class Rectangle represent a
line and a rectangle shape respectively.

The code snippet in Listing 23 creates a line and sets its stroke and stroke thickness properties. X1, Y1 is
the starting point and X2, Y2 is the endpoint of the line.

<Line x:Name="LineShape"
Stroke="#000fff"
StrokeThickness="2"
X1="100"
Y1="100"
X2="300"
Y2="100"/>

Listing 23

The code snippet in Listing 24 creates a line, a rectangle, an ellipse, a polygon and a polyline shape using
XAML elements.

Before we begin with an example, let me tell you in brief what canvas control is. We will surely cover
canvas control in more detail in an upcoming chapter on layouts.

For now, let me give a brief, A Canvas panel is a parent element which is used to position child elements
by using coordinates that are relative to the canvas area. Canvas has 4 attached properties that specify
the position of the child element.
Left, Right, Top, Bottom.

<Canvas x:Name="LayoutRoot" Background="White">


<!-- Create a line in XAML -->

<!-- Create a Line in XAML -->


<Line x:Name="LineShape"
Stroke="Red"
StrokeThickness="2"
X1="0"
Y1="0"
X2="250"
Y2="0"
Canvas.Left="10"
Canvas.Top="20"/>

<!-- Create a Rectangle in XAML -->


<Rectangle x:Name="RectangleShape"
Fill="Blue"
Height="100"
Stroke="Black"
StrokeThickness="2"
Width="200"

78 @ C# Corner
Canvas.Left="10"
Canvas.Top="40"/>

<!-- Create an Ellipse in XAML -->


<Ellipse x:Name="EllipseShape"
Fill="Yellow"
Height="100"
Stroke="Black"
StrokeThickness="2"
Width="200"
Canvas.Left="10"
Canvas.Top="150"/>

<!-- Create a polygon in XAML -->


<Polygon x:Name="PolygonShape"
Fill="LightGreen"
Points="50, 100 200, 100 200, 200 300, 30"
Stroke="Black"
StrokeThickness="4"
Canvas.Left="200"
Canvas.Top="0"/>

<!-- Create a polyline in XAML-->


<Polyline x:Name="PolylineShape"
Points="10,100 100,200 200,30 250,200 200,150"
Stroke="Black"
StrokeThickness="4"
Canvas.Left="250"
Canvas.Top="100"/>

</Canvas>

Listing 24

The output generated by Listing 24 looks like Figure 11 with a line, a rectangle, an ellipse, a polygon and
a polyline.

79 @ C# Corner
Figure 11

Brushes
Brushes are responsible for drawing and painting on a surface. In XAML, each brush is represented by an
element object. For example, the SolidColorBrush element represents a solid brush. There are five
brushes available in XAML: Solid Brush, Linear Gradient Brush, Radial Gradient Brush, Visual Brush and
Image Brush.

The code snippet in Listing 25 draws various rectangles using these brushes.

<Canvas x:Name="LayoutRoot"
Background="White">

<!-- SolidColorBrush-->
<Rectangle x:Name="RectangleFirst"
Height="100"
Stroke="Black"
StrokeThickness="4"
Width="200"
Canvas.Left="10"
Canvas.Top="10">
<Rectangle.Fill>
<SolidColorBrush Color="Blue" />
</Rectangle.Fill>
</Rectangle>

<!-- ImageBrush-->
<Rectangle x:Name="RectangleSecond"
Height="100"
Stroke="Black"
StrokeThickness="4"
Width="200"
Canvas.Left="230"

80 @ C# Corner
Canvas.Top="10">
<Rectangle.Fill>
<ImageBrush ImageSource="dock.jpg" />
</Rectangle.Fill>
</Rectangle>

<!-- LinearGradientBrush-->
<Rectangle x:Name="RectangleThird"
Height="100"
Width="200"
Canvas.Left="10"
Canvas.Top="120" >
<Rectangle.Fill>
<LinearGradientBrush
StartPoint="0,0"
EndPoint="1,1" >
<GradientStop
Color="Blue"
Offset="0" />
<GradientStop
Color="Red"
Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>

<!-- RadialGradientBrush -->


<Rectangle x:Name="RectangleFourth"
Height="100"
Stroke="Black"
Width="200"
Canvas.Left="230"
Canvas.Top="120">
<Rectangle.Fill>
<RadialGradientBrush
GradientOrigin="0.5,0.5"
Center="0.5,0.5" >
<RadialGradientBrush.GradientStops>
<GradientStop
Color="Blue"
Offset="0" />
<GradientStop
Color="Red"
Offset="1.0" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>

Listing 25

The output generated by Listing 25 looks like Figure 14 that has four rectangles drawn using various
brushes.

81 @ C# Corner
Figure 12

Special Characters in XAML


XAML uses the Unicode UTF-8 file format for special characters. However, there is a set of commonly-
used special characters that are handled differently. These special characters follow the World Wide
Web Consortium (W3C) XML standard for encoding. Here is a list of these special characters.

● < = andlt;
● > = andgt;
● and = andamp;
● “ = andqout;

The code snippet in Listing 26 shows how to use these characters.

<TextBlock>
andlt; <!-- Less than symbol -->
andgt; <!-- Greater than symbol -->
andamp; <!-- Ampersand symbol -->
andquot; <!-- Double quote symbol -->
</TextBlock>
Listing 26

Read and Write XAML in Code


UI in WPF is mostly built at design-time but there may be a time when you may want to create XAML
dynamically. The XamlWriter and the XamlReader classes are your go-to classes to create and read
XAML in code. The XamlWriter and the XamlReader classes are defined in the System.Windows.Markup
namespace and must be imported to use these classes.

82 @ C# Corner
using System.Windows.Markup;

The XamlWriter.Save method takes an object as an input and creates a string containing the valid XAML.
The code snippet in Listing 27 creates a Button control using code and saves it in a string using the
XamlWriter.Save method.

// Create a Dynamic Button.


Button helloButton = new Button();
helloButton.Height = 50;
helloButton.Width = 100;
helloButton.Background = Brushes.AliceBlue;
helloButton.Content = "Click Me";

// Save the Button to a string.


string dynamicXAML = XamlWriter.Save(helloButton);

Listing 27

The XamlReader.Load method reads the XAML input in the specified Stream and returns an object that
is the root of the corresponding object tree. The code snippet in Listing 28 creates an XmlReader from a
XAML and then creates a Button control using the XamlReader.Load method.
// Load the button
XmlReader xmlReader = XmlReader.Create(new StringReader(dynamicXAML));
Button readerLoadButton = (Button)XamlReader.Load(xmlReader);

Listing 28

Styling Controls
Again, we will learn styling in more detail in a separate chapter on Styles. For now, let's see a basic
definition of styles.

XAML is the universal language for Windows Presentation Foundation (WPF), XAMARIN, WINUI, and
Windows Store apps. In this chapter, we will learn how to create and use styles on UI elements using
XAML. Once you learn to do this in XAML, you can use the same approach in your WPF, Silverlight, and
Windows Store apps.

Styling is a way to group similar properties in a single style element, then this style could apply to
multiple XAML elements.

Let's have a look at the XAML code in Listing 29. In this example, UI will have 3 Buttons, 1 TextBlock and
1 TextBox.

<Grid Name="RootLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

83 @ C# Corner
<TextBox x:Name="TextBoxBrowse"
Height="30"
HorizontalAlignment="Left"
Margin="5"
Width="390"
VerticalAlignment="Top" />

<Button x:Name="ButtonBrowse"
Background="DarkGreen"
BorderBrush="Black"
Content="Browse"
FontFamily="Verdana"
FontSize="14"
FontWeight="Normal"
Foreground="White"
HorizontalAlignment="Right"
Height="30"
Margin="5"
Width="120"
VerticalAlignment="Top" />

<TextBlock x:Name="TextBlockDetails"
Background="Gray"
FontFamily="Georgia"
FontSize="12"
Foreground="Orange"
Height="100"
Margin="5"
Grid.Row="1"/>

<Button x:Name="ButtonSpellCheck"
Background="DarkGreen"
BorderBrush="Black"
Content="Spell Check"
FontFamily="Verdana"
FontSize="14"
FontWeight="Normal"
Foreground="White"
Height="30"
HorizontalAlignment="Right"
Margin="5"
VerticalAlignment="Bottom"
Width="120"
Grid.Row="2"/>

<Button x:Name="ButtonSaveFile"
Background="DarkGreen"
BorderBrush="Black"
Content="Save File"
FontFamily="Verdana"
FontSize="14"
FontWeight="Normal"
Foreground="White"
HorizontalAlignment="Right"
Margin="0 0 150 5"
Height="30"
Width="120"

84 @ C# Corner
VerticalAlignment="Bottom"
Grid.Row="2"/>
</Grid>

Listing 29
The output of Listing 29 creates a window as shown in Figure 13. As you can see, all three buttons have
the same width, height, background, foreground, and fonts.

Figure 13

Here is the Button element code that sets Height, Width, Foreground, Background and Font properties.

<Button x:Name="ButtonBrowse"
Background="DarkGreen"
BorderBrush="Black"
Content="Browse"
FontFamily="Verdana"
FontSize="14"
FontWeight="Normal"
Foreground="White"
HorizontalAlignment="Right"
Height="30"
Margin="5"
Width="120"
VerticalAlignment="Top" />
Listing 30
All of the three buttons have the same values.

Use Case:

Now, imagine you have a complex application with many windows and pages and they have many
buttons with the same look and feel. Which means you will have to repeat the same XAML in every
window that has a Button. Later, after all those scrum meetings, your application is finished and now

85 @ C# Corner
your client wants to change green background color to red background color. You will have to go to each
window then find and replace the background color from green to red for each button.

Solution:

But there is a better way to do that. Remember some lessons from chapter 2, where we learned about
the resource. That can come handy now. You can create a resource style and use that for every Button
control. The next time that you need to change a property, all you need to do is change the value in the
resource, and the style will automatically be applied on all the buttons who are using that style.

The x:Key is the unique key identifier of the style. The TargetType is the element type on which style is
going to be applied such as a Button.

The code snippet in Listing 31 adds a Style to the Window Resources and within the Style, we use a
Setter to set the property type and their values. The code snippet sets Width, Height, FontFamily,
FontSize, FontWeight, Foreground, Background and BorderBrush properties.

<Window.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" TargetType="Button" >
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="120"/>
</Style>
</Window.Resources>

Listing 31

Note: If you do not specify the TargetType, you can explicitly specify it in the Setter as following:
<Setter Property="Button.Width" Value="120"/>

Listing 32

Once a Style is added to the resource dictionary, you can use it by using the Style property of a
FrameworkElement.

FrameworkElement: It extends the layout system by implementing some of the virtual methods defined
in UIElement. So you can extra properties such as Margin, MinWidth, MinHeight etc. We will cover this
topic in more detail in chapter 4.2.

The code snippet in Listing 33 sets the Style of a Button using the StaticResource Markup Extension.

86 @ C# Corner
<Button x:Name="ButtonBrowse"
Style="{StaticResource GreenButtonStyle}"
Content="Browse"
HorizontalAlignment="Right"
Margin="5"
VerticalAlignment="Top" />
Listing 33

Now we can replace code snippets from Listing 29 with the much cleaner and manageable code snippets
in Listing 34. If we need to change the background color of Buttons from green to red, all we have to do
is change the Background property in the resources.

<Grid Name="RootLayout">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="TextBoxBrowse"
Height="30"
HorizontalAlignment="Left"
Margin="5"
Width="390"
VerticalAlignment="Top" />

<Button x:Name="ButtonBrowse"
Style="{StaticResource GreenButtonStyle}"
Content="Browse"
HorizontalAlignment="Right"
Margin="5"
VerticalAlignment="Top" />

<TextBlock x:Name="TextBlockDetails"
Background="Gray"
FontFamily="Georgia" FontSize="12"
Foreground="Orange"
Height="100"
Margin="5"
Grid.Row="1"/>

<Button x:Name="ButtonSpellCheck"
Style="{StaticResource GreenButtonStyle}"
Content="Spell Check"
HorizontalAlignment="Right"
Margin="5"
VerticalAlignment="Bottom"
Grid.Row="2"/>

<Button x:Name="ButtonSaveFile"
Style="{StaticResource GreenButtonStyle}"
Content="Save File"
HorizontalAlignment="Right"
Margin="0 0 150 5"
VerticalAlignment="Bottom"
Grid.Row="2"/>

87 @ C# Corner
</Grid>
Listing 34

Style Element

In the previous example, we saw how to group multiple properties and use them as a single Style
element. However, Style functionality does not end here. Style can be used to group and could be
shared not only on properties but also on resources, and event handlers on any FrameworkElement or
FrameworkContentElement.

Styles are nothing but resources and can be used as any other resource. The scope of styles is similar to
any other resource. The resource lookup process first looks up for local styles and if not found, it
traverses to the parent element in the logical tree and so on. In the end, the resource lookup process
looks for styles in the application and themes.

A Style element in XAML represents a style. The typical definition of a Style element looks as in the
following:

<Style>
<Setter/>
<Setter/>
<Setter/>
</Style>
As you can see from the definition, a Style could have one or more Setter element/s. Each Setter
consists of a property and a value. The property is the name of the property and value is the actual value
to be assigned to that property.

Setters Property

The Setters property of Type represents a collection of Setter and EventSetter objects. Listing 35 uses
the Setters property and adds a Setter and EventSetter objects.

The code snippet in Listing 35 sets the Setters property of a Style by adding a few Setter elements and
one EventSetter element using XAML at design-time.

<Grid x:Name="GridMain">
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="200"/>
<EventSetter Event="Click" Handler="Button1_Click"/>
</Style>
</Grid.Resources>
<Button x:Name="ButtonClickMe"
Content="Click Me"/>
</Grid>
Listing 35

88 @ C# Corner
BasedOn Property

Styles support inheritance. That means we can create styles based on existing styles. When you inherit a
style from an existing style, settings from the parent style are available in the inherited style. To inherit a
style from another style, we set the BasedOn property to StaticResource Markup Extension.

The code snippet in Listing 36 creates a Style BackForeColorStyle that sets the Background and
Foreground properties of the control. Then we create a FontStyle style that sets font properties but is
inherited from the BackForeColorStyle. The last style of ButtonAllStyle is inherited from FontStyle. In the
end, we apply the Style on a button.

<Grid Name="RootLayout">
<Grid.Resources>
<Style x:Key="BackForeColorStyle">
<Setter Property="Control.Background" Value="Green"/>
<Setter Property="Control.Foreground" Value="White"/>
</Style>
<Style x:Key="FontStyle"
BasedOn="{StaticResource BackForeColorStyle}">
<Setter Property="Control.FontFamily" Value="Verdana"/>
<Setter Property="Control.FontSize" Value="14"/>
<Setter Property="Control.FontWeight" Value="Normal"/>
</Style>
<Style x:Key="ButtonAllStyle"
BasedOn="{StaticResource FontStyle}">
<Setter Property="Button.Width" Value="120"/>
<Setter Property="Button.Height" Value="30"/>
</Style>
</Grid.Resources>
<Button Name="ButtonClicklMe"
Style="{StaticResource ButtonAllStyle}"
Content="Click Me">
</Button>
</Grid>
Listing 36

Figure 14 is an output of Listing 36.

Figure 14

TargetType Property

89 @ C# Corner
The TargetType property can be used to get and set the type for which a style is intended. For example,
If you want to create a style for a TextBlock, you must set TargetType to TextBlock If there is a mismatch
between a control and its TargetType then you will get an error.

Figure 15, showing an error occurred when we tried to apply style on a Button where style’s TargetType
was a TextBlock.

Figure 15
Let's take a quick look at the code in Listing 37. This code creates a Style named GreenButtonStyle and
sets its Button properties. We have not specified TargetType so we need to use the UIElement name in
every setter. Example: Button.Width, Button.Height etc.

<Grid x:Name="GridMain">
<Grid.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" >
<Setter Property="Button.Background" Value="DarkGreen"/>
<Setter Property="Button.BorderBrush" Value="Black"/>
<Setter Property="Button.FontFamily" Value="Verdana"/>
<Setter Property="Button.FontSize" Value="14"/>
<Setter Property="Button.FontWeight" Value="Normal"/>
<Setter Property="Button.Foreground" Value="White"/>
<Setter Property="Button.Height" Value="30"/>
<Setter Property="Button.Width" Value="120"/>
</Style>
</Grid.Resources>
<Button x:Name="ButtonBrowse"
Style="{StaticResource GreenButtonStyle}"
Content="Browse"
HorizontalAlignment="Center"
Margin="5"
VerticalAlignment="Center" />
</Grid>
Listing 37

In Listing 38 where you may notice that we have set TargetType = "Button" and have removed Button
from all of the properties. Setting TargetType fixes that.

Note: this style can be applied to a Button element only.

90 @ C# Corner
<Window.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" TargetType="Button" >
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="120"/>
</Style>
</Window.Resources>
Listing 38

Triggers Property

Note: Again, Triggers is a vast topic, in this chapter, we are only going to learn some basics of triggers.
We are covering Triggers with their different types in much detail in our coming chapter.

Styles can have Triggers which are represented by a Trigger’s property. For example, the following code
snippet in Listing 39 adds a Trigger on a button, where if a Button is in a pressed state; it will change the
Foreground color of the button to Orange.

<Style.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property = "Foreground" Value="Orange"/>
</Trigger>
</Style.Triggers>
Listing 39

Listing 40 shows the complete code of implementing triggers within a style.

<Grid x:Name="GridMain" >


<Grid.Resources>
<!-- Green Button Style -->
<Style x:Key="GreenButtonStyle" TargetType="Button" >
<Setter Property="Background" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="120"/>
<Style.Triggers>

91 @ C# Corner
<Trigger Property="IsPressed" Value="true">
<Setter Property = "Foreground" Value="Orange"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Button x:Name="ButtonBrowse"
Style="{StaticResource GreenButtonStyle}"
Content="Browse"
HorizontalAlignment="Right"
Margin="0,14,26,0"
VerticalAlignment="Top" />
</Grid>
Listing 40

Following Figure 16 shows how the output of Listing 40 would look before applying the trigger, Trigger
here is pressing a button.

Figure 16

Figure 17 shows how it looks after applying a trigger.

Figure 17

92 @ C# Corner
Collection Elements
XAML provides a UI element that can host child collection items. XAML also provides support for .NET
collection types as data sources.

XAML Collections

A collection element is usually a parent control with its child collection elements. The child element is a
collection of items also known as ItemCollection, this ItemCollection implements IList<object>. For
example, a ListBox element is a collection of ListBoxItem elements. For example, ListBox, DataGrid
PieSeries, BarSeries, etc.

The code snippet in Listing 41 creates a ListBox with a few ListBoxItems.

<Grid x:Name="GridMain" >


<ListBox Name="ListBoxBeverages"
HorizontalAlignment="Left"
Height="200"
Margin="10,10,0,13"
VerticalAlignment="Top"
Width="194" >
<ListBoxItem Content="Coffee"/>
<ListBoxItem Content="Tea"/>
<ListBoxItem Content="Orange Juice"/>
<ListBoxItem Content="Milk"/>
<ListBoxItem Content="Iced Tea"/>
<ListBoxItem Content="Mango Shake"/>
</ListBox>
</Grid>
Listing 41

The preceding code in Listing 41 produces Figure 18.

93 @ C# Corner
Figure 18

Add Collection Items

In the previous section, we saw how to add items to a ListBox at design-time from XAML. We can add
items to a ListBox from the code-behind or ViewModel as well.

Let’s change our UI and add a TextBox and button control. Finally, your XAML would look like Listing 42.

<Grid x:Name="GridMain" >


<TextBox Name="TextBoxUserInput"
Height="23"
HorizontalAlignment="Left"
Margin="8,14,0,0"
VerticalAlignment="Top"
Width="127" />
<Button x:Name="button1"
Click="button1_Click"
Content="Add Item"
Height="23"
HorizontalAlignment="Left"
Margin="250,14,0,0"
Width="76"
VerticalAlignment="Top"/>

<ListBox Name="ListBoxBeverages"
HorizontalAlignment="Left"
Height="200"
Margin="10,10,0,13"
VerticalAlignment="Top"
Width="194" >
<ListBoxItem Content="Coffee"/>
<ListBoxItem Content="Tea"/>
<ListBoxItem Content="Orange Juice"/>
<ListBoxItem Content="Milk"/>
<ListBoxItem Content="Iced Tea"/>
<ListBoxItem Content="Mango Shake"/>
</ListBox>
</Grid>
Listing 42

The final UI looks as shown in Figure 19.

94 @ C# Corner
Figure 19

We can access collection items using the Items property. On a Button’s click event, we can add contents
of a TextBox to the ListBox by calling the ListBox.Items.Add method. The following code adds TextBox
contents to the ListBox items.

private void button1_Click(object sender, RoutedEventArgs e)


{
ListBoxBeverages.Items.Add(TextBoxUserInput.Text);
}

Listing 43

Now if you enter text into the TextBox and click the Add Item button, it will add the contents of the
TextBox to the ListBox

95 @ C# Corner
Figure 20

Delete Collection Items

We can either use the ListBox.Items.Remove or ListBox.Items.RemoveAt method to delete an item from
a collection of items in a ListBox. The RemoveAt method takes the index of the item in the collection.

Now, we need to modify our application and add a new button called Delete an Item. The XAML code
for this button looks as below.

<Button x:Name="ButtonDelete"
Content="Delete Item"
Click="DeleteButton_Click"
Height="23"
Margin="80,14,0,0"
VerticalAlignment="Top"
Width="76"/>
Listing 44

The Button click event handler is shown in Listing 45. On this button click, we find the index of the
selected item and call the ListBox.Items.RemoveAt method.

private void DeleteButton_Click(object sender, RoutedEventArgs e)


{
ListBoxBeverages.Items.RemoveAt
(ListBoxBeverages.Items.IndexOf(ListBoxBeverages.SelectedItem));
}

Listing 45

96 @ C# Corner
Figure 21 and 22 shows an output of Listing 42, 42 and 44.

Figure 21

Figure 22

Collection Types

97 @ C# Corner
XAML also allows developers to access .NET class library collection types from the scripting language.
The code snippet in Listing 46 creates an array of String types, a collection of strings. To use the Array
and String types, we must import the System namespace.

<Window x:Class="WPF_Hierarchy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:WPF_Hierarchy"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="780">
<Window.Resources>
<x:Array x:Key="AuthorList"
Type="{x:Type sys:String}">
<sys:String>Coffie</sys:String>
<sys:String>Tea</sys:String>
<sys:String>Orange Juice</sys:String>
<sys:String>Milk</sys:String>
<sys:String>Iced Tea</sys:String>
</x:Array>
</Window.Resources>
</Window>
Listing 46

If you wish to bind the ArrayList or any type of list to a ListBox in XAML, you can use the ItemSource
property. Shown in Listing 47.

<ListBox x:Name="ListBoxItems"
Margin="5"
ItemsSource="{StaticResource AuthorList}" />
Listing 47

Summary
This chapter is an introduction to the XAML language. We started this chapter by discussing various tools
available to write XAML code. After that, we discussed basic controls, elements, attributes, user
interfaces, and control events. After that, we discussed communication between controls followed by
shapes and brushes. We still need to discuss resources, styles, templates, skins, themes, audio, video
and much more. We will discuss these XAML syntaxes in the related chapters later in this book.

98 @ C# Corner
Chapter 4: Layouts
Proper layout and positioning play a vital role when it comes to making a UI interactive, high
performance and user-friendly. In this chapter, we will discuss the layout process in WPF. The chapter
begins with an understanding of the WPF layout process. Further along, will cover the basics of layout
and positioning such as size, margin, padding, and alignment of elements. Later in this chapter, we will
cover various panels and other parent controls available in WPF.

WPF Layout System – An Introduction


Take any UI framework, the first thing that grabs the attention are the layouts, every framework has its
own set of panels to arrange data and elements on the screen. Layouts make sure everything is
consistent concerning size, alignment, margin, position etc. WPF has a collection of rich UI Panels to take
care of these arrangements. The layout process in WPF includes the selection of a suitable parent
container, initial placement and positioning, setting margins, paddings, and alignments of parent and
child elements. Usually, a parent container is a Window, a UserControl or a Page depending on the type
of WPF application. Once a parent container is placed inside a Window, UserControl or Page, then they
become the host of the child container and other UI elements.

Figure 1 is an example of a typical Window with a title, a border, and minimize, maximize, close buttons.
The blue area is a parent container element that usually is a panel. (In this example it is a Grid). The pink
is a child of the blue parent and the green area is the child of the pink area. That makes blue Grid parent
of all other controls inside this window.

99 @ C# Corner
Figure 1

The sub-system that is responsible for the layout and positioning in WPF is called the Layout System.
The layout system is not only responsible for designing user interfaces at design-time but also manages
the rendering of elements at runtime. The layout system also manages the event processing of the
elements.

Control vs. Element


By now it must be clear what building UI at design-time and run-time is (We have covered this in chapter
1). WPF has two common ways to represent UI objects. Let’s take a Button, for example, you can
represent a button with <Button> tag in XAML or Button class in C#. The run-time representation of a UI
object in C# is often called as a control and the design-time representation of a UI object in XAML is
often called as an element.

Layout Slot and Layout Clip


In WPF, each element is defined within a rectangle shape that represents the boundaries of an element.
This rectangle is called the layout slot. The actual size of this rectangle is calculated by the layout system
at runtime after performing calculations based on the screen size, parent properties and element
properties such as border, width, height, margin, and padding. After calculating the layout properties of
the element, the final visible region of an element is called the layout clip.

For example, Figure 2 and Figure 3 show the layout slot and layout clip of an element.

Figure 2

100 @ C# Corner
Figure 3

Get Layout Information


If you look at Figure 4, there is a Button and a TextBlock element placed on a Window. You may not
notice the layout area of the TextBlock but if you look at Figure 5, you will notice a blue color, and it is
an actual layout area of the TextBlock.

Figure 4

Figure 5

The LayoutInformation class is used to get information about the layout of a Window, UserControl or
Page in WPF.

The LayoutInformation class has two static methods – GetLayoutClip and GetLayoutSlot. The
GetLayoutClip method returns a Geometry that represents the visible region of an element. The
GetLayoutSlot method returns the entire bounding rectangle of an element.
The code snippet in Listing 1 calls GetLayoutClip and GetLayoutSlot methods to get the layout clip and
layout slot of a TextBlock element.

101 @ C# Corner
Geometry clipGeometry = LayoutInformation.GetLayoutClip(textBlock1);
Rect layoutRectangle = LayoutInformation.GetLayoutSlot(textBlock1);
textBlock1.Text = "Layout: " + layoutRectangle.ToString();

Listing 1

Size, Width, and Height


This section focuses on the size of elements such as width and height etc.
Figure 6 shows a typical window with size, margin, alignment, and padding settings of various WPF
elements.

Figure 6

The size of a control is defined by the width and height properties of the control. When you create a
Windows application in WPF, the default code looks like Listing 2. In Listing 2, a Window element is used
to create a Window and a Grid panel is placed on this window. The Height and the Width of the window
are set to 300 and 400 pixels respectively.

The type of Width and Height is a double device-independent unit (1/96th inch). This value can be
followed by strings px, in, cm, or pt that is a pixel, inch, centimetre, or point respectively. Here is a listing
of pixels and other measurements.

● 1 inch = 96 pixels

● 1 centimeter = 96/2.54 pixels

● 1 point = 96/72 pixels

The following code snippet sets the Width and Height of a grid to 300 and 200 pixels respectively.
<Grid x:Name="RootLayout"
Background="LightBlue"
Height="200px"
Width="300px" />

102 @ C# Corner
Note: If the Height and Width properties of an element are not set, it inherits the width and height of the
container control.
<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="400">
<Grid Name="RootLayout">

</Grid>
</Window>
Listing 2

The output of Listing 2 looks like Figure 7.

Figure 7

Now let’s set the width and height of the Grid.

<Grid x:Name="RootLayout"
Background="LightBlue"
Height="200px"
Width="300px" />

New output with the changed width and height of Grid looks like Figure 8.

103 @ C# Corner
Figure 8

● The MinHeight property of an element represents the minimum height of an element. If you set
Height property less than this value, it will be considered as MinHeight.

● The MaxHeight property of an element represents the maximum height of an element. If you
set a Height property greater than this value, it will be considered as MaxHeight.

● The MinWidth property of an element represents the minimum width of an element. If you set
the Width property less than this value, it will be considered as MinWidth.

● The MaxWidth property of an element represents the maximum width of an element. If you set
the Width property greater than this value, it will be considered as MaxWidth.

● ActualHeight property of an element gets the actual rendered height of an element after
calculating MinHeight, MaxHeight, and Height properties.
● ActualWidth property of an element gets the actual rendered width of an element after
calculating MinWidth, MaxWidth, and Width properties.

Note: MinWidth, MinHeight, MaxWidth, and MaxHeight properties are useful when you want to restrict
your application’s size to a specific width and height.

The code snippet in Listing 3 creates a Rectangle that has Width and Height properties set to 600 each
but MaxHeight and MaxWidth are set to 200 each. That means the ActualHeight and ActualWidth of the
rectangle that renders can’t be more than 200 each.

<Grid x:Name="GridMain">
<Rectangle x:Name="SizeRectangle"
Fill="LightBlue"
Height="600"
MaxHeight="200"
MaxWidth="200"
MinHeight="200"

104 @ C# Corner
MinWidth="200"
Width="600" />
</Grid>

Listing 3

The rectangle generated by Listing 3 looks like Figure 9 where actual height and actual width of the
rectangle is 200 each, not 600.

Figure 9

Margins
The margin is the space between an element and the parent element or other adjacent element on the
same parent. Margin adds the extra space around the outside edges of an element.

The Margin property of FrameworkElement is used to specify the margin of an element. It is a type of
Thickness structure. The Thickness structure has four properties – Left, Top, Right, and Bottom. You can
either pass only a double value or four double values. When margin is defined by a single value, it
applies to all four sides of an element. If a margin is defined with values for all 4 sides, then specified 4
values are applied to the Left, Top, Right, and Bottom side of an element. If you don’t want to set a
margin for one particular side, then you can define 0 in that place.

The code snippet in Listing 4 creates two rectangles and sets the margin of the first rectangle by passing
only one value 20 that sets margin for all four directions left, top, bottom, and right. The margin for the
second rectangle is set 50,50,0,0.
<Rectangle x:Name="Rectangle1"
Fill="LightBlue"
Height="100"
HorizontalAlignment="Left"
Margin="20"

105 @ C# Corner
VerticalAlignment="Top"
Width="200" />

<Rectangle x:Name="Rectangle2"
Fill="LightGreen"
Height="100"
HorizontalAlignment="Left"
Margin="50,50,0,0"
VerticalAlignment="Top"
Width="200" />

Listing 4

The output of Listing 4 looks like Figure 10. In Figure 10, you see two rectangles. The blue rectangle has a
margin set to 20,20,20,20. That shows that this extra space is added between the starting point (left and
top corner) of the parent control and the rectangle.

Figure 10

Similar to the Width and Height, the value of Margin can be set in px, in, cm and pt. The code snippet in
Listing 5 sets Margin properties at runtime by creating a Thickness object.
Rectangle1.Margin = new Thickness(20);
Rectangle2.Margin = new Thickness(50, 50, 0, 0);

Listing 5

Padding
The padding adds extra space from the inside part of an element, it is a space between the element and
a border. It is represented by the Padding property of FrameworkElement and it is of type Thickness.
The Padding property is not available to all elements in XAML and WPF. A few elements that have this
property are Block, Border, Control, and TextBlock.

The code snippet in Listing 6 creates a Border and sets its Padding property in XAML.

106 @ C# Corner
<Border x:Name="BorderGrid"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="5"
CornerRadius="20"
Padding="20" />

Listing 6

Listing 6 generates output that looks like Figure 11.

Figure 11

The code snippet in Listing 7 creates a Grid and adds a Border to the Grid and sets padding. The
output looks exactly like Figure 11.
private void SetDynamicPadding()
{
Border brd = new Border();
brd.Background = new SolidColorBrush(Colors.LightBlue);
brd.BorderBrush = new SolidColorBrush(Colors.Black);
brd.BorderThickness = new Thickness(5);
brd.CornerRadius = new CornerRadius(20);
brd.Padding = new Thickness(20);
Grid1.Children.Add(brd);
}
Listing 7

Horizontal and Vertical Alignment


The FrameworkElement has two alignment properties – HorizontalAlignment and
VerticalAlignment.

107 @ C# Corner
The HorizontalAlignment property is used to position child elements horizontally.
HorizontalAlignment enumeration is used to set the values of HorizontalAlignment property.
The HorizontalAlignment enumeration has four properties – Left, Center, Right, and Stretch.
The Left, Center, and Right properties set a child element to the left, center, and right side of
the parent element. The Stretch property stretches a child element to fill the parent element's
allocated layout space. Which means both parent and child would have the same length.

Note: If the Width property is set on an element, Stretch alignment does not have any effect.

The code listed in Listing 8 places four Buttons elements on a StackPanel and sets the
HorizontalAlignment property to Left, Center, Right and Stretch.
<StackPanel x:Name="StackPanelOuter"
Background="LightGray">
<Button Name="ButtonFirst"
Background="LightBlue"
Content="Left Aligned"
Height="50"
HorizontalAlignment="Left"
Width="150" />

<Button x:Name="ButtonSecond"
Background="LightGreen"
Content="Center Aligned"
Height="50"
HorizontalAlignment="Center"
Width="150" />

<Button x:Name="ButtonThird"
Background="LightCyan"
Content="Right Aligned"
Height="50"
HorizontalAlignment="Right"
Width="150"/>

<Button Name="ButtonFourth"
Background="LightPink"
Content="Stretch Aligned"
Height="50"
HorizontalAlignment="Stretch"/>
</StackPanel>

Listing 8

Listing 8 generates output looks like Figure 12. Now no matter how much you resize or move the
window, the buttons will stay aligned the same way.

108 @ C# Corner
Figure 12

The code listed in Listing 9 creates a StackPanel and adds four Button controls through code-
behind and sets their HorizontalAlignment property to Left, Center, Right, and Stretch
dynamically. The output looks exactly like Figure 12.
private void DynamicallyHorizontalAlignment()
{
Button ButtonFirst = new Button();
ButtonFirst.Width = 150;
ButtonFirst.Height = 50;
ButtonFirst.Background = new SolidColorBrush(Colors.LightBlue);
ButtonFirst.Content = "Left Aligned";
ButtonFirst.HorizontalAlignment = HorizontalAlignment.Left;
StackPanelOuter.Children.Add(ButtonFirst);

Button ButtonSecond = new Button();


ButtonSecond.Width = 150;
ButtonSecond.Height = 50;
ButtonSecond.Background = new SolidColorBrush(Colors.LightGreen);
ButtonSecond.Content = "Center Aligned";
ButtonSecond.HorizontalAlignment = HorizontalAlignment.Center;
StackPanelOuter.Children.Add(ButtonSecond);

Button ButtonThird = new Button();


ButtonThird.Width = 150;
ButtonThird.Height = 50;
ButtonThird.Background = new SolidColorBrush(Colors.LightCyan);
ButtonThird.Content = "Right Aligned";
ButtonThird.HorizontalAlignment = HorizontalAlignment.Right;
StackPanelOuter.Children.Add(ButtonThird);

Button ButtonFourth = new Button();


ButtonFourth.Height = 50;
ButtonFourth.Background = new SolidColorBrush(Colors.LightPink);
ButtonFourth.Content = "Stretch Aligned";
ButtonFourth.HorizontalAlignment = HorizontalAlignment.Stretch;

109 @ C# Corner
StackPanelOuter.Children.Add(ButtonFourth);
}

Listing 9

The VerticalAlignment property is a type of VerticalAlignment enumeration and represents


how vertically child elements are positioned within a parent element.

The VerticalAlignment enumeration has four properties – Top, Center, Bottom, and Stretch. The
Top, Center, and Bottom properties set a child element to the top, center, and bottom side of
the parent element. The Stretch property stretches a child element to fill the parent element's
allocated layout space vertically.

Note: If the Height property is a set, then Stretch alignment does not have any effect.

The code listed in Listing 10 places four Button elements on a Grid and sets the
VerticalAlignment property to Top, Center, Bottom and Stretch.
<Grid x:Name="GridMain">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>

<Button x:Name="ButtonFirst"
Background="LightBlue"
Content="Left Aligned"
Height="30"
VerticalAlignment="Top"
Width="100"/>

<Button x:Name="ButtonSecond"
Background="LightGreen"
Content="Center Aligned"
Height="30"
VerticalAlignment="Center"
Width="100"
Grid.Column="1" />

<Button x:Name="ButtonThird"
Background="LightCyan"
Content="Right Aligned"
Height="30"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Width="100"
Grid.Column="2"/>

<Button x:Name="ButtonFour"
Background="LightPink"
Content="Stretch Aligned"
HorizontalAlignment="Stretch"

110 @ C# Corner
Width="100"
Grid.Column="3" />
</Grid>

Listing 10

Listing 10 generates output that looks like Figure 13. Now no matter how much you resize or move the
window, the buttons will stay aligned the same way.

Figure 13

The code snippet in Listing 11 creates a Grid and adds four Button controls and sets their
VerticalAlignment property to Top, Center, Bottom, and Stretch dynamically. The output looks
exactly like Figure 13.
private void DynamicallyVerticalAlignment()
{
Button ButtonFirst = new Button();
ButtonFirst.Width = 100;
ButtonFirst.Height = 30;
ButtonFirst.Background = new SolidColorBrush(Colors.LightBlue);
ButtonFirst.Content = "Top Aligned";
ButtonFirst.VerticalAlignment = VerticalAlignment.Top;
GridMain.Children.Add(ButtonFirst);

Button ButtonSecond = new Button();


ButtonSecond.Width = 100;
ButtonSecond.Height = 30;
ButtonSecond.Background = new SolidColorBrush(Colors.LightGreen);
ButtonSecond.Content = "Center Aligned";
ButtonSecond.VerticalAlignment = VerticalAlignment.Center;
GridMain.Children.Add(ButtonSecond);

Button ButtonThird = new Button();


ButtonThird.Width = 100;

111 @ C# Corner
ButtonThird.Height = 30;
ButtonThird.Background = new SolidColorBrush(Colors.LightCyan);
ButtonThird.Content = "Bottom Aligned";
ButtonThird.VerticalAlignment = VerticalAlignment.Bottom;
GridMain.Children.Add(ButtonThird);

Button ButtonFour = new Button();


ButtonFour.Width = 100;
ButtonFour.Background = new SolidColorBrush(Colors.LightPink);
ButtonFour.Content = "Stretch Aligned";
ButtonFour.VerticalAlignment = VerticalAlignment.Stretch;
GridMain.Children.Add(ButtonFour);
}

Listing 11

Content Alignments
In Chapter 3, we learned what content is and how we can change the content of elements. The
alignment of content can be set with two properties are HorizontalContentAlignment and
VerticalContentAlignment. These properties are defined in the
System.Windows.Controls.Control class that is the parent class of all controls in WPF.

Similar to the HorizontalAlignment and VerticalAlignment, both HorizontalContentAlignment


and VerticalContentAlignment properties are of type HorizontalAlignment and
VerticalAlignment enumerations respectively.

Figure 14 shows a Windows which has a Button and a TextBox element. As you can see the
default vertical and horizontal alignment of the content of a Button is center. The default
vertical and horizontal alignment of content for a TextBox is left and top.

Figure 14

112 @ C# Corner
Now, what if you want to place the contents of a Button and TextBox in different positions? Let’s say,
you want to set the contents of the Button and TextBox to bottom and right. This comes handy when
the size of elements is larger than the size of contents.

The code snippet in Listing 12 sets VerticalContentAlignment and HorizontalContentAlignment


properties to bottom and right.
<Grid Name="GridRoot"
Background="LightGray" >
<Button x:Name="ButtonClickMe"
Background="LightBlue"
Content="Click Me!"
FontSize="16"
FontWeight="Bold"
Height="45"
HorizontalContentAlignment="Right"
Margin="23,12,159,0"
VerticalAlignment="Top"
VerticalContentAlignment="Bottom" />

<TextBox x:Name="TextBoxDetails"
FontSize="16"
Height="50"
HorizontalContentAlignment="Right"
Margin="26,72,74,0"
Text="I am a TextBox"
VerticalContentAlignment="Bottom"
VerticalAlignment="Top" />
</Grid>

Listing 12

Listing 12 generates an output which looks like Figure 15. As you notice, the contents of the Button and
TextBox are aligned bottom and right.

Figure 15

113 @ C# Corner
Dealing with Percentage Size in WPF
In HTML, the percentage (%) symbol is used to define a uniform layout that keeps the same
width and height ratio when a web page is resized. We did not have this feature in Windows
forms. However, WPF supports this feature differently by using an asterisk (*) suffix with a
double number. Unlike the percentage, an asterisk does not have a maximum limit of 100. An
asterisk uses the current width or height of an element and divides by the value associated with
the asterisk and when a Window, UserControl or a Page is resized, the actual size of the
element is calculated at runtime.

Let us explain to you the problem with an example. Figure 16 is a Window with a Grid panel and
three Rectangle elements.

Figure 16

You can create this UI by simply placing 3 rectangles on a Grid element and moving them where
you want. The XAML for the same is listed in the following listing.
<Grid Name="GridRoot">
<Rectangle x:Name="RectangleFirst"
Fill="Orange"
Margin="55,0,112,80"
Stroke="Black" />

<Rectangle x:Name="RectangleSecond"
Fill="Green"
HorizontalAlignment="Right"
Margin="0,80,0,0"
Stroke="Black"
Width="113" />

<Rectangle x:Name="RectangleThird"
Fill="Purple"
HorizontalAlignment="Left"
Margin="0,80,0,0"
Stroke="Black"
Width="54" />
</Grid>

Listing 13

114 @ C# Corner
The problem occurs when we try to resize this window, all these rectangles won’t have a size which is
proportional to the current window size. Figure 15 shows what happens if we try to resize the same
window.

Figure 17

So when we resize the window, we want the size of the rectangles to have the same ratio as the
new size of the Window. We can achieve this using an asterisk with the size.
However, all elements in XAML do not support asterisk features. So we have placed columns and rows in
a Grid and fixed their width and height with the asterisk.

The new code is listed in Listing 14.


<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="400">
<Grid Name="GridRoot">
<Grid.RowDefinitions>
<RowDefinition Height="139*" />
<RowDefinition Height="150*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="101*" />
<ColumnDefinition Width="208*" />
<ColumnDefinition Width="169*" />

115 @ C# Corner
</Grid.ColumnDefinitions>
<Rectangle x:Name="RectangleFirst"
Fill="Orange"
Stroke="Black"
Grid.Column="1" />

<Rectangle x:Name="RectangleSecond"
Fill="Purple"
Stroke="Black"
Grid.Row="1" />

<Rectangle x:Name="RectangleThird"
Fill="Green"
Stroke="Black"
Grid.Column="2"
Grid.Row="1" />
</Grid>

</Window>
Listing 14

Figure 18 shows how UI would look with Listing 14.

Figure 18

Now if you resize the window, the size of the rectangles will be changed in proportional to the size of
the window. You can notice the difference in Figure 19.

116 @ C# Corner
Figure 19

Panels
All Panel controls are defined in the System.Windows.Controls namespace that resides in the
presentationframework.dll assembly. Besides the root Window, a Panel works as a parent control for
other child controls. If you create a WPF application using Visual Studio 2019, the default code for the
Window looks like Listing 15, where you can see a Grid panel is the default parent control that is placed
inside a Window.
<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Grid>

</Grid>
</Window>
Listing 15

117 @ C# Corner
Listing 15 generates Figure 20.

Figure 20

WPF comes with five built-in panels.

1. Canvas

2. DockPanel

3. Grid

4. StackPanel

5. WrapPanel

Each panel serves a different purpose. Each has a different way to position and reposition child
elements. Similar to any other WPF control, Panel control is represented in two ways. First, at design-
time using XAML elements and attributes and second, at run-time, using a WPF class and its properties.

The code snippet in Listing 16 creates a Grid panel at design-time using XAML.
<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Grid x:Name="GridPanel"
Background="Blue"
FlowDirection="LeftToRight"
Height="200"
HorizontalAlignment="Left"

118 @ C# Corner
VerticalAlignment="Top"
Width="250" />

</Window>
Listing 16

Output of Listing 16 shown in Figure 21.

Figure 21

The code snippet in Listing 17 creates the same Grid panel shown in Figure 21 at run-time using WPF
classes.
private void CreateDynamicPanel()
{
// Create a Grid Panel control
Grid gridPanel = new Grid();

// Set Grid Panel properties


gridPanel.Background = new SolidColorBrush(Colors.Blue);
gridPanel.Width = 250;
gridPanel.Height = 200;
gridPanel.HorizontalAlignment = HorizontalAlignment.Left;
gridPanel.VerticalAlignment = VerticalAlignment.Top;
gridPanel.FlowDirection = FlowDirection.LeftToRight;

// Set Grid Panel as the content of the Window


RootWindow.Content = gridPanel;
}
Listing 17

All Panel controls are derived from the Panel class. Let’s take a look at the Panel class properties and
methods.

Panel Class Properties

119 @ C# Corner
● The Background property represents the background colour of a panel which can be set with a
Brush object.

● The Children property represents all child controls of a Panel.

● The HasLogicalOrientation property signifies whether a Panel arranges its descendants in a


single dimension.

● The InternalChildren property represents all child controls of a Panel including items that are
added directly in the code, and also items that are generated by data binding.

● The IsItemHost property signifies if this Panel is a container for UI items that are generated by
an ItemsControl. An ItemsControl is a control that can be used to present a collection of items.

● The LogicalChildrent property returns an enumerator that iterates the logical child elements of
this panel.

● The LogicalOrientation property signifies if a panel only supports layout in a single dimension.

● The VisualChildrentCount property represents several child Visual objects in this Panel.

Canvas
We are familiar with a canvas used in a painting, it is used as a surface for oil painting. Artists can paint
in any direction at any point, he can even overlap some of his art. The artist has complete control over
the canvas. It is up to him to decide where to put items on the canvas.

WPF canvas panel follows the same rules as real-life canvas, it gives complete control to the developer.
It allows child elements to be overlapped or to be placed in any direction as per the developer's wish.

A Canvas panel is used to position child elements by using coordinates that are relative to the canvas
area. Canvas has 4 attached properties that specify the position of the child element.
Left, Right, Top, Bottom
Canvas.Left="10", Canvas.Top="10"
The Left property represents the distance between the left side of control and its parent container
Canvas. The Top property represents the distance between the top of the control and its parent
container Canvas.
Here, 10 specifies the margin of a specific coordinate, if Canvas.left is set to "10", then that element
would be positioned on the left side by keeping a margin of 10.
Same goes for Right and Bottom.

Here are some of the properties of Canvas panels.

1. The default values of Height and Width properties are 0. If you do not set these values, you will
not see a canvas unless child elements are automatically resizable.
2. Child elements on a Canvas can never be resized.

120 @ C# Corner
3. The vertical and horizontal alignments on child elements do not work. Child elements are placed
on positions set by the Canvas Left, Top, Right, and Bottom properties.
4. The margin does work partially. If the Left property of Canvas is set, the Right property does not
work. If the Top property of Canvas is set, the Bottom property does not work.

Following is a syntax of Canvas in XAML.

<Canvas/>

Let's see a basic example.


We will draw some basic 2D shapes and see how to place them inside a canvas panel.
Shapes in the following order:
● Ellipse
● Rectangle
● Rectangle with curved edges
● Path
● Path with heart shape
Order is very important in canvas because canvas overlaps last control over the previous ones, meaning
the 2nd rectangle will be overlapped on the 1st ellipse in our case.
The code snippet in Listing 18 covers all of the above requirements.

<Canvas x:Name="CanvasPanel"
Background="LightGray">
<Ellipse x:Name="TwoDEllipse"
Height = "100"
Margin="10 0 0 0"
Stroke="Black"
StrokeThickness="1"
Width = "100"
Canvas.Left="0"
Canvas.Top="18"
>
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "AliceBlue"/>
<GradientStop Offset = "1" Color = "LightBlue"/>
<GradientStop Offset = "2" Color = "DarkBlue"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>

<Rectangle x:Name="TwoDRectangle"
Height="75"
Margin = "10 0 0 0"
Stroke="Black"
StrokeThickness="1"
Width="75"
Canvas.Left="50"
Canvas.Top="65">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "#f1ba82"/>
<GradientStop Offset = "1" Color = "Coral"/>

121 @ C# Corner
<GradientStop Offset = "2" Color = "Coral"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

<Rectangle x:Name="TwoDRectangle2"
Height="75"
Margin = "10 0 0 0"
RadiusX="10"
RadiusY="10"
Stroke="Black"
StrokeThickness="1"
Width="75"
Canvas.Left="90"
Canvas.Top="100">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "Coral"/>
<GradientStop Offset = "1" Color = "#ff3f33"/>
<GradientStop Offset = "2" Color = "#ff5733"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

<Path x:Name="TwoDPath"
Height = "80"
Margin = "10 0 0 0"
Stretch = "Fill"
Stroke="Black"
StrokeThickness="1"
Width="80"
Canvas.Left="124"
Canvas.Top="134">
<Path.Data>
<PathGeometry x:Name="PathGeoMetry">
<PathFigure StartPoint = "50,0" IsClosed = "True">
<LineSegment Point = "100,50"/>
<LineSegment Point = "50,100"/>
<LineSegment Point = "0,50"/>
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "#e8e670"/>
<GradientStop Offset = "1" Color = "#eda619"/>
<GradientStop Offset = "2" Color = "#edea19"/>
</RadialGradientBrush>
</Path.Fill>
</Path>

<Path x:Name="PathHeart"
Data="M 241,200
A 20,20 0 0 0 200,240
C 210,250 240,270 240,270
C 240,270 260,260 280,240
A 20,20 0 0 0 239,200"

122 @ C# Corner
Stroke="Black"
StrokeThickness="1"
Canvas.Right="35"
Canvas.Bottom="30"
>
<Path.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "#e88270"/>
<GradientStop Offset = "1" Color = "#ee3514"/>
<GradientStop Offset = "2" Color = "#ee1414"/>
</RadialGradientBrush>
</Path.Fill>
</Path>
</Canvas>

Listing 18

Figure 22 shows the output of Listing 18.

Figure 22

Z-Index: Here, we have limited shapes in our example. So we can manually adjust which control we
want to display overlap by adding it at the end of the XAML.
It gets messy when it has more than 20 or 30 shapes.
To overcome this problem, the canvas panel has a property named Z-Index. Control with the higher z
index overlaps the one with a lower z index.

Note: Two controls can have the same z index, but then the last defined control will overlap the previous
one.

123 @ C# Corner
Let's make changes in our example by setting Panel.ZIndex for the Rectangle and Path to 2. Now, these
2 shapes will overlap our centered shape. To achieve that, set its Panel.ZIndex = 1.
So now, the order for ZIndex is 0 -> 2 -> 1 -> 2 -> 0. Why 0? Because by default, ZIndex is set to 0.

Listing 19 incorporates all these new changes.

<Canvas x:Name="CanvasPanel"
Background="LightGray">
<Ellipse x:Name="TwoDEllipse"
Height = "100"
Margin="10 0 0 0"
Stroke="Black"
StrokeThickness="1"
Width = "100"
Canvas.Left="0"
Canvas.Top="18"
>
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "AliceBlue"/>
<GradientStop Offset = "1" Color = "LightBlue"/>
<GradientStop Offset = "2" Color = "DarkBlue"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>

<Rectangle x:Name="TwoDRectangle"
Height="75"
Margin = "10 0 0 0"
Stroke="Black"
StrokeThickness="1"
Width="75"
Canvas.Left="50"
Canvas.Top="65"
Panel.ZIndex="2">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "#f1ba82"/>
<GradientStop Offset = "1" Color = "Coral"/>
<GradientStop Offset = "2" Color = "Coral"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

<Rectangle x:Name="TwoDRectangle2"
Height="75"
Margin = "10 0 0 0"
RadiusX="10"
RadiusY="10"
Stroke="Black"
StrokeThickness="1"
Width="75"
Canvas.Left="90"
Canvas.Top="100"
Panel.ZIndex="1">

124 @ C# Corner
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "Coral"/>
<GradientStop Offset = "1" Color = "#ff3f33"/>
<GradientStop Offset = "2" Color = "#ff5733"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

<Path x:Name="TwoDPath"
Height = "80"
Margin = "10 0 0 0"
Stretch = "Fill"
Stroke="Black"
StrokeThickness="1"
Width="80"
Canvas.Left="124"
Canvas.Top="134"
Panel.ZIndex="2">
<Path.Data>
<PathGeometry x:Name="PathGeoMetry">
<PathFigure StartPoint = "50,0" IsClosed = "True">
<LineSegment Point = "100,50"/>
<LineSegment Point = "50,100"/>
<LineSegment Point = "0,50"/>
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "#e8e670"/>
<GradientStop Offset = "1" Color = "#eda619"/>
<GradientStop Offset = "2" Color = "#edea19"/>
</RadialGradientBrush>
</Path.Fill>
</Path>

<Path x:Name="PathHeart"
Data="M 241,200
A 20,20 0 0 0 200,240
C 210,250 240,270 240,270
C 240,270 260,260 280,240
A 20,20 0 0 0 239,200"
Stroke="Black"
StrokeThickness="1"
Canvas.Right="35"
Canvas.Bottom="30"
>
<Path.Fill>
<RadialGradientBrush>
<GradientStop Offset = "0" Color = "#e88270"/>
<GradientStop Offset = "1" Color = "#ee3514"/>
<GradientStop Offset = "2" Color = "#ee1414"/>
</RadialGradientBrush>
</Path.Fill>
</Path>
</Canvas>

125 @ C# Corner
Listing 19
Figure 23 is an output of Listing 19. Where you can see how the second and the fourth shape are
overlapping on others.

Figure 23

Canvas panel is the simplest amongst other panels in WPF. It is famous because of its flexibility and it is
mostly used with shapes or animations.

DockPanel
A Dock Panel is used for docking its child elements in the left, right, top, and the bottom position. The
position of child elements is determined by the Dock property of the respective child elements and the
relative order of those child elements. The default value of Dock property is left. The Dock property is a
type of Dock enumeration that has Left, Right, Top, and Bottom values.

Here are some of the properties of DockPanels.

● The LastChildFill property specifies whether the last child element within a DockPanel stretches
to fill the remaining available space. If it is set to true, then the Dock property of the last
element will be ignored.

● Margin is applicable on DockPanels.

The GetDock and SetDock methods are used to get and set the dock value of an element.

The code snippet in Listing 22 creates a DockPanel with five Buttons. Four buttons are docked and the
last one has no docking set that fills the entire remaining area.

126 @ C# Corner
<DockPanel Name="MainPanel">
<Button Name="ButtonTop"
Background="LightGreen"
Content="Top"
Height="50"
DockPanel.Dock="Top" />

<Button Name="ButtonLeft"
Background="LightBlue"
Content="Left"
Width="50"
DockPanel.Dock="Left" />

<Button Name="ButtonRight"
Background="LightSalmon"
Content="Right"
Width="50"
DockPanel.Dock="Right" />

<Button Name="ButtonBottom"
Background="LightCyan"
Content="Bottom"
Height="50"
DockPanel.Dock="Bottom" />
<Button Name="ButtonCentre"
Background="LightGray" />
</DockPanel>

Listing 20

Figure 22

The DockPanel class in WPF represents a DockPanel control. The code listed in Listing 21 creates a Dock
Panel dynamically, adds five Button controls, and sets their docking properties by using the SetDock
method. The output of Listing 21 also generates the same output as in Figure 22.

127 @ C# Corner
private void CreateADockPanelDynamically()
{
// Create a DockPanel
DockPanel dcPanel = new DockPanel();

// Create a button
Button TopRect = new Button();
TopRect.Background = new SolidColorBrush(Colors.LightGreen);
TopRect.Height = 50;
TopRect.Content = "Top";
// Dock button to top
DockPanel.SetDock(TopRect, Dock.Top);
// Add docked button to DockPanel
dcPanel.Children.Add(TopRect);

// Create a button
Button LeftRect = new Button();
LeftRect.Background = new SolidColorBrush(Colors.LightBlue);
LeftRect.Width = 50;
LeftRect.Content = "Left";
// Dock button to left
DockPanel.SetDock(LeftRect, Dock.Left);
// Add docked button to DockPanel
dcPanel.Children.Add(LeftRect);

// Create a button
Button RightRect = new Button();
RightRect.Background = new SolidColorBrush(Colors.LightSalmon);
RightRect.Width = 50;
RightRect.Content = "Right";
// Dock button to left
DockPanel.SetDock(RightRect, Dock.Right);
// Add docked button to DockPanel
dcPanel.Children.Add(RightRect);

// Create a button
Button BottomRect = new Button();
BottomRect.Background = new SolidColorBrush(Colors.LightCyan);
BottomRect.Height = 50;
BottomRect.Content = "Bottom";
// Dock button to left
DockPanel.SetDock(BottomRect, Dock.Bottom);
// Add docked button to DockPanel
dcPanel.Children.Add(BottomRect);

// Create a fill button


Button FillRect = new Button();
FillRect.Background = new SolidColorBrush(Colors.LightGray);
FillRect.Content = "Center";

// Add docked button to DockPanel


dcPanel.Children.Add(FillRect);

RootWindow.Content = dcPanel;

128 @ C# Corner
Listing 21

Grid
We all are surrounded by a grid-like structure. To give you an idea let me brief you a bit. A most popular
example of a grid is the relational database where data is divided into rows and columns. Grids are so
powerful that they are not only used for storing data but for displaying the data as well. Grid panel is
WPF's one of the widely used panels.

It consists of columns and rows. Each field is occupied by a single row-column combination. To give you
an idea, this is what the grid looks like:

Figure 23

Grid Panel may be a complicated but versatile panel among all panels. It can be used to design
complicated UIs where we need to place multiple elements in a tabular format of rows and columns.

The following code snippet creates a Grid element and sets its background, width, height, vertical and
horizontal alignment properties.
<Grid x:Name="GridPanel"
Background="Blue"
Height="220"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Width="280"/>

Listing 22

The output of Listing 22 looks like Figure 24.

129 @ C# Corner
Figure 24

Grid Properties
The Grid has three major properties – RowDefinitions, ColumnDefinitions, and ShowGridLines. The
RowDefinitions property is a collection of RowDefinition. The ColumnDefinitions property represents a
collection of ColumnDefinition. The ShowGridLines property decides whether the grid lines of a Grid
panel should be visible or not.

Create Grid
The following code snippet creates a Grid control, sets its width and foreground color and makes sure
grid lines are visible.
<Grid Name="MainGrid" Width="400" Background="LightSteelBlue" ShowGridLines="True" \>

Listing 23

The ColumnDefinitions property is used to add columns and the RowDefinitions property is used to add
rows to a Grid. The following code snippet in Listing 24 adds three columns and three rows to a grid.
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>
Listing 24

130 @ C# Corner
There are 2 attach properties of Grid. One is Grid.Row and another is Grid.Column. These properties are
used by Grid’s child elements. Any child element can use Grid.Row and Grid.Column properties to
specify their position inside a Grid. The values of rows and columns start with 0. That means, if there are
three columns in a grid, the first column would be represented by number 0.

The following code snippet in Listing 25 puts a TextBlock control in the second row and third column.

<TextBlock Grid.Row="1" Grid.Column="2" Foreground="Green"


Text="Age" Height="20" VerticalAlignment="Top" />

Listing 25

Listing 26 merges code from Listing 23,24, and 25, with few more TextBlocks to cover all cells in the Grid.

<Grid x:Name="MainGrid"
Background="LightSteelBlue"
ShowGridLines="True"
Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition Height="45" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>

<TextBlock x:Name="TextBlockHeaderOne"
FontSize="14"
FontWeight="Bold"
Foreground="Green"
Height="20"
Text="Model Name"
VerticalAlignment="Top"/>

<TextBlock x:Name="TextBlockHeaderSecond"
FontSize="14"
FontWeight="Bold"
Foreground="Green"
Height="20"
Text="OS"
VerticalAlignment="Top"
Grid.Column="1" />

<TextBlock x:Name="TextBlockHeaderThird"
FontSize="14"
FontWeight="Bold"
Foreground="Green"
Text="Company"
Height="20"
VerticalAlignment="Top"
Grid.Column="2" />

131 @ C# Corner
<TextBlock x:Name="TextBlockModelOne"
FontSize="12"
Text="iPhone 12"
Grid.Row="1"/>

<TextBlock x:Name="TextBlockOSOne"
FontSize="12"
Text="ios 14"
Grid.Column="1"
Grid.Row="1" />

<TextBlock x:Name="TextBlockCompanyOne"
FontSize="12"
Text="Apple"
Grid.Row="1"
Grid.Column="2"/>

<TextBlock x:Name="TextBlockModelTwo"
FontSize="12"
Text="Note 20"
Grid.Row="2" />

<TextBlock x:Name="TextBlockMOSTwo"
FontSize="12"
Text="Android"
Grid.Column="1"
Grid.Row="2" />

<TextBlock x:Name="TextBlockCompanyTwo"
FontSize="12"
Text="Samsung"
Grid.Column="2"
Grid.Row="2" />
</Grid>

Listing 26

The output of Listing 26 looks like this Figure 25.

Figure 25

132 @ C# Corner
Create a Grid Dynamically
The Grid class in WPF represents a Grid control. The following code snippet in Listing 27 creates a Grid
control, sets its width, horizontal alignment, vertical alignment, show grid lines, and background color.

Grid DynamicGrid = new Grid();


DynamicGrid.Width = 400;
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Top;
DynamicGrid.ShowGridLines = true;
DynamicGrid.Background = new SolidColorBrush(Colors.LightSteelBlue);
Listing 27

The following code snippet in Listing 28 adds three columns and three rows to Grid.

// Create Columns
ColumnDefinition gridCol1 = new ColumnDefinition();
ColumnDefinition gridCol2 = new ColumnDefinition();
ColumnDefinition gridCol3 = new ColumnDefinition();
DynamicGrid.ColumnDefinitions.Add(gridCol1);
DynamicGrid.ColumnDefinitions.Add(gridCol2);
DynamicGrid.ColumnDefinitions.Add(gridCol3);

// Create Rows
RowDefinition gridRow1 = new RowDefinition();
gridRow1.Height = new GridLength(45);
RowDefinition gridRow2 = new RowDefinition();
gridRow2.Height = new GridLength(45);
RowDefinition gridRow3 = new RowDefinition();
gridRow3.Height = new GridLength(45);
DynamicGrid.RowDefinitions.Add(gridRow1);
DynamicGrid.RowDefinitions.Add(gridRow2);
DynamicGrid.RowDefinitions.Add(gridRow3);
Listing 28

Once rows and columns are added to the Grid, you can add any contents to Grid cells by using SetRow
and SetColumn methods. SetRow and SetColumn methods take control name as the first parameter, and
row number or column number as the second parameter. The following code snippet in Listing 29
creates a TextBlock control and displays it in Cell(0,0) that represents the first row and first column of
Grid.

// Add first column header


TextBlock txtBlock1 = new TextBlock();
txtBlock1.Text = "Model Name";
txtBlock1.FontSize = 14;
txtBlock1.FontWeight = FontWeights.Bold;
txtBlock1.Foreground = new SolidColorBrush(Colors.Green);
txtBlock1.VerticalAlignment = VerticalAlignment.Top;
Grid.SetRow(txtBlock1, 0);
Grid.SetColumn(txtBlock1, 0);
Listing 29

133 @ C# Corner
Once control is created and its position within Grid is set, the next step is to add control to Grid by using
Grid.Children.Add method. This code snippet in Listing 30 adds a TextBlock to Grid.

DynamicGrid.Children.Add(txtBlock1);
Listing 30

The complete code is listed in Listing 31 which generates the same output as shown in Figure 25.

private void CreateDynamicWPFGrid()


{
// Create the Grid
Grid DynamicGrid = new Grid();
DynamicGrid.Width = 400;
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Top;
DynamicGrid.ShowGridLines = true;
DynamicGrid.Background = new SolidColorBrush(Colors.LightSteelBlue);

// Create Columns
ColumnDefinition gridCol1 = new ColumnDefinition();
ColumnDefinition gridCol2 = new ColumnDefinition();
ColumnDefinition gridCol3 = new ColumnDefinition();
DynamicGrid.ColumnDefinitions.Add(gridCol1);
DynamicGrid.ColumnDefinitions.Add(gridCol2);
DynamicGrid.ColumnDefinitions.Add(gridCol3);

// Create Rows
RowDefinition gridRow1 = new RowDefinition();
gridRow1.Height = new GridLength(45);
RowDefinition gridRow2 = new RowDefinition();
gridRow2.Height = new GridLength(45);
RowDefinition gridRow3 = new RowDefinition();
gridRow3.Height = new GridLength(45);
DynamicGrid.RowDefinitions.Add(gridRow1);
DynamicGrid.RowDefinitions.Add(gridRow2);
DynamicGrid.RowDefinitions.Add(gridRow3);

// Add first column header


TextBlock txtBlock1 = new TextBlock();
txtBlock1.Text = "Model Name";
txtBlock1.FontSize = 14;
txtBlock1.FontWeight = FontWeights.Bold;
txtBlock1.Foreground = new SolidColorBrush(Colors.Green);
txtBlock1.VerticalAlignment = VerticalAlignment.Top;
Grid.SetRow(txtBlock1, 0);
Grid.SetColumn(txtBlock1, 0);

// Add second column header


TextBlock txtBlock2 = new TextBlock();
txtBlock2.Text = "OS";
txtBlock2.FontSize = 14;
txtBlock2.FontWeight = FontWeights.Bold;
txtBlock2.Foreground = new SolidColorBrush(Colors.Green);
txtBlock2.VerticalAlignment = VerticalAlignment.Top;
Grid.SetRow(txtBlock2, 0);
Grid.SetColumn(txtBlock2, 1);

134 @ C# Corner
// Add third column header
TextBlock txtBlock3 = new TextBlock();
txtBlock3.Text = "Company";
txtBlock3.FontSize = 14;
txtBlock3.FontWeight = FontWeights.Bold;
txtBlock3.Foreground = new SolidColorBrush(Colors.Green);
txtBlock3.VerticalAlignment = VerticalAlignment.Top;
Grid.SetRow(txtBlock3, 0);
Grid.SetColumn(txtBlock3, 2);

//// Add column headers to the Grid


DynamicGrid.Children.Add(txtBlock1);
DynamicGrid.Children.Add(txtBlock2);
DynamicGrid.Children.Add(txtBlock3);

// Create first Row


TextBlock authorText = new TextBlock();
authorText.Text = "iPhone 12";
authorText.FontSize = 12;
authorText.FontWeight = FontWeights.Bold;
Grid.SetRow(authorText, 1);
Grid.SetColumn(authorText, 0);

TextBlock ageText = new TextBlock();


ageText.Text = "ios 14";
ageText.FontSize = 12;
ageText.FontWeight = FontWeights.Bold;
Grid.SetRow(ageText, 1);
Grid.SetColumn(ageText, 1);

TextBlock bookText = new TextBlock();


bookText.Text = " Apple ";
bookText.FontSize = 12;
bookText.FontWeight = FontWeights.Bold;
Grid.SetRow(bookText, 1);
Grid.SetColumn(bookText, 2);
// Add first row to Grid
DynamicGrid.Children.Add(authorText);
DynamicGrid.Children.Add(ageText);
DynamicGrid.Children.Add(bookText);

// Create second row


authorText = new TextBlock();
authorText.Text = "Note 20";
authorText.FontSize = 12;
authorText.FontWeight = FontWeights.Bold;
Grid.SetRow(authorText, 2);
Grid.SetColumn(authorText, 0);

ageText = new TextBlock();


ageText.Text = "Android";
ageText.FontSize = 12;
ageText.FontWeight = FontWeights.Bold;
Grid.SetRow(ageText, 2);
Grid.SetColumn(ageText, 1);

135 @ C# Corner
bookText = new TextBlock();
bookText.Text = "Samsung";
bookText.FontSize = 12;
bookText.FontWeight = FontWeights.Bold;
Grid.SetRow(bookText, 2);
Grid.SetColumn(bookText, 2);

// Add second row to Grid


DynamicGrid.Children.Add(authorText);
DynamicGrid.Children.Add(ageText);
DynamicGrid.Children.Add(bookText);

// Display grid into a Window


RootWindow.Content = DynamicGrid;

}
Listing 31

Managing Column Width and Row Height


The ColumnDefinition has three properties that are used to manage the width of a column in a Grid.
These properties are Width, MaxWidth, and MinWidth. The Width property represents the width of a
column. The MaxWidth and MinWidth are used to set maximum and minimum width of a column.

The RowDefinition has three properties that are used to manage the height of a row in a Grid. These
properties are Height, MaxHeight, and MinHeight. The Height property represents the height of a row.
The MaxHeight and MinHeight are used to set maximum and minimum height of a row.

The code snippet in Listing 32 sets the width of columns and height of rows in a Grid panel at design-
time using XAML.

<Grid x:Name="MainGrid"
Background="LightSteelBlue"
ShowGridLines="False"
Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="22" />
<RowDefinition Height="22" />
<RowDefinition Height="22" />
<RowDefinition Height="22" />
<RowDefinition Height="22" />
</Grid.RowDefinitions>

<TextBlock x:Name="TextBlockHeaderOne"
FontSize="14"
FontWeight="Bold"

136 @ C# Corner
Foreground="Green"
Height="20"
Text="Model Name"
VerticalAlignment="Top"/>

<TextBlock x:Name="TextBlockHeaderSecond"
FontSize="14"
FontWeight="Bold"
Foreground="Green"
Height="20"
Text="OS"
VerticalAlignment="Top"
Grid.Column="1" />

<TextBlock x:Name="TextBlockHeaderThird"
FontSize="14"
FontWeight="Bold"
Foreground="Green"
Text="Company"
Height="20"
VerticalAlignment="Top"
Grid.Column="2" />

<TextBlock x:Name="TextBlockModelOne"
FontSize="12"
Text="iPhone 12"
Grid.Row="1"/>

<TextBlock x:Name="TextBlockOSOne"
FontSize="12"
Text="ios 14"
Grid.Column="1"
Grid.Row="1" />

<TextBlock x:Name="TextBlockCompanyOne"
FontSize="12"
Text="Apple"
Grid.Row="1"
Grid.Column="2"/>

<TextBlock x:Name="TextBlockModelTwo"
FontSize="12"
Text="Note 20"
Grid.Row="2" />

<TextBlock x:Name="TextBlockMOSTwo"
FontSize="12"
Text="Android"
Grid.Column="1"
Grid.Row="2" />

<TextBlock x:Name="TextBlockCompanyTwo"
FontSize="12"
Text="Samsung"
Grid.Column="2"
Grid.Row="2" />

137 @ C# Corner
<TextBlock x:Name="TextBlockModelThird"
Text="BlackBerry Bold 9000"
Grid.Row="3" />

<TextBlock x:Name="TextBlockOSThird"
Text="BlackBerry OS 6"
Grid.Column="1"
Grid.Row="3" />

<TextBlock x:Name="TextBlockCompanyThird"
Text="BlackBerry"
Grid.Column="2"
Grid.Row="3" />

<TextBlock x:Name="TextBlockModelFourth"
Text="Nokia Lumia 630"
Grid.Row="4"/>

<TextBlock x:Name="TextBlockOSFourth"
Text="Windows 8.1"
Grid.Column="1"
Grid.Row="4" />

<TextBlock x:Name="TextBlockCompanyFourth"
Text="Nokia"
Grid.Column="2"
Grid.Row="4" />

<TextBlock x:Name="TextBlockModelFifth"
Text="Sony Ericsson Walkman"
Grid.Row="5" />

<TextBlock x:Name="TextBlockOSFifth"
Text="Symbian"
Grid.Column="1"
Grid.Row="5" />

<TextBlock x:Name="TextBlockCompanyFifth"
Text="Sony Ericsson"
Grid.Column="2"
Grid.Row="5" />

</Grid>

Listing 31

The output of Listing looks like Figure 26.

138 @ C# Corner
Figure 26
Add and Remove Columns
● The Add method of Grid.ColumnDefinitions adds a new column to Grid.
DynamicGrid.ColumnDefinitions.Add(new ColumnDefinition());

● The Grid.ColumnDefinitions.Insert method adds a column at a given position. The following


code adds a new column at position 3 in a Grid.
DynamicGrid.ColumnDefinitions.Insert(3, new ColumnDefinition());

● The RemoveAt method of Grid.ColumnDefinitions delete a column from the given position.
DynamicGrid.ColumnDefinitions.RemoveAt(3);

● The Clear method of Grid.ColumnDefinitions delete all columns in a Grid.


DynamicGrid.ColumnDefinitions.Clear();

Add and Remove Rows


● The Add method of Grid.RowDefinitions adds a new row to the Grid.
DynamicGrid.RowDefinitions.Add(new RowDefinition());

● The Grid.RowDefinitions.Insert method adds a row at a given position.


DynamicGrid.RowDefinitions.Insert(3, new RowDefinition ());

● The RemoveAt method of Grid.RowDefinitions deletes a row from the given position.
DynamicGrid.RowDefinitions.RemoveAt(3);

● The Clear method of Grid.RowDefinitions deletes all rows in a Grid.


DynamicGrid.RowDefinitions.Clear();

Resize Grid Rows with a GridSplitter


The following code snippet in Listing 32 adds a Grid splitter to a Grid that you can use to resize a Grid
row.

139 @ C# Corner
<Grid x:Name="MainGrid"
Background="LightSteelBlue"
Canvas.Top="119"
Height="200"
ShowGridLines="True"
Width="466"
Canvas.Left="8" >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="50*" />
</Grid.RowDefinitions>

<GridSplitter x:Name="GridSplitterCentre"
Background="Green"
Height="3"
HorizontalAlignment="Stretch"
ResizeDirection="Rows"
VerticalAlignment="Stretch"
Width="Auto"
Grid.ColumnSpan="10"
Grid.Row="1" />
</Grid>

Listing 32

Formatting Grid
The Background property of Grid sets the background colors of a Grid. The following code snippet uses
linear gradient brushes to draw the background of a Grid.

<Grid.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Grid.Background>
Listing 33

The output of Listing 33 looks like Figure 27.

140 @ C# Corner
Figure 27

Setting Image as Background of a Grid


To set an image as the background of a Grid, The following code snippet sets the background of a Grid to
an image. The code also sets the opacity of the image.

<Grid.Background>
<ImageBrush ImageSource="GridImage.jpg" Opacity="0.6"/>
</Grid.Background>
Listing 34

The new output looks like Figure 28.

141 @ C# Corner
Figure 28

Let's see one last example by designing a user registration form.

Our final screen would look like Figure 29

Figure 29

This screen consists of 4 labels, 4 Textboxes and 1 button. This Grid consists of 5 Rows and 2 Columns
which are defined inside RowDefinitions and ColumnDefinitions.

The height of rows can be defined with Height property, where the width of the columns is defined with
Width property in the following three ways:

1. Fixed value: To assign a fixed size to an element in pixels.


2. Auto: It will take up the default space of control. If the length of the text is 10 then 10, If it is 100
then 100. Auto calculates length or height of control and assigns available space.
3. Star (*): It will take the remaining space once Auto or fixed-sized are filled.

The code snippet in Listing 35 fulfils all above requirements.

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<Label x:Name="LabelUserName"
Content="User Name:"

142 @ C# Corner
Margin="0 10 0 0"/>

<Label x:Name="LabelPassword"
Content="Password:"
Grid.Row="1"/>

<Label x:Name="LabelConfirmPassword"
Content="Confirm Password:"
Grid.Row="2"/>

<Label x:Name="LabelEmailId"
Content="Email:"
Grid.Row="3"/>

<TextBox x:Name="TextBoxUserName"
Text="{Binding UserName}"
Height="20"
Margin="0 10 0 0"
Width="150"
Grid.Column="1"/>

<PasswordBox x:Name="TextBoxPassword"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="1"/>

<PasswordBox x:Name="TextBoxConfirmPassword"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>

<TextBox x:Name="TextBoxEmail"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="3"/>

<Button x:Name="ButtonLogin"
Content="Register"
Height="20"
HorizontalAlignment="Center"
Margin="20 10 0 0"
Width="100"
Grid.ColumnSpan="2"
Grid.Row="4"/>

</Grid>

Listing 35

Figure 30 is a result of Listing 35.

143 @ C# Corner
Figure 30

Placement is always -1
In the following code, for PasswordBox, we have set Grid.Row property to 1 but it is technically on the
2nd row, this is possible because the Index of column and rows starts with 0 and also notice that we did
not even set Grid.Row property for our UserName label, this is because, by default, a Grid panel is
created with one row and one column so Grid.Row = 0 and Grid.Column = 0 are set by default.

● Have a look at the way we have set Column properties in the above example for these
TextBoxes. No Grid.Row for the first TextBox.

<TextBox x:Name="TextBoxUserName"
Text="{Binding UserName}"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>

<PasswordBox x:Name="TextBoxPassword"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="1"/>

Listing 36

● What if you want to merge 2 columns? We can use the ColumnSpan property, then specify the
number of columns you wish to merge. So it merges 2 columns from its position. Login Button’s
column position is 0 so it merges 0 and 1 together. For rows, there is RowSpan property.
Have a look at the code snippet from Listing 37, which was part of our example. How we have
used ColumnSpan property on Button.

<Button x:Name="ButtonLogin"
Height="20"
Width="100"
HorizontalAlignment="Center"
Command="{Binding RegisterButtonClicked}"
Grid.Row="4"

144 @ C# Corner
Grid.ColumnSpan="2"/>

Listing 37

StackPanel
Stack panel is one of the simplest panels to use. It stacks its child elements in a single line, either
horizontally or vertically. In real life, we have seen a stack of books, arranged vertically one below
another. Stack Panel follows the same concept.

The following code snippet creates a StackPanel at design-time using XAML.


<StackPanel x:Name="StackPanelRoot"
Background="LightBlue"
Height="200"
Width="300" />

Listing 38

The Orientation property specifies the direction of children that can be vertical or horizontal. The
default orientation of the StackPanel is Vertical, meaning if you don't specify the orientation property,
by default child elements will be stacked vertically. Here’s how you can set the orientation property to
Horizontal.
<StackPanel x:Name="StackPanelRoot"
Background="LightBlue"
Height="200"
Orientation="Horizontal"
Width="300" />

Listing 39

Note: If child elements on a StackPanel do not fit in the StackPanel’s area, then they go outside of the
visible area. If you wish to wrap the child elements then you can use WrapPanel instead.

Note: Also by default StackPanel stretches its elements. We can use the HorizontalAlignment and the
VerticalAlignment properties of child elements to get rid of this stretch behaviour.

First, let’s see how Canvas control positions five ellipse elements on UI. The code snippet in Listing 40
shows the same.
<Canvas >
<Ellipse Width="100" Height="100" Fill="Red" />
<Ellipse Width="80" Height="80" Fill="Orange" />
<Ellipse Width="60" Height="60" Fill="Yellow" />
<Ellipse Width="40" Height="40" Fill="Green" />
<Ellipse Width="20" Height="20" Fill="Blue" />
</Canvas>
Listing 40

145 @ C# Corner
Figure 31 illustrates the output of Listing 40.

Figure 31

Now, in Listing 40, let’s replace Canvas with a StackPanel. The new code looks like Listing 41.
<StackPanel>
<Ellipse Width="100" Height="100" Fill="Red" />
<Ellipse Width="80" Height="80" Fill="Orange" />
<Ellipse Width="60" Height="60" Fill="Yellow" />
<Ellipse Width="40" Height="40" Fill="Green" />
<Ellipse Width="20" Height="20" Fill="Blue" />
</StackPanel>
Listing 41

The new output looks like Figure 32, where you can see all elements are stacked in a vertical direction.

146 @ C# Corner
Figure 32

Now let’s change the Orientation property to horizontal by doing the following.
<StackPanel Orientation="Horizontal">
The new output would look like Figure 33.

Figure 33

The code snippet in Listing 42 creates a StackPanel dynamically, then sets its properties and adds five
ellipses.
private void CreateDynamicStackPanel()
{

147 @ C# Corner
// Create a StackPanel and set its properties
StackPanel dynamicStackPanel = new StackPanel();
dynamicStackPanel.Background = new SolidColorBrush(Colors.LightBlue);
dynamicStackPanel.Orientation = Orientation.Horizontal;

// Create Ellipses and add to StackPanel


Ellipse redCircle = new Ellipse();
redCircle.Width = 100;
redCircle.Height = 100;
redCircle.Fill = new SolidColorBrush(Colors.Red);
dynamicStackPanel.Children.Add(redCircle);

Ellipse orangeCircle = new Ellipse();


orangeCircle.Width = 80;
orangeCircle.Height = 80;
orangeCircle.Fill = new SolidColorBrush(Colors.Orange);
dynamicStackPanel.Children.Add(orangeCircle);

Ellipse yellowCircle = new Ellipse();


yellowCircle.Width = 60;
yellowCircle.Height = 60;
yellowCircle.Fill = new SolidColorBrush(Colors.Yellow);
dynamicStackPanel.Children.Add(yellowCircle);

Ellipse greenCircle = new Ellipse();


greenCircle.Width = 40;
greenCircle.Height = 40;
greenCircle.Fill = new SolidColorBrush(Colors.Green);
dynamicStackPanel.Children.Add(greenCircle);

Ellipse blueCircle = new Ellipse();


blueCircle.Width = 20;
blueCircle.Height = 20;
blueCircle.Fill = new SolidColorBrush(Colors.Blue);
dynamicStackPanel.Children.Add(blueCircle);

// Display StackPanel into a Window


RootWindow.Content = dynamicStackPanel;
}
Listing 42

The output of Listing 42 generates output as Figure 34.

148 @ C# Corner
Figure 34

If there isn’t enough space on a StackPanel vertically or horizontally, you may add a scrolling feature to
it. The CanHorizontallyScroll and CanVerticallyScroll properties are used to add scrolling functionality to
a StackPanel.

WrapPanel
Wouldn't it be great to have a panel that arranges its child elements by itself? Well, WPF got you
covered. The answer is WrapPanel: The meaning is in the name itself, it wraps the contents until there is
no empty place left. It arranges elements automatically.
The WrapPanel arranges its child elements next to one another, either horizontally or vertically, unlike a
stack panel by default WrapPanel's orientation is horizontal. While wrapping these child elements, one
needs to have fixed height or width for every child element.
If the orientation of WrapPanel is Horizontal, then child elements will share the same height as the
highest element. If the orientation of WrapPanel is Vertical, then child elements will share the same
width as the widest element.

The following code snippet creates a WrapPanel and sets its height, width, and background properties at
design-time using XAML.

<WrapPanel x:Name="PanelRoot"
Background="LightBlue"
Height="200"
Width="300" />

Listing 43

149 @ C# Corner
The ItemHeight and ItemWidth properties of WrapPanel are used to set a fixed uniform height and
width for all items that are contained within a WrapPanel. The following code snippet sets Orientation,
ItemHeight, and ItemWidth properties of a WrapPanel in XAML. Every item within a WrapPanel will have
the height and width of 100 each.

<WrapPanel x:Name="PanelRoot"
Background="LightBlue"
Height="200"
ItemHeight="100"
ItemWidth="100"
Orientation="Vertical"
Width="300" />

Listing 44

The code snippet in Listing 45 creates a WrapPanel control and keeps its orientation to horizontal by
default.

<WrapPanel>
<Ellipse Width="100" Height="100" Fill="Red" />
<Ellipse Width="90" Height="90" Fill="Orange" />
<Ellipse Width="80" Height="80" Fill="Yellow" />
<Ellipse Width="70" Height="70" Fill="LightGreen" />
<Ellipse Width="60" Height="60" Fill="Green" />
<Ellipse Width="50" Height="50" Fill="LightBlue" />
<Ellipse Width="40" Height="40" Fill="Blue" />
<Ellipse Width="30" Height="30" Fill="Black" />
</WrapPanel>
Listing 45

Figure 35 is an output of Listing 36 where all child controls are wrapped horizontally.

Figure 35

150 @ C# Corner
Now if you change orientation to vertical like the following code, the output would look like Figure 36.

<WrapPanel Orientation="Vertical">

As you can see Figure 36, the new controls are aligned vertically.

Figure 36

The code listed in Listing 37 creates a StackPanel dynamically, then sets its properties and add five
ellipses.
private void CreateDynamicWrapPanel()
{
// Create a WrapPanel and set its properties
WrapPanel dynamicWrapPanel = new WrapPanel();
dynamicWrapPanel.Orientation = Orientation.Horizontal;

// Create Ellipses and add to StackPanel


Ellipse redCircle = new Ellipse();
redCircle.Width = 100;
redCircle.Height = 100;
redCircle.Fill = new SolidColorBrush(Colors.Red);
dynamicWrapPanel.Children.Add(redCircle);

Ellipse orangeCircle = new Ellipse();


orangeCircle.Width = 80;
orangeCircle.Height = 80;
orangeCircle.Fill = new SolidColorBrush(Colors.Orange);
dynamicWrapPanel.Children.Add(orangeCircle);

Ellipse yellowCircle = new Ellipse();


yellowCircle.Width = 60;
yellowCircle.Height = 60;
yellowCircle.Fill = new SolidColorBrush(Colors.Yellow);

151 @ C# Corner
dynamicWrapPanel.Children.Add(yellowCircle);

Ellipse greenCircle = new Ellipse();


greenCircle.Width = 40;
greenCircle.Height = 40;
greenCircle.Fill = new SolidColorBrush(Colors.Green);
dynamicWrapPanel.Children.Add(greenCircle);

Ellipse blueCircle = new Ellipse();


blueCircle.Width = 20;
blueCircle.Height = 20;
blueCircle.Fill = new SolidColorBrush(Colors.Blue);
dynamicWrapPanel.Children.Add(blueCircle);

// Display WrapPanel into a Window


RootWindow.Content = dynamicWrapPanel;
}
Listing 46

Let's see one more example with default orientation: horizontal.


The screen will have 3 labels and 3 Textboxes and 1 Register button.

<WrapPanel x:Name="WrapPanelRoot"
Grid.IsSharedSizeScope="True">
<Grid x:Name="GridInnerUserName">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>

<Label x:Name="LabelUserName"
Content="User Name:"
Margin="0 10 0 0"/>

<TextBox x:Name="TextBoxUserName"
Text="{Binding UserName}"
Height="20"
Width="150"
Grid.Column="1"/>
</Grid>

<Grid x:Name="GridInnerPassword">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>

<Label x:Name="LabelPassword"
Content="Password:" />

<PasswordBox x:Name="TextBoxPassword"
Height="20"
Width="150"
Grid.Column="1"/>
</Grid>

152 @ C# Corner
<Grid x:Name="GridInnerEmail">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>

<Label x:Name="LabelEmailId"
Content="Email:" />

<TextBox x:Name="TextBoxEmail"
Height="20"
Width="150"
Grid.Column="1"/>
</Grid>

<Button x:Name="ButtonLogin"
Content="Register"
Height="20"
HorizontalAlignment="Center"
Margin="20 10 0 0"
Width="100" />
</WrapPanel>

Listing 47

Now if you start dragging the screen horizontally, You’ll notice that elements will start occupying empty
space as we drag more.

Dragging horizontally
Figure 37

Figure 38

153 @ C# Corner
Figure 39

Dragging vertically upwards


Figure 40

To see its horizontal wrapping behaviour, change the wrap panel's orientation to vertical.
<WrapPanel x:Name="GridOuter" Orientation="Vertical" >

Alright, once you are done with making these changes, run the project and see the alternate magic:

Figure 41

Dragging vertically downwards


Figure 42

154 @ C# Corner
Dragging vertically downwards
Figure 43

Figure 44

In layman terms, items are horizontally arranged when the window is stretched horizontally and items
are vertically arranged when the window is stretched vertically.

WPF Layout – Border


Elements in WPF do not have a border property. To place a border around an element, WPF provides
the Border element. Similar to other WPF elements, the Border has Width, Height, Background, and
HorizontalAlignment and VerticalAlignment properties.

Besides these common properties, Border has two properties that make a border the Border, which are
BorderThickness and BorderBrush. The BorderBrush property represents the brush that is used to draw
the border. The BorderThickness property represents the thickness of the border.

The CornerRadius property represents the degree to which the corners of a Border will be rounded. The
following code snippet creates a Border element and sets its properties.

<Border x:Name="BorderGreen"
BorderThickness="5"
BorderBrush="Green"
Background="LightGray"
CornerRadius="10"
Height="250"
HorizontalAlignment="Left"

155 @ C# Corner
VerticalAlignment="Top"
Width="270" />

Listing 48

The code snippet in Listing 40 creates a Border around a Canvas element and sets its properties.
The output looks like Figure 1 where all child controls are wrapped horizontally.

<Border x:Name="BorderGreen"
BorderThickness="5"
BorderBrush="Green"
Background="LightGray"
CornerRadius="10"
Height="250"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="270">

<Canvas Background="LightCyan" >


<Rectangle x:Name="RectangleInner"
Canvas.Top="20"
Fill="Red"
Height="200"
Stroke="Black"
StrokeThickness="10"
Width="200"
Canvas.Left="30"/>
</Canvas>
</Border>

Listing 49

The output looks like Figure 45 where you can see the green border with rounded corners.

Figure 45

156 @ C# Corner
The Border class in WPF represents a Border element. The code snippet listed in Listing 41 creates a
Border, sets its properties, and places it around a Canvas element.

private void CreateDynamicBorder()


{
Border border = new Border();
border.Background = new SolidColorBrush(Colors.LightGray);
border.BorderThickness = new Thickness(5);
border.BorderBrush = new SolidColorBrush(Colors.Green);
border.CornerRadius = new CornerRadius(15);
border.Width = 270;
border.Height = 250;

Canvas canvas = new Canvas();


Rectangle rect = new Rectangle();
rect.Width = 200;
rect.Height = 200;
rect.Fill = new SolidColorBrush(Colors.Black );
rect.StrokeThickness = 10d;
canvas.Children.Add(rect);

border.Child = canvas;
RootLayout.Content = border;
}
Listing 50

Note. Border can have only one child element. If you need to place a border around multiple elements,
you must place a border around each element.

WPF Layout – VirtualizingStackPanel


Virtualization technique in WPF improves the rendering performance of UI elements. By applying
virtualization, the layout system ensures that only the visible items of a container are rendered on the
screen. For example, a ListBox element may have thousands of items but virtualization will reduce the
rendering to the visible items only.

VirtualizingStackPanel

The VirtualizingStackPanel control in WPF is used to implement virtualization. The IsVirtualizing


property of the VirtualizingStackPanel initiates the virtualization. By default, the IsVirtualizing property
is set to true. When IsVirtualizing is set to false, a VirtualizingStackPanel behaves the same as an
ordinary StackPanel.

The VirtualizingStackPanel calculates the number of visible items and works with the
ItemContainerGenerator from an ItemsControl to create UI elements only for visible items. The
following code snippet creates a VirtualizingStackPanel.
<VirtualizingStackPanel x:Name="VirtualizingStackPanelRoot"
Height="200"
Width="300" />

The VirtualizingStackPanel.VirtualizationMode property has two values, Standard and Recycling. The
default value of VirtualizationMode is Standard, which means that the VirtualizingStackPanel creates an

157 @ C# Corner
item container for each visible item and discards it when it is no longer needed (such as when the item is
scrolled out of view). When an ItemsControl contains a lot of items, the process of creating and
discarding item containers can negatively affect performance. In that case, use the Recycling, which
reuses item containers instead of creating a new one each time.

The following code snippet creates a VirtualizingStackPanel and sets its VirtualizationModel to Recycling.
<VirtualizingStackPanel x:Name="VirtualizingStackPanelRoot"
Height="200"
VirtualizationMode="Recycling"
Width="300" />

Virtualization can be applied to a container control by directly setting the


VirtualizingStackPanel.VirtualizationMode property. The code snippet in Listing 42 creates a ListBox
control and sets its VirtualizationMode to Recycling.
<StackPanel x:Name="PanelRoot">
<ListBox x:Name="ListBoxParent"
Background="#FFF5BDBD"
Height="193.333"
HorizontalAlignment="Left"
Margin="20,20,0,0"
VerticalAlignment="Top"
Width="400"
VirtualizingStackPanel.VirtualizationMode="Recycling"/>
<Button x:Name="ButtonLoad"
Content="Load Data"
Height="29"
HorizontalAlignment="Left"
Margin="20,18.666,0,0"
VerticalAlignment="Top"
Width="120"
Click="LoadDataButton_Click"/>
</StackPanel>

Listing 51

The supporting code is listed in Listing 43 that creates a data collection and binds the
ListBox.ItemsSource property to the data collection.
private void LoadDataButton_Click(object sender, RoutedEventArgs e)
{
listBox.ItemsSource = GetDataSet();

}
public ArrayList GetDataSet()
{
ArrayList items = new ArrayList();
for (var count = 0; count < 10000; ++count)
{
items.Add(string.Format("Item {0}", count));
}
return items;
}

158 @ C# Corner
}
Listing 52

Summary
At the beginning of this chapter, we covered a basic understanding of the WPF layout system. Later we
discussed the layout clip and the layout slot. We covered the size, margins, paddings, alignments of
elements in the WPF layout system. of WPF elements. Later, we switched our focus on panels. We
discussed the basics of the panels in WPF. We covered how to use different panels such as canvas, dock,
grid, stack and wrap panel. We also discuss their purpose and behaviour. Finally, we covered Border and
VirtualizingStackPanel.

159 @ C# Corner
Chapter 5: Windows, Pages and Dialogs
Windows and Pages are essential items of user interfaces in WPF applications. A Window or a Page
works as the container for all children's control. Dialog boxes are another essence of WPF applications.
In this chapter, we will discuss Windows, Pages, and Dialog Boxes.

Windows
A single Window works as a container for all of its child elements. A Window in WPF looks like Figure 1.
Note: a WPF Application could be a combination of multiple Windows.

Figure 1

A Window has two parts – 1. non-client area and 2. client area.

The non-client area of a window is fixed most of the time and includes the following
components:
● A border

● A title bar

● An icon

160 @ C# Corner
● A Minimize, Maximize, and Restore buttons

● A Close button

● A System menu with menu items that allow the user to minimize, maximize, restore,
move, resize, and close a window

The client area of a window is for developers to add application-specific content, such as menu
bars, toolbars, and other UI controls.

Window Class
In WPF, the class Window represents a Window screen at run-time. A Window object is responsible for
creating, displaying and managing a Window. Window class is a content control and can contain text,
images, and panels. Figure 2 illustrates the Window class hierarchy. As you can see, the Window class
has functionality implemented by ContentControl, Control, FrameworkElement and UIElement classes.

Figure 2

When you create a WPF application in Visual Studio 2019, the designer adds a default Window named
MainWindow for you. The XAML code for the same is shown in Listing 1. The code in Listing 1 also sets
the Title, Height, and Width attributes of a Window.

<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"

161 @ C# Corner
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="250">
<Grid>

</Grid>
</Window>
Listing 1

The code-behind for the same is listed in Listing 2.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace HelloWPFSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{

public MainWindow()
{
InitializeComponent();
}
}
}
Listing 2

Creating a Window
1. Well, we have covered this part in chapter 1. Refer section “Designing User Interfaces at
compile/design time” from chapter 1.

Opening and Closing a Window


When a Window is created at run-time using the Window object, it is not visible unless we use the Show
or ShowDialog method.

162 @ C# Corner
Now we know that the Show method of Window class is responsible for displaying a window. To open a
window, you need to create an instance of the Window class and call its Show method. The following
code snippet creates an instance of Window1 class and calls its Show method.

Window1 window = new Window1();


window.Show();
Listing 3

The window opened with a Show method is a modeless window. That means you can freely switch to
other windows in the application without closing the current window. The ShowDialog method opens a
window as a modal window. That means when the current window is active, all other windows on the
application are deactivated. You cannot switch to other windows unless the current window is closed.

window.ShowDialog();

The close method of the Window class is used to close the window. The following code snippet calls the
Close method on the window object.

window.Close();

Besides using the close method, there is some built-in mechanism to close a window. You can close a
window by using the Close menu item pressing ALT+F4 or pressing a Close button. Dialog boxes are
usually closed after an action button is clicked.

Window Icon
An Icon is a bitmap image (.ico file) that is displayed in the top left corner of a Window. Visual Studio
designer allows you to create your icon images. To add an icon to a project, right-click on the project
name in Solution Explorer. Which will open the Add-Items menu. Then select Add >> New Item.

Now on Installed Templates, select Icon File (see Figure 3) and click Add. This action adds Icon1.ico file
and opens the image editor.

163 @ C# Corner
Figure 3

In the image editor shown in Figure 4, you can design your icon the way you like. There are two icon
sizes available in the editor – 16x16 and 32x32.

Figure 4

164 @ C# Corner
The Icon attribute of Window is used to set Icon for a window. Listing 5 sets Icon1.ico file as an icon for
the following Window.

<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="250"
Icon="Icon1.ico">
<Grid>

</Grid>
</Window>
Listing 5

The output with the new icon looks like Figure 5.

Figure 5

The Icon property of Window class represents a window's icon at run-time. This property takes an
ImageSource variable. The following code snippet uses BitmapFrame.Create method to create an
ImageSource and sets the Icon property of a Window.

Uri iconUri = new Uri("pack://application:,,,/Icon1.ico", UriKind.RelativeOrAbsolute);


this.Icon = BitmapFrame.Create(iconUri);

Listing 6

Window Title
The window title is the text that appears in a window’s title bar. The following code snippet sets the title
of a Window at design-time in XAML.

<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

165 @ C# Corner
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="WPF Window Sample" Height="150" Width="250"
SizeToContent="WidthAndHeight">

Listing 7

Figure 6 is an output of Listing 7, where the highlighted part illustrates the title of the window.

Figure 6

The following code snippet sets the Title property of a Window at run-time. Which produces the same
output as Figure 6.
this.Title ="WPF Window Sample";

Window Sizing and Location


The window has properties to manage the size and location of a Window.

Width and Height

Width and Height properties represent the height and width of a window respectively.

Ok, let’s create a simple UI to understand this. The code in Listing 8 creates a Window with a Button,
TextBox, and ListBox elements on a Grid panel. If you notice, the Window element does not have Width
and Height attributes specified.

<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"
mc:Ignorable="d"
Title="WPF Window Sample"
Width="300" Height="200">
<Grid x:Name="MainGrid">
<Button x:Name="FirstButton"
Content="Button"

166 @ C# Corner
Height="32"
HorizontalAlignment="Left"
Margin="120,10,0,0"
VerticalAlignment="Top"
Width="80" />
<TextBox x:Name="TextBoxUserInput"
Height="32"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="102" />
<ListBox x:Name="ListBoxListOfItems"
Background="LightBlue"
Height="97"
HorizontalAlignment="Left"
Margin="10,50,0,0"
VerticalAlignment="Top"
Width="190"/>
</Grid>
</Window>

Listing 8

The output of Listing 8 produces Figure 7. So if we do not specify a height and width properties, WPF
creates a window with default size, and the default size of the window is very large and the position is
centralized.

Figure 7

You can still resize the window using resize-grip on the right-bottom corner. After resizing the window it
looks like Figure 8.

167 @ C# Corner
Figure 8

Same can be achieved by setting the Height and Width properties of a Window.
Height="250" Width="250"

MinHeight, MaxHeight, MinWidth, and MinHeight

The MinHeight property of an element specifies the minimum height of an element. If you set Height
property less than this value, it will be considered as MinHeight. The MaxHeight property of an element
specifies the maximum height of an element. If you set a Height property greater than this value, it will
be considered as MaxHeight.

The MinWidth property of an element specifies the minimum width of an element. If you set the Width
property less than this value, it will be considered as MinWidth. The MaxWidth property of an element
specifies the maximum width of an element. If you set the Width property greater than this value, it will
be considered as MaxWidth.

ActualHeight property of an element gets the actual rendered height of an element after calculating
MinHeight, MaxHeight, and Height properties. ActualWidth property of an element gets the actual
rendered width of an element after calculating MinWidth, MaxWidth, and Width properties.

Note: MinWidth, MinHeight, MaxWidth, and MaxHeight properties are useful when you want to restrict
your application‘s interfaces to a specific width and height.

Left and Top

Left and Top properties represent the left and top position of the window relative to the desktop.

Now let’s set Width, Height, Left, and Top attributes. As you can see from the following code snippet,
Width, Height, Left, and Top properties are set to 300, 200, 500, and 500 respectively.

<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"

168 @ C# Corner
mc:Ignorable="d"
Title="WPF Window Sample"
Width="300" Height="200" Left="500" Top="500">

Listing 9

Now if you build and run the project, you will see Windows has a fixed size of 300x200 and location
would be at the bottom of the screen as shown in Figure 9.

Figure 9

TopMost and Z-Order

Z-order determines the vertical position of a window concerning other windows. There are two
types of z-order: normal z-order and topmost z-order. The location of a window in the normal z-
order is determined based on whether it is currently active or not. By default, a window is
located in the normal z-order. The location of a window in the topmost z-order is also
determined based on whether it is currently active or not. Furthermore, windows in the
topmost z-order are always placed above other windows in the normal z-order.

A window is placed in the topmost z-order by setting its Topmost property to true.
<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"
mc:Ignorable="d"

169 @ C# Corner
Title="WPF Window Sample"
Width="300" Height="200" Left="500" Top="500"
Topmost="True">
Listing 10

If you have multiple windows opened in the same application, you will see the current window is always
on top.

SizeToContent

SizeToContent property indicates how a window will automatically resize itself to fit the size of its
content. This property accepts the enumeration which has four values – Manual, Width, Height, and
WidthAndHeight.

● When SizeToContent is set to WidthAndHeight, the values of Height or Width properties stay
ineffective.
● When SizeToContent is set to Height, then setting Height does not change the height of the
window.
● When SizeToContent is set to Width, then setting Width does not change the width of the
window.
● When SizeToContent is set to Manual, then the size of the window is determined by other
properties including Width, Height, MaxWidth, MaxHeight, MinWidth, and MinHeight.

The following code snippet sets the SizeToContent to WidthAndHeight.

<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"
mc:Ignorable="d"
Title="WPF Window Sample"
Width="300" Height="200" Left="500" Top="500"
SizeToContent="WidthAndHeight">
Listing 11

Now if you build and run the application, your output would look like Figure 10 where you can see the
size of Window has nothing to do with its Width and Height properties but it is the same as the size of
content controls on Window.

170 @ C# Corner
Figure 10

The following code snippet sets the SizeToContent property to WidthAndHeight at run-time.
this.SizeToContent = System.Windows.SizeToContent.WidthAndHeight;

WindowStartupLocation

WindowStartupLocation property specifies the position of the window when it is loaded. The value of
WindowStartupLocation property is a type of WindowStartupLocation enumeration. It has three values
– Manual, CenterScreen, and CenterOwner. If it is set to Manual; then the startup location of a Window
has to be set using Top and Left properties. If it is set to CenterScreen; then the startup location of a
Window is the center of the screen that contains the mouse cursor. If it is set to CenterOwner; then the
startup location of a Window is the center of the Window that owns it, as specified by the
Window.Owner property.

The following code snippet sets the WindowStartupLocation property to CenterScreen at design-time in
XAML.

<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"
mc:Ignorable="d"
Title="WPF Window Sample"
Width="300" Height="200" Left="500" Top="500"
WindowStartupLocation="CenterScreen">

Listing 12

The following code snippet sets the WindowStartupLocation property to CenterScreen at run-time.

171 @ C# Corner
this.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;

Modal Window
If we use the Show method to open a window from another window then there is no relationship
established between 2 windows, both windows can be activated or deactivated independently that
means you can switch windows back and forth. There could be scenarios when you do now want to
switch windows unless some action is taken on the currently active window. This can be achieved by
setting the Owner property to the parent Window.

Owner property of the Window class represents the owner of a Window.

Let’s say, we have two Windows in an application. The first window is MainWindow and the second
window is ModalWindow, which will be shown when a button on MainWindow is clicked. The button
click event handler is shown in Listing 13 where we are creating an instance of ModalWindow and calling
its Show method.

private void ModalWindowButton_Click(object sender, RoutedEventArgs e)


{
ModalWindow childWindow = new ModalWindow();
childWindow.Show();
}
Listing 13

Now if you run the application and click on the Modal Window button, the output would look like Figure
8 where we can activate whichever window we want.

Figure 11

172 @ C# Corner
let’s change our Listing 13 code to Listing 14 by setting the Owner property of ModalWindow to
MainWindow.

private void ModalWindowButton_Click(object sender, RoutedEventArgs e)


{
ModalWindow childWindow = new ModalWindow();
childWindow.Owner = this;
childWindow.Show();
}
Listing 14

Now if you build and run the application, you will notice that you won’t be able to activate MainWindow
unless you close ModalWindow. As shown in Figure 12

Figure 12

Window States
A Window has three states: normal, maximized, and minimized. The normal state is the default
state where a window can be moved and resized if it is resizable.

WindowState property is used to set a window state. The following code snippet sets the
WindowState property to maximized at design-time in XAML. Even the Width and Height of
Window has been set in the code below but it won’t matter if the window is in maximized
state.
<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="WPF Window Sample"

173 @ C# Corner
Height="300" Width="400"
WindowState="Maximized">
Listing 15

The following code snippet sets the WindowState property to maximized at run-time.
this.WindowState = WindowState.Maximized;
If WindowState is set to “Maximized” then that window will open in a full screen unless
MaxWidth, MaxHeight, and SizeToContent properties are set. If these properties are set, then
the maximum size of a window is decided by these properties. But if the Height property is set
then it is overridden to full screen. Figure 13, shows how the window would look if it is in a
maximized state.

Figure 13

If WindowState is set to “Minimized” then it collapses to its taskbar’s instance. But there is one
condition. There is one more property named ShowInTaskbar.

The ShowInTaskbar property decides whether the window should be visible in the taskbar or
not. If set to true, a window will be shown in the taskbar when minimized. If it is set to false,
then the window will be minimized in the left bottom corner of the screen.

The following code snippet shows how to set the ShowInTaskBar property at design-time in
XAML.
<Window x:Class="WindowSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window"
Width="432" Height="210"
ShowInTaskbar="False" />
Listing 16

174 @ C# Corner
The following code snippet sets the ShowInTaskBar property to false at run-time.
this.ShowInTaskbar = false;
Highlighted icon in Figure 14 shows an application’s instance on taskbar, if the window is in a
minimized state and ShowInTaskbar is true then this is where you can find your application.

Figure 14

Whereas the highlighted part in Figure 15 shows an application’s instance on the bottom-left
side of the desktop if the window is in minimized state and ShowInTaskbar is false.

Figure 15

Window Resize Mode


The ResizeMode property is used to resize the window. ResizeMode property accepts
enumeration of ResizeMode that has the following four values.

● NoResize – A window cannot be resized.

● CanMinimize – A window can only be minimized and restored to its previous state.

● CanResize – A window can be resized.

● CanResizeWithGrip – A window can be resized with a resize grip.

Note: The window in minimized or maximized state cannot be resized.

The code snippet in Listing 17 sets the ResizeMode property to CanResizeWithGrip at design-
time in XAML.
<Window x:Class="WindowSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window"
Width="432" Height="210"
ResizeMode="CanResizeWithGrip" />

Listing 17

The following code snippet sets the ResizeMode property to CanResizeWithGrip at run-time.

this.ResizeMode = ResizeMode.CanResizeWithGrip;

175 @ C# Corner
Window Border Style
The WindowStyle property is used to manage the border style of a window. It is a type of
WindowStyle enumeration and has the following values.

● None

● SingleBorderWindow – This is the default value.

● ThreeDBorderWindow

● ToolWindow

The Code snippet in Listing 18 sets the WindowStyle property to SingleBorderWindow at


design-time in XAML.
<Window x:Class="WindowSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window"
Width="432" Height="210"
ResizeMode="CanResizeWithGrip" />

Listing 18

The following code snippet sets the WindowStyle property to SingleBorderWindow at run-time.
this.WindowStyle = System.Windows.WindowStyle.ThreeDBorderWindow;

Transparent and Non-Rectangular Shaped Windows


The window could be of any shape such as a drawing, a fruit, a stereo player and so on.

In Windows Forms, to create non-rectangular shaped Forms, we used to create a Path and then had to
set the Path property. Creating non-rectangular interfaces in WPF is simpler than Windows Forms. We

176 @ C# Corner
just have to set the AllowsTransparency property of a Window to True, Background to Transparent and
WindowStyle to none. After that whatever you place on that Window will not have a background.

<Window x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="WPF Window Sample"
AllowsTransparency="True"
Background="Transparent"
WindowStyle="None">

</Window>
Listing 19

So let’s say we need to create a user interface that looks like Figure 16. We simply have to create a Path
and place it on a transparent Window. That will do the trick.

Figure 16

The complete code of Figure 16 is shown in Listing 20.

<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

177 @ C# Corner
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"
mc:Ignorable="d"
Title="WPF Window Sample"
AllowsTransparency="True"
Background="Transparent"
MouseLeftButtonDown="Window_MouseLeftButtonDown"
WindowStyle="None">
<Canvas x:Name="RootLayout"
Height="400"
Width="400">

<Path x:Name="UIPath"
Stroke="Gray"
StrokeThickness="2">
<Path.Fill>
<LinearGradientBrush
StartPoint="0.2,0"
EndPoint="0.8,1">
<GradientStop
Color="Green"
Offset="0" />
<GradientStop
Color="Yellow"
Offset="0.35" />
<GradientStop
Color="Orange"
Offset="0.65" />
<GradientStop
Color="Red"
Offset="0.85" />
</LinearGradientBrush>
</Path.Fill>

<Path.Data>
<PathGeometry >
<PathFigure
StartPoint="50,100">
<ArcSegment
Size="150,150"
RotationAngle="45"
IsLargeArc="True"
SweepDirection="CounterClockwise" Point="100,50" />
<LineSegment Point="20,20"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Label x:Name="DragDropLabel"
Content=" Drag Me and Watch!"
FontFamily="Georgia"
FontSize="20"
FontWeight="Bold"
Foreground="Blue"
Height="68"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Width="226"
Canvas.Left="60"

178 @ C# Corner
Canvas.Top="127" />
<Button x:Name="CloseButton"
Click="CloseButton_Click"
Height="0"
ToolTip="Click me to close the form."
Width="0"
Canvas.Left="206"
Canvas.Top="42">
<Button.Template>
<ControlTemplate>
<Canvas>
<Rectangle
Height="20"
RadiusX="2"
RadiusY="2"
Stroke="DarkBlue"
Width="20">
<Rectangle.Fill>
<SolidColorBrush x:Name="myAnimatedBrush"
Color="Blue" />
</Rectangle.Fill>
</Rectangle>
<Line X1="3" Y1="3" X2="17" Y2="17"
Stroke="White"
StrokeThickness="2"/>
<Line X1="17" Y1="3" X2="3" Y2="17"
Stroke="White"
StrokeThickness="2"/>
</Canvas>
</ControlTemplate>
</Button.Template>
</Button>
<Button x:Name="BlackNWhiteButton"
Background="Crimson"
Content="Black and White"
Click="BlackNWhiteButton_Click"
FontWeight="Bold"
Foreground="White"
Height="30"
Width="112"
Canvas.Left="131"
Canvas.Top="272"/>
</Canvas>
</Window>
Listing 20

Now, we need to write the logic for event-handlers in code-behind. One is for the left mouse button
click event-handler which enables dragging functionality on the Window, this can be achieved with the
DragMove method of the Window. The Close button click event-handler simply closes the Window. On
Black and White button click event-handler, we can change the background of the Window to black and
white color gradient.

using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

179 @ C# Corner
namespace ChapterFour_PartTwo_Windows_Pages_Dialogs
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
/// <summary>
/// MouseLeftButtonDown
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
/// <summary>
/// CloseButton_Click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
/// <summary>
/// BlackNWhiteButton_Click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BlackNWhiteButton_Click(object sender, RoutedEventArgs e)
{
// Create a linear gradient brush with five stops
LinearGradientBrush blacknwhiteBrush = new LinearGradientBrush();
blacknwhiteBrush.StartPoint = new Point(0, 0);
blacknwhiteBrush.EndPoint = new Point(1, 1);
// Create and add Gradient stops
GradientStop blackGS = new GradientStop();
blackGS.Color = Colors.Black;
blackGS.Offset = 0.0;
blacknwhiteBrush.GradientStops.Add(blackGS);
GradientStop whiteGS = new GradientStop();
whiteGS.Color = Colors.White;
whiteGS.Offset = 1.0;
blacknwhiteBrush.GradientStops.Add(whiteGS);
UIPath.Fill = blacknwhiteBrush;
}
}
}
Listing 20

180 @ C# Corner
Clicking the Black and White button changes the Window that looks like Figure 17.

Figure 17

Deactivating a Window
As soon as the Show method of a Window is called, the activated-event is raised then the current
window remains activated until the user switches to another window.

If you do not want a window to be activated when the Show method is called, you can set
ShowActivated property to false. The default value of ShowActivated is true.

Window Events
Understanding a Window event is very significant and helps you put the right code at the right place. For
example, you may want to initialize window’s variables before anything else and you may want to load
data for a window when the window is loaded and so on.

Figure 18 illustrates the events in a Window’s life cycle and helps us understand which event is fired in
what order.

181 @ C# Corner
Figure 18

First Loaded event is fired when a window is initiated. If you can write the code which is necessary while
the window is loading then this is the right place. If you have some logic for fetching data which will be
shown on UI, you can call it here as well.

The ContentRendered event is fired when a Window’s contents are rendered.

The Activated event occurs when a window becomes the foreground window.

To get an idea of which event is fired in what order, we have implemented window events and placed a
MessageBox for each event. Here is a list of major events and their order.

1. Initiated
2. LocationChanged
3. Loaded
4. ContentRendered
5. SizeChanged
6. ContentRendered
7. SourceInitiated
8. ContentRendered
9. Activated
10. Closing
11. Deactivated
12. Unloaded

182 @ C# Corner
13. Closed

The code in Listing 21 shows xaml for windows events.

<Window x:Class="ChapterFour_PartTwo_Windows_Pages_Dialogs.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFour_PartTwo_Windows_Pages_Dialogs"
mc:Ignorable="d"
Title="WPF Window Sample"
Loaded="Window_Loaded"
ContentRendered="Window_ContentRendered"
Activated="Window_Activated"
Closed="Window_Closed"
Closing="Window_Closing"
Deactivated="Window_Deactivated"
Initialized="Window_Initialized"
LayoutUpdated="Window_LayoutUpdated"
LocationChanged="Window_LocationChanged"
SizeChanged="Window_SizeChanged"
SourceInitialized="Window_SourceInitialized"
StateChanged="Window_StateChanged"
SourceUpdated="Window_SourceUpdated"
Unloaded="Window_Unloaded"
Height="200" Width="300">
<Grid>
</Grid>
</Window>
Listing 21

The code in Listing 22 shows which event is fired in what order.

using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

namespace ChapterFour_PartTwo_Windows_Pages_Dialogs
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
/// <summary>
/// Window_Loaded
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>

183 @ C# Corner
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MessageBox.Show("Window_Loaded");
}
/// <summary>
/// Window_ContentRendered
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_ContentRendered(object sender, EventArgs e)
{
MessageBox.Show("Window_ContentRendered");
}
/// <summary>
/// Window_Activated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Activated(object sender, EventArgs e)
{
MessageBox.Show("Window_Activated");
}
/// <summary>
/// Window_Closed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Closed(object sender, EventArgs e)
{
MessageBox.Show("Are you sure?");
}
/// <summary>
/// Window_Closing
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs
e)
{
MessageBox.Show("Window_Closing");
}

/// <summary>
/// Window_Deactivated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Deactivated(object sender, EventArgs e)
{
MessageBox.Show("Window_Deactivated");
}
/// <summary>
/// Window_Initialized

184 @ C# Corner
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Initialized(object sender, EventArgs e)
{
MessageBox.Show("Window_Initialized");
}
/// <summary>
/// Window_LayoutUpdated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_LayoutUpdated(object sender, EventArgs e)
{
MessageBox.Show("Window_ContentRendered");
}
/// <summary>
/// Window_LocationChanged
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_LocationChanged(object sender, EventArgs e)
{
MessageBox.Show("Window_LocationChanged");
}
/// <summary>
/// Window_SizeChanged
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
MessageBox.Show("Window_SizeChanged");
}
/// <summary>
/// Window_SourceInitialized
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_SourceInitialized(object sender, EventArgs e)
{
MessageBox.Show("Window_SourceInitialized");
}
/// <summary>
/// Window_StateChanged
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_StateChanged(object sender, EventArgs e)
{
MessageBox.Show("Window_StateChanged");
}

185 @ C# Corner
/// <summary>
/// Window_SourceUpdated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_SourceUpdated(object sender, DataTransferEventArgs e)
{
MessageBox.Show("Window_SourceUpdated");
}
/// <summary>
/// Window_Unloaded
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Unloaded(object sender, RoutedEventArgs e)
{
MessageBox.Show("Window_Unloaded");
}
}
}
Listing 22

186 @ C# Corner
Pages
Unlike Windows Forms, WPF supports browser-enabled Windows client and Web applications. In a
browser-enabled Window client application, the application runs on a system as an executable
assembly. The only difference is that the application uses a browser to display the user interface and
provides browser navigation functionality.

A typical browser-enabled WPF application looks like Figure 19. As you can see, the application opens in
a Web browser which can be Mozilla Firefox or any other browser.

Figure 19

A Browser window has three parts – Header, footer, and content area.

The header area has menus, buttons, and a navigation bar. Footer has a status bar and UI depends on
the type of browser running on a machine. The centre area between the header and footer is the
content area. This is where your user interface will be displayed.

In WPF, a Page hosts browser application’s content that can be supported by a Web Browser,
NavigationWindow, and Frame.

Page element in XAML represents a page at design-time. The Page class in WPF represents a page at
run-time.

187 @ C# Corner
When you create a WPF browser application in Visual Studio 2019, the designer adds a default Page
called Page1. The XAML code in the designer looks like Listing 23. You will notice that it also sets the
Title and Content attributes of a Page. By default, a Grid panel is placed as the contents of a Page.
<Page x:Class="ChapterFour_PartTwo_WebBrowser.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ChapterFour_PartTwo_WebBrowser"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="Page1">
<Grid>
</Grid>
</Page>
Listing 23

The x:Class attribute specifies the name of the code-behind file. The code-behind .cs file is listed in
Listing 24 where you can see the first few lines of code are nothing but namespaces that are required in
a Browser enabled WPF application.
using System.Windows.Controls;
namespace ChapterFour_PartTwo_WebBrowser
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
}
}

Listing 24

Changing Startup Page


Now we know that after creating a WPF browser application in Visual Studio, it adds and sets
Page1.xaml to default. If you open the App.xaml file, you will see Application.StartupUri is set to
Page1.xaml. If you would like to change the default startup page, just change this attribute. The code
snippet in Listing 25 shows how you can change the default page to MyFirstPage.xaml.

<Application x:Class="WpfBrowserApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfBrowserApp1"
StartupUri="MyFirstPage.xaml">

188 @ C# Corner
<Application.Resources>

</Application.Resources>
</Application>

Listing 25

Creating a Page
There are three ways to design a Page – XAML, XAML with code-behind, or just code-behind, Same as
any other WPF application. In most of the cases, we use a mix of both XAML and code-behind and
usually design a Page in XAML at design-time and manage its properties and methods in code-behind.
Listing 26 creates a Page using XAML at design-time.

<Page x:Class="ChapterFour_PartTwo_WebBrowser.MyFirstPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ChapterFour_PartTwo_WebBrowser"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
WindowTitle="Window Title"
Height="250" Width="400">
<Page.Content>Hello WPF Browser Application</Page.Content>
</Page>

Listing 26

The code snippet in Listing 27 creates a Page and sets its properties dynamically.

private void CreateDynamicPage()


{
Page dynamicPage = new Page();
dynamicPage.Name = "FirstBrowserPage";
dynamicPage.Title = "Dynamic Page";
}
Listing 27

Page Properties
The Background and Foreground properties specify the background color and foreground color of a
Page respectively. The FontFamily and FontSize properties specify font family and font size respectively.

When a page is first navigated to, a new instance of the Page class is created. During the navigation
process, the current page’s instance is removed and a URI for the new page is added to the navigation
history. When a Browser moves back to a previous page, the URI of the old page is referenced and a

189 @ C# Corner
Page’s instance is created again. This creation of a page may take a while. If you would like to retain the
Page object in an application, you can do so by setting property KeepAlive to true. By default, this
property is set to false to avoid unnecessary use of memory and resources.

Title property represents the title of a Page. The WindowTitle property represents the title of the host
Window or NavigationWindow of the Page. If you wish to show the title in the Browser, you need to use
the WindowTitle property.

The WindowHeight and WindowWidth properties specify the height and width of a browser window. By
default, a Browser opens a Page in full-screen or the last size and position of the Browser. The Height
and Width property of Page represents the height and width of the page contents area.

The code listed in Listing 28 sets the Page properties.

<Page x:Class="ChapterFour_PartTwo_WebBrowser.MyFirstPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ChapterFour_PartTwo_WebBrowser"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
WindowTitle="Window Title"
Height="250" Width="400"
WindowHeight="300" WindowWidth="400"
Background="LightBlue" Foreground="DarkBlue"
FontFamily="Verdana" FontSize="24"
KeepAlive="True"
Name="FirstBrowserPage" >
<Page.Content>Hello WPF Browser Application</Page.Content>
</Page>
Listing 28

When you run the application, you will see the browser window looks like Figure 20.

190 @ C# Corner
Figure 20

The code snippet in Listing 29 sets Page properties at run-time.

private void CreateDynamicPage()


{
Page dynamicPage = new Page();
dynamicPage.Name = "FirstBrowserPage";
dynamicPage.Title = "Page Title";
dynamicPage.Background = new SolidColorBrush(Colors.LightBlue);
dynamicPage.Foreground = new SolidColorBrush(Colors.DarkBlue);
dynamicPage.Width = 500;
dynamicPage.Height = 300;
dynamicPage.FontFamily = new FontFamily("Verdana");
dynamicPage.FontSize = 12;
dynamicPage.WindowWidth = 400;
dynamicPage.WindowHeight = 300;
dynamicPage.WindowTitle = "Window Title";
dynamicPage.KeepAlive = true;
}
Listing 29

Page Content
The Content property of Page specifies Page content. This property can host only one element as the
root element. You will notice in Listing 27, that when you create a WPF Browser application using Visual
Studio, the default content of a Page is a Grid panel that acts as a container for other children elements.
We can also set the Page content using the following format.

<Page.Content>Hello WPF Browser Application</Page.Content>

191 @ C# Corner
To create user interfaces, we can simply place a panel inside a Page and then this panel element will be
used to host the rest of the child elements. For example, in the code snippet in Listing 30, we place a
Grid panel and then we place a Button, TextBox and ListBox controls in the Grid panel.

<Page x:Class="ChapterFour_PartTwo_WebBrowser.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ChapterFour_PartTwo_WebBrowser"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
Title="Page1">
<Grid x:Name="GridRoot">
<Button x:Name="AddItemButton"
Content="Add Item"
HorizontalAlignment="Left"
Height="43"
Margin="197,37,0,0"
VerticalAlignment="Top"
Width="120" />
<TextBox x:Name="TextBoxItems"
HorizontalAlignment="Left"
Height="44"
Margin="24,37,0,0"
TextWrapping="Wrap"
Text="TextBox"
VerticalAlignment="Top"
Width="159"/>
<ListBox x:Name="ListBoxItems"
HorizontalAlignment="Left"
Height="145"
Margin="24,103,0,0"
VerticalAlignment="Top"
Width="290"/>
</Grid>
</Page>
Listing 30

The output of Listing 29 looks like Figure 21. As you can see the child element such as Button has
inherited FontSize and FontFamily properties from the Page element.

192 @ C# Corner
Figure 21

193 @ C# Corner
Navigation
A WPF Browser application is usually a combination of more than one page. The process of moving from
one page to another and going back and forth is called navigation. Navigation in WPF is supported using
four different methods.

● Hyperlink
● Fragment
● NavigationService
● NavigationWindow

WPF supports navigation in both WPF Browser Applications and Windows Standalone Applications.
Navigation in WPF Browser Applications is supported using Hyperlinks, Fragment, and
NavigationService. While navigation in Windows Standalone Applications is usually supported by
NavigationWindow.

Hyperlink Navigation
A hyperlink is the simplest way to navigate from one page to another. The Hyperlink element in XAML is
used to create a hyperlink. The NavigateUri attribute of Hyperlink is used to set the URI of the page
where a hyperlink click would navigate to. The code snippet in Listing 31 creates a hyperlink to navigate
from a page to Page2.xaml.

<Hyperlink NavigateUri="Page2.xaml">
Navigate to Page2
</Hyperlink>
Listing 31

Fragmented Navigation
WPF supports named element navigation. That means we can navigate to elements in WPF pages using
their Name attribute. Named element navigation can be applied within the same page or any other
pages within the same application. The following syntax is used for fragmented navigation.

PageURI#ElementName

For example, if you have a page in a WPF application named Page2 and it has a TextBox with Name
attribute set to TextBox1. Then to navigate to TextBox1 on Page2 from anywhere within the application,
we can use set the NavigateUri attribute of Hyperlink as per the following syntax:

NavigateUri="Page2.xaml#TextBox1"

The code snippet in Listing 32 creates a hyperlink and sets its NavigateUri to an element.

<Hyperlink NavigateUri="Page2.xaml#TextBox1">
Navigate to TextBox1 on Page2
</Hyperlink>

194 @ C# Corner
Listing 32
NavigationService Navigation
WPF Hyperlink element internally uses NavigationService to navigate from one page to another. The
NavigationService class is used to create and support navigation functionality. NavigationService is
defined in the System.Windows.Navigation namespace.

The GetNavigationService method gets a reference to the NavigationService for the navigator. The
page also has a NavigationService property that returns the NavigationService for that page.

The code snippet in Listing 33 creates a NavigationService for a page.

NavigationService nvs = NavigationService.GetNavigationService(this);

NavigationService nvs1 = this.NavigationService;

Listing 33

Navigation

Source property of NavigationService is used to get and set the URI of the content that is currently being
navigated or displayed. NavigationService can also be used to display contents stored in objects. The
content property represents the current contents that are being displayed.
ContentSource property represents the URI that was last navigated to.

Navigate method is used to navigate asynchronously to the specified source content. The Navigate
method can take an object, a URI

The code snippet in Listing 34 navigates to Page2.xaml URI from the current page.

NavigationService nvs = NavigationService.GetNavigationService(this);


nvs.Navigate(new Uri("Page2.xaml", UriKind.Relative));

Listing 34

Moving Back and Forward

CanGoBack property indicates if there is at least one entry in “back navigation history”.
CanGoForward property indicates if there is at least one entry in the “forward navigation history”.

GoBack method navigates to the most recent entry in “back navigation history” if there is one.
The GoForeward method navigates to the most recent entry in the “forward navigation history” if there
is one.

When you navigate from page to page, the previous page is automatically added to the navigation
history. Adding and removing contents to the navigation history can be coded manually too. The
AddBackEntry method adds an entry to “back navigation history” that contains a CustomContentState
object. The RemoveBackEntry method removes the most recent journal entry from “back history”.

195 @ C# Corner
The code snippet in Listing 35 creates a NavigationService and uses GoBack and GoForeward method to
move back and forward in the navigation history.

NavigationService nvs = NavigationService.GetNavigationService(this);


if (nvs.CanGoBack)
nvs.GoBack();
if (nvs.CanGoForward)
nvs.GoForward();
Listing 35

Refresh and Stop Page Loading

The Refresh method reloads the current content of a NavigationService. The code snippet in Listing 36
creates a NavigationService and calls its Refresh method to refresh the page contents.

NavigationService nvs = NavigationService.GetNavigationService(this);


nvs.Refresh();
Listing 36

The StopLoading method stops further downloading of content for the current navigation request. The
code snippet in Listing 37 creates a NavigationService and calls its StopLoading method.

NavigationService nvs = NavigationService.GetNavigationService(this);


nvs.StopLoading();
Listing 37

NavigationWindow
NavigationWindow is used to add navigation functionality to Windows Standalone applications. A
NavigationWindow can be used as an applications container Window or a dialog box, depending on the
requirements of an application.

Create NavigationWindow

Similar to a Window, a NavigationWindow supports both XAML and code-behind models.

Let’s create a NavigationWindow based application.

First, create a WPF Application using Visual Studio 2019.

Once the application is created, open MainWindow.xaml and change the Window root element to
NavigationWindow element. The XAML of MainWindow then looks like Listing 38.

<NavigationWindow x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

196 @ C# Corner
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="WPF Window Sample">
<Grid>

</Grid>
</NavigationWindow>

Listing 38

As soon as the Window element is changed to NavigationWindow, the designer shoots the following
error as shown in Figure 22. That means we cannot set the direct content of a NavigationWindow.

Figure 22

Just remove the Grid element from the XAML.

Next, we need to inherit MainWindow from NavigationWindow by changing Window to


NavigationWindow. The MainWindow class would look like Listing 39.

public partial class MainWindow : NavigationWindow


{
public MainWindow()
{
InitializeComponent();
}
}
Listing 39

Now if you build and run the application, the new UI would look like Figure 23 that has navigation
controls on the Window.

197 @ C# Corner
Figure 23

Properties and Methods

The Source property specifies the source that is currently being navigated or displayed to. The code
snippet in Listing 40 sets the Source attribute of NavigationWindow to a URL http://www.c-
sharpcorner.com.

<NavigationWindow x:Class="HelloWPFSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWPFSample"
mc:Ignorable="d"
Title="WPF Window Sample"
Source="https://www.c-sharpcorner.com/">
</NavigationWindow>
Listing 40

The output of Listing 39 looks like Figure 24 that shows the C# Corner home page in the
NavigationWindow.

198 @ C# Corner
Figure 24

Navigate method is used to navigate asynchronously to the specified source content. The Navigate
method can take an object or a URI. The code snippet in Listing 41 navigates to Page2.xaml URI from the
current page.

NavWindow.Navigate(new Uri("Page2.xaml", UriKind.Relative));

Listing 41

199 @ C# Corner
Frame
A NavigationWindow or a Page can contain a smaller navigation window within itself with the help of
Frame. This is helpful when we wish to refresh only some part of a screen. For example, take any sports
website which shows sport related news. They might add a dynamic section in one corner which shows
you the live score; this section refreshes itself with some time interval.

The Frame element in XAML specifies frame at design-time and Frame class represents a frame at run-
time. Similar to a Page or NavigationWindow, a Frame has its navigation controls and options.

The following code snippet creates a Frame in XAML at design-time and sets its Source,
JournalOwnership, and NavigationUIVisibility properties. The Source property represents the content
of a Frame. Page2 will be displayed within the frame of Page1. The NavigationUIVisibility property
specifies if navigation controls are visible or hidden. It has three values – Visible, Hidden, and Automatic.

<Frame Margin="14,106,145,12" Name="Frame1"


Source="Page2.xaml"
JournalOwnership="OwnsJournal"
NavigationUIVisibility="Hidden"/>

Listing 42

This code above creates a Frame within a Page and the UI of the same looks like Figure 25.

Figure 25

200 @ C# Corner
Properties and Methods
Navigate method is used to navigate asynchronously to the specified source. The Navigate method can
take an object or a URI as the first parameter. The code snippet in Listing 43 navigates to Page2.xaml URI
from the current page.

Frame1.Navigate(new Uri("Page2.xaml", UriKind.Relative));

Listing 43

It supports properties such as CanGoBack, CanGoForward, GoBack, GoForeward. And methods such as
Refresh and StopLoading are the same as NavigationService.

201 @ C# Corner
WPF Dialog Boxes
A Dialog Box is a popup represented by a Window in WPF. As we discussed in the Windows section of
this chapter, a Window can be modal or modeless. In this section, we will see common dialog boxes
available in WPF including MessageBox, OpenFileDialog, SaveFileDialog, and PrintDialog.

MessageBox Dialog
The purpose of a message box is to display an alert or a message. It even lets users have some options to
choose from. A simple message box has an OK button and it looks like Figure 26.

Figure 26

A message box can have a title and multiple options such as Yes, No, and Cancel. A message box can also
have some input control to accept input from a user.

MessageBox Class
The MessageBox class in WPF represents a modal message dialog box, which is defined in the
System.Windows namespace. The Show method of the MessageBox is the only method that is used to
display a message box. The Show method returns a MessageBoxResult enumeration that has values –
None, OK, Cancel, Yes, and No. We can use MessageBoxResult to find out what button was clicked on a
MessageBox and take appropriate action.

The Show method has 13 overloaded methods. Here are the code samples and the results of these
overloaded methods.

Simple MessageBox
A simple MessageBox shows a message and only has an OK button. Clicking on the OK button triggers
the MessageBox to close. The following line of code uses the Show method to display a message box
with a simple message.

MessageBoxResult result = MessageBox.Show("Hello MessageBox");

Listing 44

202 @ C# Corner
The MessageBox produced by Listing 43 is a modal dialog with an OK button on it, which looks like
Figure 27.

Figure 27

MessageBox with Title


A MessageBox can have a title. The first parameter of the Show method is a string parameter which is
used to display the text on the dialog box and the second parameter is the title string of the dialog. The
following code snippet creates a MessageBox with a message and a title.

MessageBoxResult result = MessageBox.Show("Hello MessageBox",


"Confirmation");

Listing 45

The output looks like Figure 28.

Figure 28

MessageBox with Owner


A MessageBox does not have an owner by default but you can specify an owner by setting the first
parameter. In this code, the first parameter is the current Window.

MessageBoxResult result = MessageBox.Show(this, "Hello MessageBox");

Listing 46

Output won’t have any difference.

203 @ C# Corner
Figure 29

MessageBoxButton Enumeration
The MessageBoxButton enumeration is responsible for showing various buttons on the dialog box. It has
the following values:

● OK – OK button is displayed.
● OKCancel – OK and Cancel buttons are displayed.
● YesNo – Yes and No buttons are displayed.
● YesNoCancel – Yes, No, and Cancel buttons are displayed.

MessageBox with Title, Yes and No Buttons

A MessageBox can be used to ask the user a question and showing options by providing Yes and No
buttons. Based on the user’s selection (Yes or No), you can execute the appropriate code. The third
parameter of the Show method is a MessageBoxButton enumeration. By simply passing
MessageBoxButton.YesNo in the third parameter creates a MessageBox with OK and Cancel buttons.

The following code snippet creates a MessageBox with a message, a title, and Yes and No buttons.

if (MessageBox.Show("Do you want to close this window?",


"Confirmation", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
// Close the window
}
else
{
// Do not close the window
}

Listing 47

The output looks like Figure 30.

204 @ C# Corner
Figure 30

MessageBox with Title, Yes, No and Cancel Buttons

The following code snippet creates a MessageBox with a message, a title, and buttons such as Yes, No,
and Cancel.

MessageBoxResult result = MessageBox.Show("Do you want to close this


window?",
"Confirmation", MessageBoxButton.YesNoCancel);
if (result == MessageBoxResult.Yes)
{
// Yes code here
}
else if (result == MessageBoxResult.No)
{
// No code here
}
else
{
// Cancel code here
}

Listing 48

The output looks like Figure 31.

Figure 31

205 @ C# Corner
MessageBox with Title, Icon, Yes and No Buttons

A MessageBox also allows you to place an icon that represents the message and comes with some built-
in icons. The MessageBoxImage enumeration represents an icon. Here is a list of MessageBoxImage
enumeration values that represent the relative icons.
● None
● Hand
● Question
● Exclamation
● Asterisk
● Stop
● Error
● Warning
● Information

The following code snippet creates a MessageBox with a message, a title, and Yes and No buttons with
an icon.

string message = "Are you sure?";


string caption = "Confirmation";
MessageBoxButton buttons = MessageBoxButton.YesNo;
MessageBoxImage icon = MessageBoxImage.Question;
if (MessageBox.Show(message, caption, buttons, icon) == MessageBoxResult.OK)
{
// OK code here
}
else
{
// Cancel code here
}

Listing 49

The output looks like Figure 32.

Figure 32

206 @ C# Corner
MessageBox with Title, Icon, OK, and Cancel Buttons

The following code snippet creates a MessageBox with a message, a title, warning icon, and two buttons
OK and Cancel.

MessageBoxResult result = MessageBox.Show(this, "If you close this window,


all data will be lost.",
"Confirmation", MessageBoxButton.OKCancel, MessageBoxImage.Warning);
if (result == MessageBoxResult.OK)
{
// Yes code here
}
else
{
// No code here
}

Listing 50

The output looks like Figure 33.

Figure 33

Mixing it

There are many more options. You can mix any of these options to show any kind of MessageBox that
you wish to display.

Customizing MessageBox
Even though it looks like WPF MessageBox is a part of System.Windows namespace, it is just a wrapper
of Win32 API and this is why you can’t use it at design-time in XAML or customize it. To customize a
MessageBox, you will be better off creating your Custom Control.

207 @ C# Corner
OpenFileDialog

The OpenFileDialog is used to browse files on a machine. The OpenFileDialog class is defined inside a
Microsoft.Win32.OpenFileDialog namespace. A typical OpenFileDialog looks like Figure 34.

Figure 34

To create and use an OpenFileDialog in a WPF application.


We need to begin with the UI, add a TextBox and a Button element to the XAML page. When you click
the button, it will open a browse dialog box as shown in Figure 34. Once you select a file to open we will
take the file name and set it to the TextBox’s Text property. Let’s filter out .txt files only. The XAML code
for the UI looks like Listing 51.

<TextBox x:Name="FileNameTextBox"
Height="32"
HorizontalAlignment="Left"
Margin="6,10,0,0"
VerticalAlignment="Top"
Width="393" />
<Button x:Name="BrowseButton"
Click="button1_Click"
Content="Browse"

208 @ C# Corner
Height="32"
HorizontalAlignment="Left"
Margin="405,10,0,0"
VerticalAlignment="Top"
Width="88"/>

Listing 51

The code snippet in Listing 52 creates an OpenFileDialog, set its default extension and filter properties
then calls ShowDialog method that opens the dialog. Once the OpenFileDialog is displayed, you can use
it to browse files. Once the file is selected, the FileName property of the OpenFileDialog is set to the
selected file name. This code sets the selected file name as a TextBox.Text property.

private void OpenFileDialog()


{
// Create OpenFileDialog
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
// Set filter for file extension and default file extension
dlg.DefaultExt = ".txt";
dlg.Filter = "Text documents (.txt)|*.txt";
// Display OpenFileDialog by calling ShowDialog method
Nullable<bool> result = dlg.ShowDialog();
// Get the selected file name and display in a TextBox
if (result == true)
{
// Open document
string filename = dlg.FileName;
FileNameTextBox.Text = filename;
}
}

Listing 52

209 @ C# Corner
SaveFileDialog
The SaveFileDialog class is defined inside a Microsoft.Win32 namespace, it represents a Windows Save
File Dialog control. A typical SaveFileDialog looks like Figure 35.

Figure 35

The following code snippet from Listing 53 creates a SaveFileDialog, sets its default extension and filter
properties then calls ShowDialog method that displays SaveFileDialog control.

private void SaveFileDialog()


{
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.DefaultExt = ".txt";
dlg.Filter = "Text documents (.txt)|*.txt";
if (dlg.ShowDialog() == true)
{
string filename = dlg.FileName;
}
}
Listing 53

210 @ C# Corner
PrintDialog
Windows PrintDialog allows users to select a printer from the available printers on the local machine as
well as on the network and set printer properties.

The PrintDialog is defined inside a System.Windows.Controls namespace and is used to create and call a
Windows PrintDialog. A typical Windows PrintDialog looks like Figure 36.

Figure 36

The following code snippet in Listing 54, creates a PrintDialog and launches it. This code also sets the
PageRangeSelection and UserPageRangeEnabled properties.
private void PrintDialog()
{
System.Windows.Controls.PrintDialog dlg = new System.Windows.Controls.PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;

Nullable<bool> result = dlg.ShowDialog();

if (result == true)
{
// Print document
}
}

Listing 54

We will see PrintDialog and print properties in more detail in our Printing chapter.

211 @ C# Corner
Chapter 5.1 Resources
WPF has redefined the way how resources are used in the applications. This chapter focuses on
implementing resources and using them in WPF applications using both XAML and as well as the code-
behind approach.

Resources are nothing but data in the form of files, objects, values such as brushes, fonts, and images
etc. The main purpose of using resources is sharing the same resource among multiple controls or
windows.

Resources are stored temporarily in a variable so that we can reuse them later when we need them. Just
like cached memory in the CPU. It stores frequently used data in the cache for faster access and it loads
data from the cache instead of fetching it from RAM or HDD.

Advantages

1. Re-usability: Just define it once in a common file and then use it in multiple XAML files.
2. Store data locally: You can define a resource in the same Window if usage scope is the same
window.
3. Global scope: Define resource-dictionary in App.xaml if the usage scope is an entire
application.
4. Panel or control specific: You can define it inside a panel such as Grid, Stack panel or
controls such as button, textbox etc.

Implementing Resources
Resources in WPF can be used in both ways – design-time using XAML and at run-time using code-
behind.

Design-time using XAML


In XAML, you can have Application-level resources, Window level resources or Panel level resources.
More on these later. The Resources property of Application or Window gets or sets a collection of
application-scope resources. In layman terms, it means we can define all the resources inside an
Application.Resources or Window.Resources respectively for an Application or a Window. By setting
Resources property on the application level, you make these resources available to an entire application.

Each resource must have a unique key which is defined using the x:Key attribute. For example, this code
snippet in Listing 1 adds a SolidColorBrush resource to the Application and the unique key for the
resource is x:Key="YellowSolidBrush".
<Application x:Class="WPFSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

212 @ C# Corner
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="App_Startup"
ShutdownMode="OnLastWindowClose">
<Application.Resources>
<SolidColorBrush x:Key="YellowSolidBrush" Color="Yellow"/>
</Application.Resources>
</Application>
Listing 1

Now this resource can be accessed by any Window or Control within the same application. A resource
can be referenced using a StaticResource. The StaticResource has the ability to store data that we define
as a resource. We will learn about StaticResource in more detail later in this chapter.

For example, if we want to use the resource YellowSolidBrush on the Background property of a
TextBlock control which could be part of any Window in the same application, then we can achieve this
by using StaticResource as shown in Listing 2.

<TextBlock x:Name="TextBlockYellow"
Background="{StaticResource YellowSolidBrush}"
Text="Main Window"/>

Listing 2

Run-time using code-behind


In WPF, resources can be referred at run-time as well. The Resources property of a FrameworkElement
is a type of ResourceDirectory which represents the resources at runtime. The Add method of
ResourceDirectory is used to add resources. The FindResource method of a FrameworkElement is used
to get the resources from the ResourceDirectory.

The code snippet in Listing 3 adds two resources YellowSolidBrush and GraySolidBrush to the
application. You can add resources to a Window or control.

/// <summary>
/// Adding colors Resources to Application
/// </summary>
private void AddResourcesToApplication()
{
Application curApp = Application.Current;
curApp.Resources.Add("YellowSolidBrush", new SolidColorBrush(Colors.Yellow));
curApp.Resources.Add("GrayBorderBrush", new SolidColorBrush(Colors.Gray));
}
Listing 3

The code snippet in Listing 4 uses the FindResource method to get the resources and returns a resource
as an object. Before you use the resource, you must convert it to an appropriate type. As you can see
from Listing 4, we have converted two resources to Brush types before setting them as Background and
BorderBrush of a Button control.
/// <summary>
/// Get Application Resources
/// </summary>

213 @ C# Corner
private void GetApplicationResources()
{
Application curApp = Application.Current;
ButtonYellow.Background = (Brush)curApp.FindResource("YellowSolidBrush");
ButtonYellow.BorderBrush = (Brush)curApp.FindResource("GrayBorderBrush");
}
Listing 4

We have 2 approaches (design-time and run-time), we can mix these 2 approaches and use resources
the way it suits in our applications. We are going to discuss this in more detail later in this chapter.

Scope of Resources
In WPF, we can define Resources on various levels and their scope of accessibility depends on the level
they are defined on. The following is the list of scope levels of resources.

● Application Resources
● Page or Window Resources
● Control Resources
● Local Resources

Each FrameworkElement such as a Window or Grid has its Resources property. Each resource is
associated with a unique key. Here we first need to understand the hierarchy, at lower level comes the
UI Element then its parent a Panel (Grid, Stack Panel etc.) followed by the Window and at last the
Application. We can use the same key for multiple resources. Let’s understand this with an example,
let’s create a resource called SolidBrushBackground on Application-level followed by Window, and Grid
level. The code snippet in Listing 5 creates a resource on the Application level.

<Application x:Class="ResourcesScopeSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<SolidColorBrush x:Key=" SolidBrushBackground" Color="Yellow"/>
</Application.Resources>
</Application>

Listing 5

The code snippet in Listing 6 creates a resource on Window and Grid level with same key name.

<Window x:Class="ResourcesScopeSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="SolidBrushBackground" Color="Yellow"/>
</Window.Resources>
<Grid x:Name="GridRoot">
<Grid.Resources>

214 @ C# Corner
<SolidColorBrush x:Key="SolidBrushBackground" Color="Green"/>
</Grid.Resources>
<Button x:Name="ButtonYellowColor"
Background="{StaticResource SolidBrushBackground}"
BorderThickness="1"
Content="Button"
Height="40"
VerticalAlignment="Center"
Width="200"/>
</Grid>
</Window>
Listing 6

The output of this would look like Figure 1. As you can see from Figure 1, the resource created on the
last level (Grid) is applied to the button that has a Green color brush. As it found a resource on the most
immediate level it did not go any further looking for a resource up in the hierarchy.

Figure 1

1.1 Application Resources


Application-level resources are defined in the application file and accessible within the entire application
from anywhere including Windows, Pages, and Controls.

Each WPF application has an App.xaml file. This file defines all the resources, events, and definitions on
the application level. The default App.xaml file looks like Listing 7. As you may see from Listing 7. You
may also notice Application.Resources attribute, this represents the resources defined on the
application level.

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

</Application.Resources>
</Application>

Listing 7

Note: You must define application-level resources when they are common to more than one Windows,
Pages, or Controls.

215 @ C# Corner
We have seen examples of application-level resources in Listing 1 and Listing 2.

1.2 Page or Window Resources


The Resources property of Window or Page represents one or more resources that would be available
for that Window or Page. The code snippet in Listing 8 creates a resource in XAML at design-time on a
Window level and accesses it by setting Background property of a Button control.
<Window x:Class="ResourcesScopeSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300">
<Window.Resources>
<SolidColorBrush x:Key="YellowSolidBrush" Color="Yellow"/>
</Window.Resources>
<Grid>
<Button x:Name="ButtonYellowBackground"
Background="{StaticResource YellowSolidBrush}"
BorderThickness="1"
Content="Button"
Height="40"
VerticalAlignment="Center"
Width="200" />
</Grid>
</Window>
Listing 8

In WPF, Window.Resources property represents resources on a Window level. The code snippet in
Listing 9 adds two resources YellowSolidBrush and GraySolidBrush to a Window and then uses these
resources to set the Background and BorderBrush of a Button control.
// Add Resources to a Window
this.Resources.Add("YellowSolidBrush", new SolidColorBrush(Colors.Yellow));
this.Resources.Add("GrayBorderBrush", new SolidColorBrush(Colors.Gray));
// Get and Set resources
ButtonYellowBackground.Background =
(Brush)this.FindResource("YellowSolidBrush");
ButtonYellowBackground.BorderBrush =
(Brush)this.FindResource("GrayBorderBrush");

Listing 9

1.3 Control/Panel Resources


In WPF, The Resource property of each control is used to define resources on a control level. The
resources added to a control are available to the control itself and its child controls. For example, if we

216 @ C# Corner
add some resources to a Grid, and then we place a Button and a TextBox inside a Grid, then resources
are available to the Grid as well as to the Button, and TextBox controls.

The code snippet in Listing 10 creates a resource in XAML at design-time for a Grid control and accesses
it by setting Background property of a Button control. The resource is defined using a Grid panel.

Note: Resources are available within the Grid element only.


<Grid x:Name="GridRoot">
<Grid.Resources>
<SolidColorBrush x:Key="YellowSolidBrush" Color="Yellow"/>
</Grid.Resources>
<Button Name=" ButtonYellowBackground"
Background="{StaticResource YellowSolidBrush}"
BorderThickness="1"
Content="Button"
Height="40"
VerticalAlignment="Center"
Width="200" />
</Grid>

Listing 10

In Listing 10, when the XAML loader processes the value {StaticResource YellowSolidBrush} for
the Background property on Button element, the resource lookup first checks the resource dictionary of
a Button element. If ResourceDictionary of Button element does not have a definition for
YellowSolidBrush key, then the lookup next checks its parent element, which is Grid in this case. If the
ResourceDictionary of Grid does not have a definition YellowSolidBrush key, the lookup next checks the
root element, that is Window element. Remember the hierarchy we talked about, it follows the tree till
it reaches the Application level and then it goes into system themes to look for the resources.

In WPF, Grid.Resources property specifies resources for a Grid. The code snippet in Listing 11 adds two
resources YellowSolidBrush and GraySolidBrush to a Grid and then uses these resources to set the
Background and BorderBrush of a Button control.
// Add Resources to a Grid
GridRoot.Resources.Add("YellowSolidBrush", new
SolidColorBrush(Colors.Yellow));
GridRoot.Resources.Add("GrayBorderBrush", new SolidColorBrush(Colors.Gray));
// Get and Set resources
ButtonYellowBackground.Background =
(Brush)Grid1.FindResource("YellowSolidBrush");
ButtonYellowBackground.BorderBrush =
(Brush)Grid1.FindResource("GrayBorderBrush");

Listing 11

1.4 Local Resources


Local resources are applicable to a specific control only. These are nothing but different properties used
for an element. For example, listing 12 adds multiple resources on a Button level.

217 @ C# Corner
<Button Name="ButtonYellowBackground"
Background="{StaticResource YellowSolidBrush}"
BorderThickness="1"
Content="Button"
Height="40"
Width="150"
VerticalAlignment="Top" />

Listing 12

Resource Dictionary
So far, we know that one can define resources on 4 different levels. But we can even define
resources into a separate xaml file which is called ResourceDictionary. This is useful when we want
to keep different resources in a different file. E.g. one ResourceDictionary will have resources
related to colors, others would have resources related to position, size etc. All the resources
defined inside ResourceDictionary are only processed when the application refers to that resource.
So it works on the request-process basis. To add ResourceDictionary into your project, Right-click on
a project and add a resource dictionary as shown in Figure 2.

Tip: Create a folder and name it styles so you can add all ResourceDictionaries inside this folder.

Figure 2

218 @ C# Corner
Figure 3

The code snippet in Listing 13 shows what ResourceDictionary looks like by default.

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ChapterFiveOne_Resources">
</ResourceDictionary>

Listing 13

Say we want to add 4 Solid colors in a resource dictionary, these 4 colors are nothing but 4 resources
that I want to use across the application. The code snippet in Listing 14 shows how code would look like
after adding 4 resources.

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ChapterFiveOne_Resources">
<SolidColorBrush x:Key="LightSalmonBrush" Color="LightSalmon"/>
<SolidColorBrush x:Key="LightGreenBrush" Color="LightGreen"/>
<SolidColorBrush x:Key="LightBlueBrush" Color="LightBlue"/>
<SolidColorBrush x:Key="LightGrayBrush" Color="LightGray"/>
</ResourceDictionary>

Listing 14

219 @ C# Corner
Once ResourceDictionary is ready you can use it as Application Level Resource or Window or Control
level resource.

To use it as Application-level simply add this ResourceDictionary in App.xaml

Following code snippet shows how to use ResourceDictionary.MergedDictionaries tag to add


ResourceDictionary into App.xaml

<Application x:Class="ChapterFiveOne_Resources.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ChapterFiveOne_Resources"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionaryColors.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Listing 15

If you want to keep your scope to your Window or UserControl, then update Window.Resources or
UserControl.Resources.

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionaryColors.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

Listing 16

Now Let’s apply these resources on different 4 buttons. Listing 17 shows the final code of the window
where we have integrated ResourceDictionaryColors into MainWindow and we are using
StaticResource to fetch each resource.

<Window x:Class="ChapterFiveOne_Resources.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ChapterFiveOne_Resources"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles\ResourceDictionaryColors.xaml"/>
</ResourceDictionary.MergedDictionaries>

220 @ C# Corner
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button x:Name="ButtonFirst"
Background="{StaticResource LightSalmonBrush}"
BorderThickness="1"
Height="40"
VerticalAlignment="Center"
Width="200"/>
<Button x:Name="ButtonSecond"
Background="{StaticResource LightGreenBrush}"
BorderThickness="1"
Height="40"
VerticalAlignment="Center"
Width="200"
Grid.Row="1"/>
<Button x:Name="ButtonThird"
Background="{StaticResource LightBlueBrush}"
BorderThickness="1"
Height="40"
VerticalAlignment="Center"
Width="200"
Grid.Row="2"/>
<Button x:Name="ButtonFourth"
Background="{StaticResource LightGrayBrush}"
BorderThickness="1"
Height="40"
VerticalAlignment="Center"
Width="200"
Grid.Row="3"/>
</Grid>
</Window>
Listing 17

Figure 4 is an output on Listing 17.

221 @ C# Corner
Figure 4

Static and Dynamic Resources


There are two ways to reference resources in WPF – static and dynamic.

Static Resources
The static resource does not change once they are assigned and they are applied at the compiled time
only. The static resources are loaded when the first time a FrameworkElement is loaded. For example, if
you have resources defined on the Application level, which will be loaded once the application starts. If
you have Window specific resources, they will be loaded when the Window instance is created for the
first time. There are no later changes in resources. The following is the XAML declaration for
StaticResource where the key is the key to the resources that are being accessed.

<object>
<object.property>
<StaticResource ResourceKey="key" .../>
</object.property>
</object>
The code snippet in Listing 18 creates a static resource in XAML and accesses it by setting Background
property of a Button control by using a StaticResource Markup Extension.

<Grid Name="GridRoot">
<Grid.Resources>
<SolidColorBrush x:Key="YellowSolidBrush" Color="Green"/>
</Grid.Resources>
<Button Name="ButtonGreenBackground"
Background="{StaticResource YellowSolidBrush}"
Content="Button"
Height="40"
VerticalAlignment="Top"
Width="150"/>

222 @ C# Corner
</Grid>

Listing 18

In the static resources process, WPF resource lookup checks for the requested key within the
resource dictionary defined by the current element. If the resource is not found there, then the
look process traverses the logical tree upward and looks for the resource in the resource
dictionary of the parent element and goes on until either the resource is found or the root
element has reached. In the end, the resource lookup process checks the application resources.

Note: Static resources must be defined before they are referenced. Forward references are not
supported in static resources.

If you try to access the resources which are not defined, then the compiler will throw a “Cannot
locate resource” exception. As shown in Figure 5.

Figure 5

Now we know that the static resource does not change once they are assigned and they are applied at
the compiled time only.

<Window.Resources>
<SolidColorBrush x:Key="SolidAquamarine" Color="Aquamarine"/>
<SolidColorBrush x:Key="SolidBlack" Color="Black"/>
</Window.Resources>
<Grid x:Name="MainGrid">
<Button x:Name="SubmitButton"
Background="{StaticResource SolidAquamarine}"
BorderBrush="{StaticResource SolidBlack}"
Content="Submit"
Height="20"
Width="200" />
</Grid>
Listing 19

Figure 6 shows how Button already has background color applied, without having to run the program to
see the change.

223 @ C# Corner
Figure 6

Dynamic Resources
Dynamic resources are loaded when the application runs the resource-specific code. A DynamicResource
will create a temporary expression during the initial compilation and thus defer lookup for resources
until the requested resource’s value is required to construct an object. This may potentially be after the
XAML page is loaded. The key is used to find the resource against all active resource dictionaries starting
from the current page scope and is substituted for the placeholder expression from the compilation.

DynamicResource Markup Extension provides a value for any XAML property attribute by looking up a
reference to an already defined resource. The following is the XAML declaration for DynamicResource
where the key is the key to the resources that are being accessed.

<object>
<object.property>
<DynamicResource ResourceKey="key" .../>
</object.property>
</object>
The code snippet in Listing 20 creates a dynamic resource in XAML and accesses it by setting Background
property of a Button control by using a DynamicResource Markup Extension.

<Grid Name="GridRoot">
<Grid.Resources>
<SolidColorBrush x:Key="YellowSolidBrush" Color="Green"/>
</Grid.Resources>
<Button Name="ButtonGreenBackground"
Background="{DynamicResource YellowSolidBrush}"
BorderThickness="1"
Content="Button"
Height="40"
VerticalAlignment="Top" />
</Grid>

Listing 20

224 @ C# Corner
In the Dynamic Resources process, WPF resource lookup process checks for the requested key
within the resource dictionary defined by the current element. If the current element defines a
Style property, the resource dictionary within the Style is checked. If the current element
defines a Template property, the resource dictionary within the FrameworkTemplate is
checked.

If the resource is still not found, then the look process traverses the logical tree upward and
looks for the resource in the resource dictionary of the parent element and so on until either
the resource is found or the root element has reached. In the end, the resource lookup process
checks the application resources. After that, the Theme resource dictionary is checked for the
current active theme. If the theme changes at run-time, the value is reevaluated. In the end,
system resources are checked.

Note: Dynamic resources support forward references. That means you can reference dynamic
resources before you define them.

Dynamic resources can change even after they’re being used.

Let’s take an example to understand their behavior. Listing 21 has 2 buttons, the first button
has a static resource and the second button has a dynamic resource.
<Window.Resources>
<SolidColorBrush x:Key="SolidAquamarine" Color="Aquamarine"/>
<SolidColorBrush x:Key="SolidBlack" Color="Black"/>
</Window.Resources>
<Grid x:Name="MainGrid">
<StackPanel VerticalAlignment="Center">
<Button x:Name="StaticResourceButton"
Background="{StaticResource SolidAquamarine}"
BorderBrush="{StaticResource SolidBlack}"
Content="Static Resource"
Height="20"
Width="100"/>
<Button x:Name="DynamicResourceButton"
Background="{DynamicResource ButtonExitBackgroundColor}"
BorderBrush="{DynamicResource ButtonExitBorderColor}"
Margin="0 10 0 0"
Content="Dynamic Resource"
Height="20"
Width="100"/>
</StackPanel>
</Grid>

Listing 21

Also, add 2 resources in the code-behind.

public MainWindow()
{
InitializeComponent();
this.Resources["ButtonExitBackgroundColor"] = new
SolidColorBrush(Colors.LightGray);

225 @ C# Corner
this.Resources["ButtonExitBorderColor"] = new
SolidColorBrush(Colors.Black);
}

Listing 22

If you see, there is a warning given at compile-time on dynamic resources. The warning says
resources could not be resolved. That is because it resolves resource dependency at run-time.

Figure 7

Now, run the project to see the magic. Have a look at Figure 8. Color is not applied on the 2nd
button at run-time, as the dependency is resolved at runtime.

Figure 8

Recommendation: Dynamic resources are slower in loading and processing. If you have
predefined resources that do not change often at run-time, you should reference your resources
statically. You should use Dynamic Resources when you are not sure what resource to use when

226 @ C# Corner
implementing themes and styles where users can pick a new theme or style whenever they
want.

227 @ C# Corner
Chapter 5.2 Templates in WPF
WPF has three types of templates

● Control Template
● Content Template: Data Template
● Item Template

Control Template
ControlTemplate of a control is used to define the appearance of the control. They are used to
customize the UI elements. We can change or define a new look and appearance of a control by simply
changing the ControlTemplate of a control. We can transform both controls as well as data with the
templates. ControlTemplates are even more useful when you write your own controls. You can define a
default look of your controls.

Every control in WPF has its default template associated with it. A Default template defines a look and
feel, basically a style of a control. That's why by default, Button’s or TextBox’s shapes are rectangular
because it is defined inside their default template. We can update that template and add our own
implementation. For example, a WPF Button control has a rectangular layout but using
ControlTemplates, you can build a custom button that has a circular layout and changes its color when
you mouse over or press it.

The ControlTemplate element in XAML is used to define a ControlTemplate at design-time. Templates


are usually defined as resources using a FrameworkElement’s Resources property. Let's create a
custom control to change the shape of this button. The following code snippet is the syntax of
defining a ControlTemplate for a Button element.
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="RoundButtonTemplate"
TargetType="{x:Type Button}" />
</Grid.Resources>
</Grid>

Now let’s imagine that we need to create a circular button that looks like Figure 1 where outer circle of
the button is a different color that the inner circle and when you mouse over and press the button, it
changes the background color.

Figure 1

228 @ C# Corner
The code snippet in Listing 1 creates a ControlTemplate and adds a Grid as contents of the
ControlTemplate. The content is what your control will look like. As you can see from Listing 1, we add
two Ellipse elements within a Grid with different size and different color fills.

<Grid.Resources>
<ControlTemplate x:Key="RoundButtonTemplate"
TargetType="{x:Type Button}" >
<Grid>
<Ellipse x:Name="OuterCircle"
Fill="OrangeRed"
Height="100"
Width="100" />
<Ellipse x:Name="InnerCircle"
Fill="Orange"
Height="80"
Width="80" />
</Grid>
</ControlTemplate>
</Grid.Resources>

Listing 1

The following code snippet creates a Button element and sets its Template to ControlTemplate that we
have created in Listing 1.
<Button x:Name="ButtonRectangle"
Template="{StaticResource RoundButtonTemplate}"
Content="OK"/>
The output of this looks like Figure 1.

TargetType Property
The TargetType property is used to restrict the type of element. The following code snippet ensures that
RoundButtonTemplate is applicable to the Button elements only.
<ControlTemplate x:Key="RoundButtonTemplate" TargetType="{x:Type Button}" >

ControlTemplate Triggers
Now how about adding some cool features to this control? Let’s animate the button on mouse over and
click events. We are going to change the color when you hover a mouse over it and we are going to
decrease the size of the button when it is pressed.

The Triggers property of ControlTemplate is used to handle events. The code snippet in Listing 2 adds
triggers for IsMouseOver and IsPressed events of a Button. At the IsMouseOver event, I change the color
of the InnerCircle of the Button. On the IsPressed event, I change the width and height of InnerCircle
and Fill of OuterCircle.

<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter TargetName="InnerCircle" Property="Fill" Value="LightGreen" />
</Trigger>
<Trigger Property="Button.IsPressed" Value="True">

229 @ C# Corner
<Setter TargetName="InnerCircle" Property="Width" Value="60" />
<Setter TargetName="InnerCircle" Property="Height" Value="60" />
<Setter TargetName="OuterCircle" Property="Fill" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>

Listing 2

Figure 2 shows Button when it first loaded.

Figure 2

If you roll your mouse over the button, you will see the background of the inner circle is changed to
green and looks like Figure 3.

Figure 3

If you click on the button, you will see the background of the outer circle changes to gray and the width
and height of the inner circle is reduced. Figure 4 shows the effect on a Button when it is pressed.

Figure 4

230 @ C# Corner
Now let’s add gradients for the Fill property of Ellipses and fill them with gradient brushes as shown in
Listing 3.
<Ellipse Width="100" Height="100" Name="OuterCircle" >
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,0.5">
<GradientStop Offset="0" Color="OrangeRed" />
<GradientStop Offset="1" Color="Orange" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Width="80" Height="80" Name="InnerCircle">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="1" Color="OrangeRed" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
Listing 3

The renewed button with gradient color looks like Figure 5.

Figure 5

If you roll over the button, you will see the background of the inner circle is changed to green and looks
like Figure 6.

Figure 6

231 @ C# Corner
Content Template: Data Template
Content presenter ensures how data will be displayed in a template. Let’s take an example of an
employee, Let’s try to display fields such as employee Id, name and designation. Code snippet in Listing
4 has encapsulated this information into a class Employee.

public class Employee


{
public int EmpId { get; set; }
public string EmpName { get; set; }
public string Designation { get; set; }
}

Listing 4

Inside a ContentPresenter we need to specify a content which is a source of data. In our example, the
object of an employee would be our source of data. Note: Content is Datacontext for the DataTemplate.

So, what is a DataTemplate? It defines a structure in which we want to display the data. It could be
DataGrid, TextBlock or any other WPF’s UI elements. In our example we will use labels to display
Employee details. We are going to follow MVVM architecture for this example. For which we need a
View and a ViewModel class. So here View is MainWindow and ViewModel is MainWindowViewModel.

For Button’s control template we can use the same example as above and to make things a little more
interesting let’s add RoundButtonTemplate inside a create ResourceDictionary. Code snippet in Listing 5
shows ResourceDictionary with RoundButtonTemplate.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Thickness x:Key="MarginB">0 0 0 10</Thickness>
<ControlTemplate x:Key="RoundButtonTemplate">
<Grid>
<Ellipse x:Name="OuterCircle"
Height="65"
Width="65">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,0.5">
<GradientStop Offset="0" Color="OrangeRed" />
<GradientStop Offset="1" Color="Orange" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>

<Ellipse x:Name="InnerCircle"
Height="45"
Width="45">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="1" Color="OrangeRed" />
</LinearGradientBrush>
</Ellipse.Fill>

232 @ C# Corner
</Ellipse>

<ContentPresenter Content="Submit"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter TargetName="InnerCircle" Property="Fill" Value="LightGreen" />
</Trigger>
<Trigger Property="Button.IsPressed" Value="True">
<Setter TargetName="InnerCircle" Property="Width" Value="60" />
<Setter TargetName="InnerCircle" Property="Height" Value="60" />
<Setter TargetName="OuterCircle" Property="Fill" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>

Listing 5

Moving forward we have to use this dictionary inside our View. Listing 6 shows how to add a
ResourceDictionary inside a Window.

<Window x:Class="ChapterFive_PartTwo_Template.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="ResourceDictionaryTemplate.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

</Window.Resources>
<Grid>

</Grid>
</Window>
Listing 6

Now let’s create a ContentPresenter in which we are supposed to display Employee’s information.
Listing 7 shows how to use ContentPresenter.ContentTemplate to add a DataTemplate.

<Window x:Class="ChapterFive_PartTwo_Template.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

233 @ C# Corner
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="ResourceDictionaryTemplate.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

</Window.Resources>
<Grid>
<ContentPresenter x:Name="EmployeeDetails" Content="{Binding
EmpDetails}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

<Label Content="Employee Id:"/>


<Label Content="{Binding EmpId}"
Grid.Column="1"/>

<Label Content="Employee Name:"


Grid.Row="1"/>

<Label Content="{Binding EmpName}"


Grid.Row="1"
Grid.Column="1"/>

<Label Content="Employee Designation:"


Grid.Row="2"/>

<Label Content="{Binding Designation}"


Grid.Column="1"
Grid.Row="2"/>

</Grid>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>

<Button x:Name="SubmitButton"
Template="{StaticResource RoundButtonTemplate}"
VerticalAlignment="Bottom"

234 @ C# Corner
Margin="{StaticResource MarginB}"
Foreground="White"
Width="100"/>
</Grid>
</Window>
Listing 7

We are done with View. Let’s create a ViewModel for the same. Listing 8 shows a ViewModel containing
Employee’s property which is bound on our View. We are using a constructor to initialize this property
with some static data for this example.

public class MainWindowViewModel


{

#region Properties
private Employee _empDetails;
public Employee EmpDetails
{
get { return _empDetails; }
set { _empDetails = value; }
}

#endregion

#region Constructor
public MainWindowViewModel()
{
EmpDetails = new Employee()
{
EmpId = 1,
EmpName = "Alex",
Designation = "Software Engineer"
};
}
#endregion
}
Listing 8

Now all that is left is to bind View with ViewModel, we can achieve this by simply assigning DataContext
of View. Code snippet in Listing 9 shows how to use an instance of MainWindowViewModel for
MainWindow’s DataContext.

Note: We are using code-behind to bind DataContext, there are 2 other and better ways to do the same
which we will discuss in upcoming chapters.

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

235 @ C# Corner
this.DataContext = new MainWindowViewModel();
}
}

Listing 9

At last, you can see how output of above listings would look like. Figure 7 shows the output window
showing employee’s details with Content Presenter and Control Template.

Figure 7

ItemsTemplate
Let’s say we have a list of employees to display. We can use an item template where we can define a
template for a one item then it will be replicated for all the items in the list.

As you can see in figure 8, we have 4 employees. It would be wrong to write the same code for every
instance of an employee, rather we can simply create a data template once then use it as an
ItemsTemplate. We can use ListView to show the list of employees and we can use the ItemTemplate
property of ListView to bind our newly created DataTemplate.

236 @ C# Corner
Figure 8

First, Let’s go ahead and create an Employee class. Let's reuse the same we used in listing 4 with one
extra property which tells if an employee is a manager or not? Listing 10 shows an updated employee
class.
public class Employee
{
public int EmpId { get; set; }
public string EmpName { get; set; }
public string Designation { get; set; }
public bool IsManager { get; set; }
}

Listing 10

Now let’s create a DataTemplate to display these properties. Listing 11 shows how to create a
DataTemplate to show a single employee detail.

Note: This DataTemplate is being used in Windows.Resources, you can also use directly inside a control.
<DataTemplate x:Key="EmployeeDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TextBlockEmployeeDetail"
FontWeight="Bold" >
<Run Text=" | "/>
<Run Text="Emp Id: "
Foreground="#344CB7"/>
<Run Text="{Binding EmpId}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Name: "
Foreground="#344CB7"/>
<Run Text="{Binding EmpName}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Designation: "
Foreground="#344CB7"/>
<Run Text="{Binding Designation}"

237 @ C# Corner
Foreground="#CD1818"/>
<Run Text=" | Manager: "
Foreground="#344CB7"/>
</TextBlock>
<CheckBox IsChecked="{Binding IsManager}"/>
</StackPanel>
</DataTemplate>

Listing 11

Now let’s create a ListView to hold this template. In listing 12, note we are also adding one TextBlock
just to show heading.

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock FontSize="30"
Foreground="#B91646"
HorizontalAlignment="Center"
Margin="0 0 0 20"
Text="Employee details:"/>
<ListView x:Name="ListViewItemTemplateExample"
HorizontalAlignment="Center"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.Row="1"/>
</Grid>

Listing 12

As you can see in listing 12, we are assigning “EmployeeDataTemplate” to the “ItemTemplate property”
of a ListView.

Now at last, we need a list of employees. So, head back to code-behind and make changes as per listing
13.
using System.Collections.Generic;
using System.Windows;

namespace ItemTemplate
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LoadList();
}
private void LoadList()
{

238 @ C# Corner
List<Employee> employees = new ();
employees.Add(new Employee() { EmpId = 1, EmpName = "Alex", Designation =
"Software Engg.", IsManager = false });
employees.Add(new Employee() { EmpId = 2, EmpName = "Marty", Designation =
"Team Lead", IsManager = false });
employees.Add(new Employee() { EmpId = 3, EmpName = "Gloria", Designation =
"H.R.", IsManager = false });
employees.Add(new Employee() { EmpId = 4, EmpName = "Julien", Designation =
"Manager", IsManager = true });
ListViewItemTemplateExample.ItemsSource = employees;
}
}
}
Listing 13

And that’s all you need to use the ItemTemplate to populate the list of items.

239 @ C# Corner
Chapter 6: WPF Controls and Elements

AccessText
The AccessKey control in WPF is used to add underscore to a character.

For this we first have to understand what access keys are? They are referred as accelerator keys, they
provide you the flexibility to reach a specific control inside a Window by holding down the Alt key on the
keyboard and then pressing another next key on the keyboard. This is one way through which users can
access UI elements with a keyboard directly.

WPF has AccessText control to serve the purpose of access keys.

Creating an AccessText
The AccessText tag represents an AccessText control in XAML.

<AccessText>_Click Me</AccessText>

Now if you run the project, you’d see a Click Me text as shown in figure 1.

Figure 1

If you hold down the alt key on the keyboard, then you’d see underscore below the “Click Me” text.

Figure 2

If there are multiple underscore characters, only the first one gets converted to the AccessKey; the rest
of the underscores appear as normal text, but If you wish to convert any specific underscore as access
key then use two consecutive underscores for the first position if you wish to ignore the first
underscores.
Here let us explain this with an example. In the following syntax, you would notice we have used 2
underscore before word click and one underscore before word me.

240 @ C# Corner
<AccessText> Click _Me</AccessText>

The output of this would look like figure 3.

Figure 3

Usage of access keys is not limited to AccessText control. You can directly use it on the content or text
properties. Code snippet in listing 1 shows how we can use underscore directly on Button’s content
property.

<Window x:Class="AccessText.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:AccessText"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button x:Name="ButtonClick"
Content="_Click Me"
Height="30"
Width="100"/>
</Grid>
</Window>

Listing 1

Figure 4 is an output for listing 1.

Figure 4

241 @ C# Corner
Button
Introduction
The Button control is one of the essential controls in WPF. A button is bound with a click event which
executes the code on its click event handler. A button control can be represented at design-time using
the XAML <Button> element. The Button class in C# represents the WPF button at run-time.

Creating a Button

The Button element in XAML represents a WPF Button control.

<Button/>

In order to set the width and the height for a Button we can use Width and Height attributes of the
Button element. The Content property of the Button element sets the text which appears on a button.
The x:Name attribute represents the name of the control, which is a unique identifier of a control. You
may also use the Name property to set the name of a control.

The code snippet in Listing 1 creates a Button control and sets the name, height, width, and content of a
Button control.

<Button x:Name="DrawCircleButton"
Content="Draw Circle"
Height="40"
Width="120" />

Listing 1

The default property of a Button is Content.

The code snippet in Listing 2 creates the same button as Listing 1 except without specifying the content
property. Button considers the text entered in between the opening and closing tags as content.

<Button x:Name="DrawCircleButton"
Height="40"
Width="120">
Draw Circle
</Button>

Listing 2

The output looks like Figure 1.

242 @ C# Corner
Figure 1

If you place a button on a Grid control, the button will be placed in the center of the Grid. If you are
using Canvas as your parent control of Button, then the Button will be placed in the left top corner of
Canvas.

You can use Margin property to position a button control in a container like a Grid. The Margin property
takes 4 values that follow this order. Starting from left, top, right, and bottom positions. Listing 3 sets
the Margin property of the Button control.

<Button x:Name="DrawCircleButton"
Content="Draw Circle"
Height="40"
Margin="60,120,80,120"
Width="120"/>
Listing 3

If you click on a Button at design time you would see numbers besides a Button representing, it’s
margin. This behavior is illustrated in Figure 2.

Figure 2

If you are using a Canvas, you may also use Canvas.Left and Canvas.Top properties.

243 @ C# Corner
You may also use VerticalAlignment and HorizontalAlignment attributes to set vertical alignment, and
horizontal alignment of a button.

The code snippet in Listing 4 sets the position of the Button control to the left top corner of the Canvas.

<Button x:Name="DrawCircleButton"
Content="Draw Circle"
Height="40"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
Canvas.Left="10"
Canvas.Top="10" />

Listing 4

Formatting a Button

Now let’s get a little creative. How about we create a Button control with a border formatting,
background, and foreground?

The BorderBrush property of the Button can be used to draw the border of a Button. You can use any
brush to fill the border. The following code snippet uses a linear gradient brush to draw the border with
a combination of red and blue color.

<Button.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Button.BorderBrush>
Listing 5

The Background and Foreground properties of the Button set the background and foreground colors of a
Button. You may use any brush to fill the border. The following code snippet uses linear gradient
brushes to draw the background and foreground of a Button.

<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Button.Background>
<Button.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="1.0" />
</LinearGradientBrush>
</Button.Foreground>

244 @ C# Corner
Listing 6

Listing 7 is the final complete source code .

<Window x:Class="ButtonControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:ButtonControl"
mc:Ignorable="d"
Title="MainWindow"
Height="300"
Width="300">
<Canvas Name="LayoutRoot">
<Button x:Name="DrawCircleButton"
Content="Draw Circle"
Height="40"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
Canvas.Left="10"
Canvas.Top="10">
<Button.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Button.BorderBrush>
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="White" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Button.Background>
<Button.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Black" Offset="0.25" />
<GradientStop Color="Green" Offset="1.0" />
</LinearGradientBrush>
</Button.Foreground>
</Button>
</Canvas>
</Window>
Listing 7

The output of listing 7looks like Figure 3.

245 @ C# Corner
Figure 3

Creating a Button Dynamically

The code snippet in Listing 8 creates a Button control programmatically. First, it creates a Button object
and sets its width, height, contents, background and foreground and later the Button is added to the
LayoutRoot.

private void CreateAButton()


{
Button btn = new Button();
btn.Height = 40;
btn.Width = 120;
btn.Content = "Click Me";
btn.Margin = new Thickness(50,75,0,0);
btn.Background = new SolidColorBrush(Colors.Orange);
btn.Foreground = new SolidColorBrush(Colors.Black);
LayoutRoot.Children.Add(btn);
}

Listing 8

The output of listing 8 and 9 would look like figure 4.

246 @ C# Corner
Figure 4

Button Content

Each XAML object element is capable of displaying different content types. XAML provides a special
property called Content. As we saw earlier it is used to display the content of the element. For example,
a Content property of a Button can be a set to a string, an object, a UIElement, or even a container.
However, the Content property of a ListBox is set using the Items property.

Note: Some XAML object elements may not have the Content property available directly. It must be set
through a property.

The code snippet in Listing 9 creates a Button control and sets its Content property to a string “Hello
XAML”. The output looks like Figure 10.

<Grid Name="LayoutRoot">
<Button
Content="Hello XAML"
Height="50"
Width="200"/>
</Grid>

Listing 9

Listing 10 is an alternative way to set the Content property of a Button.

<Button Height="50"
Width="200">Hello XAML</Button>
Listing 10

The output of Listing 9 or 10 looks the same as Figure 5.

247 @ C# Corner
Figure 5

A Button element can display other child elements as its content. The code listed in Listing 11 sets a
Rectangle element as the content of the Button.

<Button
Height="50"
Width="200">
<Rectangle
Height="40"
Width="180"
Fill="Green"/>
</Button>

Listing 11

The output of Listing 20 looks the same as Figure 6.

Figure 6

Content property can also be a container or a parent element hosting other child elements. The code
snippet in Listing 12 sets a StackPanel as a parent with its 5 child elements as the content of the Button.

<Button>

248 @ C# Corner
<StackPanel Orientation="Horizontal">
<Ellipse
Fill="Red"
Height="60"
Width="60" />
<TextBlock
TextAlignment="Center">
<Run Text=" Red Circle "/>
</TextBlock>

<Rectangle
Height="60"
Width="120"
Fill="Green"/>
<TextBlock
TextAlignment="Center">
<Run Text=" Green Rectangle"/>
</TextBlock>
</StackPanel>
</Button>

Listing 12

The output of Listing 12 looks the same as Figure 7.

Figure 7

The final XAML code is listed in Listing 13.

<Grid Name="LayoutRoot">

<!-- Listing 13 -->


<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button
Content="Hello XAML"
Height="50"
HorizontalAlignment="Left"
Margin="10"
Width="150" />
<Button

249 @ C# Corner
Height="80"
HorizontalAlignment="Left"
Margin="10"
Width="200"
Grid.Row="1">
<Rectangle Height="60"
Width="120"
Fill="Green"/>
</Button>

<!-- Listing 12 -->


<Button Margin="10"
Grid.Row="2">
<StackPanel Orientation="Horizontal">
<Ellipse
Fill="Red"
Height="60"
Width="60" />
<TextBlock
TextAlignment="Center">
<Run Text=" Red Circle "/>
</TextBlock>

<Rectangle
Height="60"
Width="120"
Fill="Green"/>
<TextBlock
TextAlignment="Center">
<Run Text=" Green Rectangle"/>
</TextBlock>
</StackPanel>
</Button>
</Grid>

Listing 13

The output of Listing 13 looks the same as Figure 8.

250 @ C# Corner
Figure 7

As you can imagine from the above examples, you can pretty much host any user interfaces as content
of a XAML element.

The code listed in Listing 14 creates the above Button controls dynamically in the code and sets their
Content properties to a string, a Rectangle, and a StackPanel respectively.
// Button with string content
Button helloButton = new Button();
helloButton.Margin = new Thickness(10,10,350,310);
helloButton.Content = "Hello XAML";

// Button with a UIElement


Button buttonWithRectangle = new Button();
buttonWithRectangle.Height = 80;
buttonWithRectangle.Margin = new Thickness(10, 80, 300, 170);
// Create a Rectangle
Rectangle greenRectangle = new Rectangle();
greenRectangle.Height = 60;
greenRectangle.Width = 120;
greenRectangle.Fill = Brushes.Green;
// Set Rectangle as Button.Content
buttonWithRectangle.Content = greenRectangle;

// Button with a Container, StackPanel


Button buttonWithStackPanel = new Button();

251 @ C# Corner
buttonWithStackPanel.Margin = new Thickness(10, 10, 350, 310);
// Create a StackPanel and set its orientation to horizontal
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
// Create an Ellipse
Ellipse redEllipse = new Ellipse();
redEllipse.Width = 60;
redEllipse.Height = 60;
redEllipse.Fill = Brushes.Red;
// Add to StackPanel
stackPanel.Children.Add(redEllipse);

// Create a TextBlock
TextBlock textBlock1 = new TextBlock();
textBlock1.TextAlignment = TextAlignment.Left;
textBlock1.Text = "Red Circle";
// Add to StackPanel
stackPanel.Children.Add(textBlock1);

// Create a TextBlock
TextBlock space = new TextBlock();
space.TextAlignment = TextAlignment.Center;
space.Text = " ";
// Add to StackPanel
stackPanel.Children.Add(space);

// Create a Rectangle
Rectangle greenRectangle2 = new Rectangle();
greenRectangle2.Height = 60;
greenRectangle2.Width = 120;
greenRectangle2.Fill = Brushes.Green;
// Add to StackPanel
stackPanel.Children.Add(greenRectangle2);

// Create a TextBlock
TextBlock textBlock2 = new TextBlock();
textBlock2.TextAlignment = TextAlignment.Left;
textBlock2.Text = "Green Rectangle";
// Add to StackPanel
stackPanel.Children.Add(textBlock2);
// Set StackPaenl as Button.Content
buttonWithStackPanel.Content = stackPanel;
// Add dynamic button controls to the Window
LayoutRoot.Children.Add(helloButton);
LayoutRoot.Children.Add(buttonWithRectangle);
LayoutRoot.Children.Add(buttonWithStackPanel);

Listing 14

Setting Image as Background of a Button

We can set an image as a Background of the Button. The code snippet in Listing 15 sets the background
of a Button to an image.

252 @ C# Corner
<Button.Background>
<ImageBrush ImageSource="dock.jpg" />
</Button.Background>

Listing 15

The new output looks like Figure 9.

Figure 9

Adding a Button’s Click Event Handler

The Click attribute of the Button element adds the click event handler. The code in Listing 16 adds the
click event handler for a Button.

<Button x:Name="DrawCircleButton"
Click="DrawCircleButton_Click"
Content="Draw Circle"
Height="40"
Width="120"/>

Listing 16

The code for the click event handler looks like the following. You will find this code in the code-behind
file.

private void DrawCircleButton_Click(object sender, RoutedEventArgs e)


{

Now, whatever code you write in the click event handler that will be executed on the Button click. The
code listed in Listing 17 creates a circle on the Button click event handler.

private void DrawCircleButton_Click(object sender, RoutedEventArgs e)


{
// creates a Circle
Ellipse circle = new Ellipse();
circle.Width = 200;
circle.Height = 200;
circle.Fill = new SolidColorBrush(Colors.Yellow);
circle.Stroke = new SolidColorBrush(Colors.Black);
circle.StrokeThickness = 4;
LayoutRoot.Children.Add(circle);
}

253 @ C# Corner
Listing 17

When you run the program you will see Button as shown in figure 10.

Figure 10

When you click on a Button you’d see the round shape.

Figure 11

254 @ C# Corner
Mouse Rollover Formatting

Let’s add a couple of more events. You can add events when a mouse is hovering over the Button and
mouse leaves the Button area. We can achieve this by adding MouseEnter and MouseLeave event
handlers.

The code snippet in Listing 18 adds Mouse Enter and MouseLeave event handlers.

<Button x:Name="DrawCircleButton"
Click="DrawCircleButton_Click"
Content="Draw Circle"
Height="40"
MouseEnter="DrawCircleButton_MouseEnter"
MouseLeave="DrawCircleButton_MouseLeave"
Width="120" />

Listing 18

The code snippet in Listing 19 sets the background and foreground colors of a Button on mouse enter
and mouse leave event handlers.

private void DrawCircleButton_MouseEnter(object sender, MouseEventArgs e)


{
DrawCircleButton.Background = new SolidColorBrush(Colors.SkyBlue);
DrawCircleButton.Foreground = new SolidColorBrush(Colors.Green);
}

private void DrawCircleButton_MouseLeave(object sender, MouseEventArgs e)


{
DrawCircleButton.Background = new SolidColorBrush(Colors.Red);
DrawCircleButton.Foreground = new SolidColorBrush(Colors.Purple);
}

Listing 19

Figure shows the background of a Button changed to SkyBlue when the mouse is hovering over its
surface.

255 @ C# Corner
Figure 12

Figure shows the background of a Button changed to Red when the mouse leaves its surface.

Figure 13

Summary
In this chapter, I discussed how we can create a Button control in WPF and C#. We also saw how we can
format a Button by setting its border, background, and foreground properties. Later, we saw how we
can set an image as the background of a Button. At last, we learnt how to create a Button dynamically
and how to add events on a Button control.

256 @ C# Corner
Calendar
A Calendar control lets the user pick a date and fire an event on the selection of the date. This chapter
demonstrates how to create and use a Calendar control in Silverlight using XAML and C#.

Creating a Calendar
The Calendar element represents a WPF calendar control in XAML.

<Calendar/>

The Calendar control is defined in the System.Windows.Controls namespace. Listing 1 shows how
Calendar control looks like in XAML. The code snippet in Listing 1 creates a Calendar control and sets the
name, height, width and horizontal, vertical alignment properties for the same.

<Calendar x:Name="CalendarExample"
Height="170"
HorizontalAlignment="Left"
Margin="50,50"
VerticalAlignment="Top"
Width="180" />
Listing 1

The default view of the Calendar control looks like Figure 1.

Figure 1

The Width and Height attributes of the Calendar element specify the width and the height of a Calendar.
The Name attribute specifies the name of the control, which is a unique identifier of a control.

257 @ C# Corner
Display Modes
The DisplayMode property of the Calendar class represents the format of display of a Calendar, which
can be a month, year, or decade. Month is the default mode, which means it shows all the dates of the
month by default.

Figure 2 shows how calendar looks like when DisplayMode property is set to “Year”

<Calendar DisplayMode="Year">

Figure 2

Figure 3 shows how calendar looks like when DisplayMode property is set to “Decade”

<Calendar DisplayMode="Decade">

Figure 3

258 @ C# Corner
If you take an example of the Decade, and click on year 2021 as shown in Figure 3, It will take you to the
Calendar format with all months in year 2021 and if you click further down by selecting specific month
then it will take you to Months view from where you will be able to select a specific date.

The following code snippet sets the DisplayMode property to Decade.

Selection Modes and Selection Dates


The SelectedDate property lets you select the date. There are 3 different ways you can select the date/s.

The SelectionMode is a type of CalendarSelectionMode enumeration which specifies the selection mode
of the calendar. Table 1 describes the CalendarSelectionMode enumeration with its values.

CalendarSelectionMode Description

None No selections are allowed.

SingleDate Only a single date can be selected, either by setting SelectedDate or the first
value in SelectedDates. AddRange cannot be used.

<Calendar SelectionMode="SingleDate">
Figure 4 has date 10 selected where date 14 is today’s date.

Figure 4

SingleRange A single range of dates can be selected. Setting SelectedDate, adding a date
individually to SelectedDates. Use the mouse to drag across dates you wish
to select.

<Calendar SelectionMode="SingleRange">
Figure 5 has a week starting from 8 to 14 has been selected.

259 @ C# Corner
Figure 5

MultipleRange Multiple non-contiguous ranges of dates can be selected. Adding a date


individually to SelectedDates. Setting SelectedDate will still clear
SelectedDates, but additional dates or ranges can then be added. Adding a
range that includes some dates that are already selected or overlaps with
another range results in the union of the ranges and does not cause an
exception. Use the mouse to drag across dates you wish to select.

Use mouse to drag across dates you wish to select, hold down the ctrl key to
select non-contiguous ranges of dates.

<Calendar SelectionMode="MultipleRange">
Figure 6 has 3 ranges of dates selected, from 1-7, 15-21 and 29-31.

Figure 6

260 @ C# Corner
BlackoutDates
The BlackoutDates property of the Calendar class specifies a collection of dates that are not up for
selection. It blocks users from selecting those dates. All non-selection dates are marked by a cross. For
example, say in the month of July 2021. We only want users to block from selecting dates from the
month of June or August. Code snippet in listing 2 shows how to achieve this.

<Calendar.BlackoutDates>
<CalendarDateRange Start="6/27/2021" End="6/30/2021"/>
<CalendarDateRange Start="8/1/2021" End="8/7/2021"/>
</Calendar.BlackoutDates>

Listing 2

Figure 7 shows how the Calendar look like after blacking out dates specified In listing 2.

Figure 7

We can even achieve this same behavior dynamically. As you can see from Listing 3, the
BlackoutDates.Add method takes a CalendarDateRange object, which is a collection of two DateTime
objects. The first date is the start date of the range and the second date is the end date of the date
range.

private void SetBlackOutDates()


{
CalendarExample.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2021, 6, 27),
new DateTime(2021, 6, 30)
));
CalendarExample.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2021, 8, 1),
new DateTime(2021, 8, 7)
));
}

Listing 3

261 @ C# Corner
DisplayDateStart and DisplayDateEnd
The Calendar control allows you to set the start and end display dates by using the DisplayDateStart and
DisplayDateEnd properties. In the previous example, you’d notice in Figure 5, the month July 2021 starts
with July 01, 2021, as it supposed to. Let’s say a client asks you to start the month of July from July,10
rather than July, 1st. Weird I know, but the client is god so let’s do those changes. We can use the
DisplayStartDate and DisplayEndDate properties to control the start and end date’s visibility of a month.

The following code snippet sets the DisplayDate, DisplayDateStart and DisplayDateEnd attributes of the
Calendar element in XAML.

<Calendar x:Name="CalendarExample"
DisplayMode="Month"
DisplayDate="7/10/2021"
DisplayDateStart="7/10/2021"
DisplayDateEnd="7/20/2021"
Height="220"
HorizontalAlignment="Left"
Margin="50,50"
SelectionMode="MultipleRange"
VerticalAlignment="Top"
Width="200" >

Listing 4

The output of listing 4 is shown in figure 8.

Figure 8

Let’s add a dynamic function to achieve the same behavior from code-behind.

private void SetDisplayDates()


{
CalendarExample.DisplayDate = new DateTime(2021, 7, 10);
CalendarExample.DisplayDateStart = new DateTime(2021, 7, 10);

262 @ C# Corner
CalendarExample.DisplayDateEnd = new DateTime(2021, 7, 20);
}

Listing 5

FirstDayOfWeek and IsTodayHighlighted


By default, Sunday is the first day of the week. If you would like to change it, you can do so by using
FirstDayOfWeek property, and the IsTodayHightlighted property is used to make today highlighted.

The following code snippet sets the FirstDayOfWeek to Tuesday and makes today highlighted.

<Calendar x:Name="CalendarExample"
DisplayMode="Month"
FirstDayOfWeek="Thursday"
Height="220"
HorizontalAlignment="Left"
IsTodayHighlighted="True"
Margin="50,50"
SelectionMode="MultipleRange"
VerticalAlignment="Top"
Width="200" >

Listing 6

Listing 7 shows to set the FirstDayOfWeek to Tuesday and makes today’s date highlighted from code-
behind.

CalendarExample.FirstDayOfWeek = DayOfWeek.Tuesday;
CalendarExample.IsTodayHighlighted = true;

Listing 7

The new calendar looks like Figure 9, where you can see the start day of the week is Tuesday and date
15th is highlighted.

Figure 9

263 @ C# Corner
Selected Date and Selected Dates
The SelectedDate property specifies the current selected date. If multiple date selection is true, then
SelectedDates property specifies all selected dates in a Calendar. The following code snippet sets the
SelectedDates in XAML at design-time.

<Calendar x:Name="CalendarExample"
DisplayMode="Month"
Height="220"
HorizontalAlignment="Left"
IsTodayHighlighted="True"
Margin="50,50"
SelectionMode="MultipleRange"
VerticalAlignment="Top"
Width="200"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Calendar.SelectedDates>
<sys:DateTime>8/2/2021</sys:DateTime>
<sys:DateTime>8/9/2021</sys:DateTime>
<sys:DateTime>8/16/2021</sys:DateTime>
<sys:DateTime>8/23/2021</sys:DateTime>
<sys:DateTime>8/30/2021</sys:DateTime>
</Calendar.SelectedDates>
</Calendar>
Listing 8

The selected dates in listing 8 looks like Figure 10, as you can see August 2nd, 9th, 16th, 23rd, and 30th
have a light blue background and represent the selected dates.

Figure 10

The following code snippet sets the SelectedDates property in WPF at run-time.

private void AddSelectedDates()


{

264 @ C# Corner
CalendarExample.SelectedDates.Add(new DateTime(2021, 8, 2));
CalendarExample.SelectedDates.Add(new DateTime(2021, 8, 9));
CalendarExample.SelectedDates.Add(new DateTime(2021, 8, 16));
CalendarExample.SelectedDates.Add(new DateTime(2021, 8, 23));
CalendarExample.SelectedDates.Add(new DateTime(2021, 8, 30));
}

Listing 9

Note: if your SelectedDates falls under any of BlackoutDates then the compiler will throw an error.
Listing 10 shows how all selected dates are coming under blackout dates.

<Calendar.BlackoutDates>
<CalendarDateRange Start="8/2/2021" End="8/30/2021"/>
</Calendar.BlackoutDates>
<Calendar.SelectedDates>
<sys:DateTime>8/2/2021</sys:DateTime>
<sys:DateTime>8/9/2021</sys:DateTime>
<sys:DateTime>8/16/2021</sys:DateTime>
<sys:DateTime>8/23/2021</sys:DateTime>
<sys:DateTime>8/30/2021</sys:DateTime>
</Calendar.SelectedDates>

Listing 10

Figure 11 shows an exception thrown.

Figure 11

265 @ C# Corner
Calendar Events
Besides any common events of the control, the Calendar control has three calendar specific events.
These events are the DisplayDateChanged, DisplayModeChanged, and SelectedDatesChanged. The
DisplayDateChanged event is fired if the DisplayDate property is changed. The DisplayModeChanged
event is fired when the DisplayMode property is changed. The SelectedDatesChanged event is fired if
the SelectedDate or SelectedDates properties are changed. The following code snippet sets these three
events attributes.

<Calendar x:Name="CalendarExample"
DisplayMode="Month"
Height="220"
HorizontalAlignment="Left"
IsTodayHighlighted="True"
Margin="50,50"
SelectionMode="MultipleRange"
VerticalAlignment="Top"
Width="200"
SelectedDatesChanged="CalendarExample_SelectedDatesChanged"
DisplayDateChanged="CalendarExample_DisplayDateChanged"
DisplayModeChanged="CalendarExample_DisplayModeChanged">

Listing 11

The code behind these events looks like Listing 12.

private void CalendarExample_SelectedDatesChanged(object sender,


SelectionChangedEventArgs e)
{
}

private void CalendarExample_DisplayDateChanged(object sender,


CalendarDateChangedEventArgs e)
{

private void CalendarExample_DisplayModeChanged(object sender,


CalendarModeChangedEventArgs e)
{

Listing 12

Let’s make use of the SelectedDatesChanged event, let’s show the selected date on UI. We are going to
need one TextBlock to display the selected date then let’s set the text of the TextBlock to the currently
selected date from the calendar.

Code snippet in listing 13 shows how TextBlock is placed below Calendar in XAML.

266 @ C# Corner
<Grid>
<Calendar x:Name="CalendarExample"
Height="220"
HorizontalAlignment="Left"
Margin="50,50"
VerticalAlignment="Top"
Width="200"
SelectedDatesChanged="CalendarExample_SelectedDatesChanged"
/>

<TextBlock x:Name="TextBlockSelectedDate"
Height="20"
Margin="35 200 0 0"
Width="200"/>
</Grid>

Listing 13

On the SelectedDateChanged event handler, we set the TextBlock.Text property to the SelectedDate
property of the Calendar control as you can see from code in Listing 14.

private void CalendarExample_SelectedDatesChanged(object sender,


SelectionChangedEventArgs e)
{
TextBlockSelectedDate.Text = CalendarExample.SelectedDate.ToString();
}

Listing 14

Now when you run the application, you will see output as Figure 12. When you select a date in the
Calendar, it will be displayed in the Textblock.

Figure 12

267 @ C# Corner
Formatting a Calendar
Let’s format a Calendar bit. We can change the border, background and foreground of the Calendar.

The BorderBrush property of the Calendar sets a brush to draw the border of a Calendar. You may use
any brush to fill the border. The following code snippet uses a linear gradient brush to draw the border
with a combination of red and blue color.

<Calendar.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Calendar.BorderBrush>

Listing 15

The Background and Foreground properties of the Calendar are used to set the background and
foreground colors of a Calendar. You may use any brush to fill the border. The following code snippet
uses linear gradient brushes to draw the background and foreground of a Calendar.

<Calendar.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Calendar.Background>
<Calendar.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Black" Offset="0.25" />
<GradientStop Color="Green" Offset="1.0" />
</LinearGradientBrush>
</Calendar.Foreground>

Listing 15

The new Calendar looks like Figure 13.

268 @ C# Corner
Figure 13

Setting Image as Background of a Calendar


To set an image as a background of a Calendar, we can set an ImageBrush as the Background of the
Calendar. The following code snippet sets the background of a Calendar to an image. The code also sets
the opacity of the image.

<Calendar.Background>
<ImageBrush ImageSource="Background.jpg" Opacity="0.3"/>
</Calendar.Background>

Listing 15

The new output looks like Figure 14.

Figure 14

269 @ C# Corner
Creating a Calendar Dynamically
The code listed in Listing 16 creates a Calendar control dynamically. First, it creates a Calendar object
and sets its DisplayMode and SelectedMode and other properties and later the Calendar is added to the
LayoutRoot.
private void CreateDynamicCalendar()
{
Calendar MonthlyCalendar = new Calendar();
MonthlyCalendar.Name = "MonthlyCalendar";
MonthlyCalendar.Width = 300;
MonthlyCalendar.Height = 400;
MonthlyCalendar.Background = Brushes.LightBlue;
MonthlyCalendar.DisplayMode = CalendarMode.Month;
MonthlyCalendar.SelectionMode = CalendarSelectionMode.SingleRange;
MonthlyCalendar.DisplayDateStart = new DateTime(2010, 3, 1);
MonthlyCalendar.DisplayDateEnd = new DateTime(2010, 3, 31);
MonthlyCalendar.SelectedDates.Add(new DateTime(2010, 3, 5));
MonthlyCalendar.SelectedDates.Add(new DateTime(2010, 3, 15));
MonthlyCalendar.SelectedDates.Add(new DateTime(2010, 3, 25));
MonthlyCalendar.FirstDayOfWeek = DayOfWeek.Monday;
MonthlyCalendar.IsTodayHighlighted = true;
LayoutRoot.Children.Add(MonthlyCalendar);
}

Listing 16

Summary
In this chapter, we learnt how we can create a Calendar control in WPF and C#. We also saw how to set
display modes, selection modes, blackout dates, selected dates, border, background, and foreground
properties. After that, we learnt to format the Calendar. In the end of this chapter, we saw how to
create a Calendar dynamically.

270 @ C# Corner
Checkbox
A checkbox is another WPF control that permits the user to make a choice. A choice between one of two
possibilities. Such as 'yes' or 'no'. This control stores value into Boolean type which could be either true
or false.

Creating a CheckBox
The CheckBox element represents a WPF CheckBox control in XAML.

<CheckBox/>

The Content attribute represents the text of a CheckBox.

The Name/x:Name attribute represents the name of the control, which is a unique identifier of a
control.
The Content attribute defines the text of the CheckBox.
The Foreground attribute defines the foreground color of the Content that appears next to CheckBox.
FontFamily, FontStyle, FontWeight, FontSize and FontStretch are other font related attributes.

The code snippet in Listing 1 creates a CheckBox control and sets the name, content, foreground, and
font related properties of a CheckBox control.

<CheckBox x:Name="CheckBoxControl"
Content="Check Me"
Foreground="Red"
FontFamily="Georgia"
FontSize="15"
FontWeight="ExtraLight"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>

Listing 1

The output looks like Figure 1.

Figure 1

271 @ C# Corner
The IsChecked property specifies the state of the CheckBox control. The IsThreeState property specifies
whether the CheckBox has two or three states. Three states are checked, unchecked, or indeterminate.

The default state of IsChecked is false, i.e. if we don’t specify the IsChecked attribute its gonna set false
by default. As shown in figure 1. Now the code snippet in Listing 2 sets IsChecked and IsThreeState
properties of the CheckBox.

<CheckBox x:Name="CheckBoxControl"
Content="Check Me"
Foreground="Red"
FontFamily="Georgia"
FontSize="15"
FontWeight="ExtraLight"
IsChecked="True"
IsThreeState="True"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>

Listing 2

Figure 2 shows the checkbox when IsChecked is true.

Figure 2

Figure 3 shows the checkbox in indecision state.

Figure 3

272 @ C# Corner
Adding an Event Handler to CheckBox’s Click Event
The Checked and Unchecked attributes of the CheckBox are associated with a checked and unchecked
event handler. These events are fired when a CheckBox state is changed to checked and unchecked
respectively. The code in Listing 3 adds these two event handlers.

<CheckBox x:Name="CheckBoxControl"
Content="Check Me"
Checked="CheckBoxControl_Checked"
Foreground="Red"
FontFamily="Georgia"
FontSize="15"
FontWeight="ExtraLight"
IsChecked="True"
IsThreeState="True"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Unchecked="CheckBoxControl_Unchecked"/>

Listing 3

The code for the click event handler looks like following listing 4.

private void CheckBoxControl_Checked(object sender, RoutedEventArgs e)


{
}

private void CheckBoxControl_Unchecked(object sender, RoutedEventArgs e)


{
}

Listing 4

The code listed in Listing 4 sets the content of a CheckBox on both checked and unchecked events.
When you check or uncheck the CheckBox, you will notice the content of the CheckBox changing.

private void CheckBoxControl_Checked(object sender, RoutedEventArgs e)


{
CheckBoxControl.Content = "Checked";
}

private void CheckBoxControl_Unchecked(object sender, RoutedEventArgs e)


{
CheckBoxControl.Content = "UnChecked";
}
Listing 5

Figure 4 is showing the checked event handler.

273 @ C# Corner
Listing 4

Figure 5 is showing an unchecked event handler.

Listing 5

Creating a CheckBox Dynamically


The code listed in Listing 6 creates a CheckBox control and sets some of its properties at run-time.

private void CreateDynamicCheckBox()


{
CheckBox chb = new CheckBox();
chb.Content = "Click me";
chb.IsChecked = true;
chb.Foreground = new SolidColorBrush(Colors.Orange);
chb.IsChecked = true;
LayoutRoot.Children.Add(chb);
}

Listing 6

Summary
In this chapter, we discussed how we can create a CheckBox control in WPF at design-time using XAML
and at run-time using C# and learnt it’s various states and necessary attributes.

274 @ C# Corner
ComboBox
A ComboBox control is an items control that works as a ListBox control except only one item from the
collection can be selected at a time. Basically ComboBox is a collection of items. The entire list is visible
once you click on the control and then the user can pick an item from the collection. Unlike ListBox
control, a ComboBox does not have multiple item selection. A ComboBox control is a combination of
three controls – A Button, a Popup, and a TextBlock. The Button control is used to show or hide available
items and Popup control displays items it is holding and allows users to select one of the items. The
TextBlock control then displays the selected item.

This chapter demonstrates how to create and use a ComboBox control in WPF.

Introduction
The ComboBox element represents a ComboBox control in XAML.

<ComboBox></ComboBox>

The Width and Height attributes specify the width and the height of a ComboBox. The x:Name attribute
specifies the name of the control, which is a unique identifier of a control. The Margin property sets the
position of a ComboBox on the parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

The code snippet in Listing 1 creates a ComboBox control and sets the name, height, and the width of a
ComboBox control. The code also sets the vertical and horizontal alignment of the ComboBox and sets
the margin.

<ComboBox x:Name="ComboBoxControl"
Height="30"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="200" />

Listing 1

The output looks like Figure 1.

275 @ C# Corner
Figure 1

You can define items for ComboBox at compile time itself, by using ComboBoxItem attribute under
ComboBox’s opening and closing tags or you can directly bind a list to a ComboBox at runtime.

The IsSelected property of the ComboBoxItem sets an item to be a selected item from the list. The
following code snippet sets the IsSelected property of a ComboBox.

<ComboBoxItem Content="Coffee"
IsSelected="True" />

Adding ComboBox Items


A ComboBox control hosts a collection of ComboBoxItem. The code snippet in Listing 2 adds items to a
ComboBox control at design-time using XAML.

<ComboBox x:Name="ComboBoxControl"
Height="30"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="200" >
<ComboBoxItem Content="Coffee" IsSelected="True"/>
<ComboBoxItem Content="Tea"/>
<ComboBoxItem Content="Orange Juice"/>
<ComboBoxItem Content="Milk"/>
<ComboBoxItem Content="Iced Tea"/>
<ComboBoxItem Content="Mango Shake"/>
</ComboBox>

Listing 2

The above code snippet generates an output as shown in figure 2.

Figure 2

276 @ C# Corner
Adding and Deleting ComboBox Items at Run-time
In the previous section, we saw how to add items to a ComboBox at design-time with XAML. Now let's
add items to a ComboBox at run-time.

The Items property is used to set ComboBox’s items, it accepts an ItemsCollection object. To add and
remove items from the collection, we can make use of Add, Remove or RemoveAt methods of the
ItemsCollection.

Let’s modify our UI and add a TextBox and a Button control to the page. The XAML code in Listing 3 adds
a TextBox and a Button controls to the UI.

<TextBox x:Name="TextBoxControl"
Height="30"
Margin="0 10 0 0"
VerticalAlignment="Top"
Width="200"/>
<Button x:Name="AddButton"
Click="AddButton_AddItems"
Content="Add Item"
Height="30"
Margin="285 10 0 0"
Width="80"
VerticalAlignment="Top"/>

Listing 3

The final UI looks like Figure 3.

Figure 3

On Button click’s event handler, we have to add the content of TextBox to the ComboBox’s collection by
calling ComboBox.Items.Add method. The code in Listing 4 adds TextBox contents to the ComboBox
items.

private void AddButton_AddItems(object sender, RoutedEventArgs e)


{
ComboBoxControl.Items.Add(TextBoxControl.Text);
}

Listing 4

277 @ C# Corner
Now when a user enters a text in the TextBox and clicks on an Add Item Button, the text will be added to
the list of ComboBox. As shown in figure 4, users have entered a string such as “Smoothie” in this
example and it will get added to the list.

Figure 4

We can use the ComboBox.Items.Remove or ComboBox.Items.RemoveAt method to delete an item


from the collection of items. The RemoveAt method takes the index of the item to be deleted from the
collection.

Now, Let’s modify our application and add a new button for delete operation. The XAML for this button
is shown in Listing 5.

<Button x:Name="DeleteButton"
Click="DeleteButton_DeleteItems"
Content="Delete Item"
Height="30"
Margin="450 10 0 0"
VerticalAlignment="Top"
Width="80"/>

Listing 5

The new page looks like Figure 5.

Figure 5

The delete Button’s click event handler looks like Listing 6. On this Button’s click, we find the index of
the selected item and call ComboBox.Items.RemoveAt method and pass the selected item as parameter.

278 @ C# Corner
Now if you click on the Delete button, the selected item will be removed from the ComboBox’s items.
Listing 6 shows the logic for the RemoveAt method.

private void DeleteButton_DeleteItems(object sender, RoutedEventArgs e)


{
ComboBoxControl.Items.RemoveAt(ComboBoxControl.Items.IndexOf(ComboBoxControl.
SelectedItem));
}

Listing 6

We are selecting “Orange Juice” and later clicking on “Delete Item” Button in figure 7.

Figure 7

Figure 8 shows the list of ComboBox items and it has deleted the “Orange Juice” item from the list.

Figure 8

279 @ C# Corner
Formatting and Styling ComboBox Items
The Foreground and Background attributes of ComboBoxItem specify the background and foreground
colors of the item. The following code snippet sets background and foreground color of a
ComboBoxItem.

<ComboBox x:Name="ComboBoxBeverages"
Background="LightCoral"
Foreground="Red"
Height="30"
Width="200">
Listing 7

The FontFamily, FontSize, and FontWeight are used to set a font of a ComboBoxItem. The following code
snippet sets font family to verdana, font size to 12, and font weight to bold of a ComboBoxItem.

<ComboBox x:Name="ComboBoxBeverages"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red"
Height="30"
Width="200">

Listing 8

The code snippet in Listing 9 sets the formatting of the ComboBox items.

<ComboBox x:Name="ComboBoxBeverages"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red"
Height="30"
Width="200">
<ComboBoxItem x:Name="ComboBoxItemCoffee"
Background="LightCoral"
Foreground="Red"
Content="Coffee"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
IsSelected="True"/>
<ComboBoxItem x:Name="ComboBoxItemTea"
Background="LightGray"
Foreground="Black"
Content="Tea"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"/>
<ComboBoxItem x:Name="ComboBoxItemOJ"
Background="LightBlue"

280 @ C# Corner
Foreground="Purple"
Content="Orange Juice"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"/>
<ComboBoxItem x:Name="ComboBoxItemMilk"
Background="LightGreen"
Foreground="Green"
Content="Milk"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"/>
<ComboBoxItem x:Name="ComboBoxItemIcedTea"
Background="LightBlue"
Foreground="Blue"
Content="Iced Tea"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"/>
<ComboBoxItem x:Name="ComboBoxItemMangoShake"
Background="LightSlateGray"
Foreground="Orange"
Content="Mango Shake"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"/>
</ComboBox>

Listing 9

The new ComboBox with all styles looks like Figure 9.

Figure 9

Display an Image in ComboBox Items


We can put any controls inside a ComboBoxItem, even an image. To show an image next to some text,
we have to add an Image and TextBlock control and club them together inside a StackPanel. The
Image.Source property takes the source of the image you would like to display in the Image control and
TextBlock.Text property takes a string that you would like to display in the TextBlock.

The code snippet in Listing 10 adds an image and text to a ComboBoxItem.

281 @ C# Corner
<ComboBoxItem x:Name="ComboBoxItemCoffee"
Background="LightCoral"
Foreground="Red"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
IsSelected="True">
<StackPanel Orientation="Horizontal">
<Image Source="Coffee.jpg" Height="30"></Image>
<TextBlock Text="Coffee"/>
</StackPanel>
</ComboBoxItem>

Listing 10

The ComboBox item with an image looks like Figure 10.

Figure 10

Adding CheckBoxes to the ComboBox Items


You can easily add checkbox control as a child of ComboBoxItem control. Advantage of this is that users
can now select multiple items at a time. To take this behavior to the next level you can even add image
and text next to the checkbox. So the final hierarchy would be ComboBoxItem -> CheckBox ->
StackPanel -> Image, TextBlock.

The code snippet in Listing 11 adds a CheckBox with an image and text to a ComboBoxItem.

<ComboBoxItem x:Name="ComboBoxItemCoffee"
Background="LightCoral"
Foreground="Red"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
IsSelected="True">
<CheckBox Name="CheckBoxCoffee">
<StackPanel Orientation="Horizontal">
<Image Source="Coffee.jpg" Height="30"/>
<TextBlock Text="Coffee"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
Listing 11

Let’s change the code for all ComboBoxItems.

282 @ C# Corner
<ComboBox x:Name="ComboBoxBeverages"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red"
Height="30"
Width="200">
<ComboBoxItem x:Name="ComboBoxItemCoffee"
Background="LightCoral"
Foreground="Red"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
IsSelected="True">
<CheckBox Name="CheckBoxCoffee">
<StackPanel Orientation="Horizontal">
<Image Source="Coffee.jpg" Height="30"/>
<TextBlock Text="Coffee"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
<ComboBoxItem x:Name="ComboBoxItemTea"
Background="LightGray"
Foreground="Black"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold">
<CheckBox Name="CheckBoxTea">
<StackPanel Orientation="Horizontal">
<Image Source="Tea.jpg" Height="30"/>
<TextBlock Text="Tea"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
<ComboBoxItem x:Name="ComboBoxItemOJ"
Background="LightBlue"
Foreground="Purple"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold">
<CheckBox Name="CoffieCheckBox">
<StackPanel Orientation="Horizontal">
<Image Source="OJ.jpg" Height="30"/>
<TextBlock Text="Orange Juice"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
<ComboBoxItem x:Name="ComboBoxItemMilk"
Background="LightGreen"
Foreground="Green"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold">
<CheckBox Name="CheckBoxMilk">
<StackPanel Orientation="Horizontal">
<Image Source="Milk.jpg" Height="30"/>

283 @ C# Corner
<TextBlock Text="Milk"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
<ComboBoxItem x:Name="ComboBoxItemIcedTea"
Background="LightBlue"
Foreground="Blue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold">
<CheckBox Name="CheckBoxIcedTea">
<StackPanel Orientation="Horizontal">
<Image Source="IceTea.jpg" Height="30"/>
<TextBlock Text="Iced Tea"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
<ComboBoxItem x:Name="ComboBoxItemMangoShake"
Background="LightSlateGray"
Foreground="Orange"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold">
<CheckBox Name="CheckBoxMangoShake">
<StackPanel Orientation="Horizontal">
<Image Source="MangoShake.jpg" Height="30"/>
<TextBlock Text="Mango Shake"/>
</StackPanel>
</CheckBox>
</ComboBoxItem>
</ComboBox>
Listing 12

Now, the new ComboBox with checkbox and images looks like Figure 11.

Figure 11

284 @ C# Corner
Data Binding
The ItemsSource property of ComboBox is used to bind a collection of IEnumerable such as an Array, list
etc. The code listed in Listing 13 creates an array of strings.

private string[] LoadComboBoxData()


{
string[] listOfBevrages =
{
"Coffee",
"Tea",
"Orange Juice",
"Milk",
"Mango Shake",
"Iced Tea",
"Soda",
"Water"
};
return listOfBevrages;
}

Listing 13

The following line of code sets the ItemsSource property of a ComboBox to load the list of beverages.

ComboBoxBeverages.ItemsSource = LoadComboBoxData();

Listing 14

Figure 12 shows an output of listing 13 and 14.

Figure 12

285 @ C# Corner
Creating ComboBox Dynamically
The ComboBox class in WPF represents a ComboBox control. The code snippet in Listing 15 creates a
ComboBox at run-time and adds a few items to the ComboBox.

private void CreateDynamicComboBox()


{
ComboBox cbx = new ComboBox();
cbx.Name = "ComboBox1";
cbx.Width = 194;
cbx.Height = 30;
ComboBoxItem item = new ComboBoxItem();
item.Content = "Coffee";
cbx.Items.Add(item);
cbx.Items.Add("Tea");
cbx.Items.Add("Orange");
cbx.Items.Add("Milk");
cbx.Items.Add("Iced Tea");
cbx.Items.Add("Mango Shake");
RootLayout.Children.Add(cbx);
}

Listing 15

Selected and Current Item


Text property of ComboBox specifies the text of the current selected item in a ComboBox.

SelectedItem specifies the currently selected item in a ComboBox.

SelectedValue specifies the value of the currently selected item of a ComboBox.

SelectedIndex specifies the index of the currently selected item of a ComboBox.

Example
Let’s understand this whole concept of ComboBox with one final example. What we are going to add a
few in xaml, let’s add 2 Buttons. One Button Will Delete the item and the other will ‘find and replace”
the item.

The XAML would look like listing 16.

<Canvas Name="LayoutRoot">
<Label x:Name="labelFind"
Content="Find"

286 @ C# Corner
Height="27"
Width="94"
Canvas.Left="37"
Canvas.Top="12" />
<TextBox x:Name="FindTextBox"
Height="28"
VerticalContentAlignment="Center"
Width="121"
Canvas.Left="137"
Canvas.Top="12" />
<Label x:Name="labelReplace"
Content="Replace with"
Height="27"
Width="94"
Canvas.Left="38"
Canvas.Top="52" />
<TextBox x:Name="ReplaceWithTextBox"
Height="31"
VerticalContentAlignment="Center"
Width="123"
Canvas.Left="138"
Canvas.Top="48" />
<Button x:Name="DeleteButton"
Content="Delete"
Click="DeleteButton_Click"
Height="27"
Width="94"
Canvas.Left="30"
Canvas.Top="90"/>
<Button x:Name="FindReplaceButton"
Content="Find and Replace"
Click="FindReplaceButton_Click"
Height="28"
Width="123"
Canvas.Left="138"
Canvas.Top="88" />
<ComboBox x:Name="ComboBoxWebsites"
Height="30"
Width="250"
Canvas.Left="30"
Canvas.Top="132">
<ComboBoxItem x:Name="FirstItem" Content="C# Corner"/>
<ComboBoxItem x:Name="SecondItem" Content="VB.NET Heaven"/>
<ComboBoxItem x:Name="ThirdItem" Content="MSDN"/>
<ComboBoxItem x:Name="FourthItem" Content="Blogs"/>
</ComboBox>
</Canvas>

Listing 16

Now that we have 2 Buttons. We also need actions for those Buttons. So let’s go ahead and do just that.
Listing 17 shows the event-handlers for both click events.

private void FindReplaceButton_Click(object sender, RoutedEventArgs e)


{
foreach (var item in ComboBoxWebsites.Items)

287 @ C# Corner
{
string search = ((ComboBoxItem)item).Content.ToString();
if (search == FindTextBox.Text)
{
((ComboBoxItem)item).Content = ReplaceWithTextBox.Text;
return;
}
}
}

private void DeleteButton_Click(object sender, RoutedEventArgs e)


{
foreach (var item in ComboBoxWebsites.Items)
{
if (((ComboBoxItem)item).Content.ToString() ==
FindTextBox.Text)
{

ComboBoxWebsites.Items.Remove(((ComboBoxItem)item).Content.ToString());
return;
}
}
}

Listing 17

Now let’s run this project. You would notice as shown in figure 13, our list has 4 items. And let’s try to
replace the last entry which is “Blogs” with “Articles”.

Figure 13

288 @ C# Corner
To do that, we need to add “Blogs” in Find TextBox and “Articles” in Replace TextBox. Then go ahead
and click the “Find and Replace” Button. You would immediately notice the list has been updated and
the last entry of Blogs has been replaced with Articles.

Figure 14

Now let’s delete one entry from the list. Just add the name of the item you wish to delete in Find
TextBox and click on a Delete Button. Items will be deleted and the list will be updated as shown in
figure 15.

289 @ C# Corner
Figure 15

Summary
In this chapter, we learnt how to create and use a ComboBox control. We saw how we can add items to
a ComboBox, customize ComboBoxItem’s content by adding images and checkboxes. In the end of this
chapter, we saw how data binding works in ComboBox and how to load ComboBox dynamically.

DataGrid

290 @ C# Corner
In this Chapter, you will learn how to use a WPF DataGrid control, set its properties, and load data from
a collection.

Introduction
DataGrid element represents WPF DataGrid control in XAML.
<DataGrid />

The Width and Height properties specify the width and the height of a DataGrid. The Name property
specify the name of the control, which is a unique identifier of a control. The Margin property sets the
margin meaning the placement of DataGrid on the window. The following code snippet sets the name,
height, width, and margin of a DataGrid control.
<DataGrid Name="DataGridExample"
Height="150"
HorizontalAlignment="Left"
Margin="20"
VerticalAlignment="Top"
Width="300" />

Listing 1

If you run the project, you’d be able to see output as figure 1. Since we don’t have any data in a grid it
would be blank.

Figure 1

Data Binding

291 @ C# Corner
The ItemSource property of DataGrid is the key to data binding. You can bind any data source that
implements IEnuemerable. Each row in the DataGrid is bound to an object in the data source and each
column in the DataGrid is bound to a property of the data source objects.

In the following example, we will create a collection of objects and bind it to a DataGrid control.

First, we are going to add a class to the project: The Actor class. It’s blueprint looks like Listing 2 that has
ID, Name, DOB, Age.
public class Actor
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime DOB { get; set; }
public int Age { get; set; }
public bool WonOscar { get; set; }
}

Listing 2

Now let's create a collection of Actor objects with the help of List. The LoadCollectionData method in
Listing 3 creates a List of Actor objects.

private List<Actor> LoadCollectionData()


{
List<Actor> actors = new List<Actor>();
actors.Add(new Actor()
{
ID = 1,
Name = "Johnny Depp",
DOB = new DateTime(1963, 6, 9),
Age = 58,
}); WonOscar = false

actors.Add(new Actor()
{
ID = 2,
Name = "Leonardo DiCaprio",
DOB = new DateTime(1974, 11, 11),
Age = 46,
}); WonOscar = true

actors.Add(new Actor()
{
ID = 3,
Name = "Robert Downey Jr.",
DOB = new DateTime(1965, 4, 4),
Age = 56,
}); WonOscar = false
return actors;
}

292 @ C# Corner
Listing
293
Now the last step is to set the ItemsSource property of DataGrid. The following code snippet sets the
ItemsSource property of a DataGrid to List of Actors.
DataGridExample.ItemsSource = LoadCollectionData();

Listing 4

After loading the data in DataGrid the output looks like figure 2.

Figure 2

As you noticed in figure 2, all public properties of the Actor class are used as columns of the DataGrid.
This is because by default, the AutoGenerateColumns property of DataGrid is true. If you do not wish to
generate automatic columns, you simply need to set this property to false.
AutoGenerateColumns = false;

Setting Column Width and Row Height


The ColumnWidth and RowHeight properties of DataGrid are used to set the default column width and
row height of DataGrid columns and rows.

The following code snippet sets column width and row height to 150 and 30 respectively.

<DataGrid Name="DataGridExample"
ColumnWidth="150"
Height="150"
HorizontalAlignment="Left"
Margin="20"
RowHeight="30"
VerticalAlignment="Top"
Width="400" />

293 @ C# Corner
Listing
294

Figure 3

The MaxWidth and MaxHeight properties specify the maximum width and maximum height of a
DataGrid. The MinWidth and MinHeight specify the minimum width and maximum height of a DataGrid.
The MaxColumnWidth and MinColumnWidth properties specify the maximum width and minimum
width of columns in a DataGrid.

Grid Lines Visibility and Header Visibility


The GridLinesVisibility property is used to make grid lines visible. Using this option, you can show and
hide grid lines. Enum supports these 4 values: vertical, horizontal, all, or none. The HeaderVisibility
property is used to show and hide row and column headers.

The following code snippet makes vertical grid lines visible and header visible for both rows and
columns.
GridLinesVisibility="Vertical"
HeadersVisibility="All"

After setting these 2 properties, your output would look like figure 4.

294 @ C# Corner
Figure 4

Grid Background, Row Background, and Alternative Row Background


The Background property is used to set the background color of the DataGrid. The RowBackground and
AlternativeRowBackground properties are used to set the background color of rows and alternative of
the DataGrid.

The following code snippet sets background, row background, and alternative row background colors of
a DataGrid.

Background="LightGray"
RowBackground="LightYellow"
AlternatingRowBackground="LightBlue"

After setting these 3 properties, your output would look like figure 5.

Figure 5

295 @ C# Corner
Border Color and Thickness

The BorderBrush and BorderThickness properties are used to set the color and width of the border. The
following code snippet sets border color to gray and thickness to 5.

BorderBrush="Gray"
BorderThickness="5"

After setting these 2 properties, your output would look like figure 6.

Figure 6

Read Only and Freezing

The IsReadOnly property is used to make a DataGrid read only. That means you cannot edit a DataGrid.
The following code snippet sets IsReadOnly property to true.
IsReadOnly="True"

The AreRowDetailsFrozen property is used to freeze the row details area so it cannot be resized. The
FrozenColumnCount property represents the number of columns that user cannot scroll horizontally.
The following code snippets sets AreRowDetailsFrozen to true and FrozenColumnCount to 2.

AreRowDetailsFrozen="True"
FrozenColumnCount="2"

DataGrid allows you to reorder columns by dragging a column but you may disable this feature by
setting the CanUserReorderColumns property to false. The following code snippet sets
CanUserReorderColumns properties to false.
CanUserReorderColumns="False"

296 @ C# Corner
DataGrid also allows you to change the width of columns. You can have fix width for columns so user
can't resize them by setting the CanUserResizeColumns property to false. The following code snippet
sets CanUserResizeColumns properties to false.

CanUserResizeColumns="False"

Sorting

By default, column sorting is enabled on a DataGrid. You can sort a column by simply clicking on the
column header. You may disable this feature by setting CanUserSortColumns property to false. The
following code snippet sets CanUserSortColumns properties to false.

CanUserSortColumns = "False"

Scrolling

The HorizontalScrollBarVisibility and VerticalScrollBarVisibility properties of type ScrollBarVisibility


enumeration control. It has four values - Auto, Disabled, Hidden, and Visible. The default value of these
properties is Auto, that means, when scrolling is needed, you will see it, otherwise it will be hidden.

The following code snippet enables the horizontal and vertical scrollbars.
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"

If you add both properties to DataGrid then you’d be able to see output as figure 7.

Figure 7

Selection Mode

The SelectionMode property decides if the DataGrid allows only a single row or multiple rows selection.
It has two values – Single and Extended. The following code snippet sets the SelectionMode to
Extended.

297 @ C# Corner
SelectionMode="Extended"

Summary

In this chapter, we demonstrated how to use a DataGrid control in WPF, set its properties and display
data using an object collection. We also discussed how to format rows, columns, their visibility, and
scrolling. In the end we saw how to make rows read-only and set selection mode property.

298 @ C# Corner
DatePicker
A DatePicker control lets the user pick a date and fire an event on the selection of the date. This chapter
demonstrates how to create and use a DatePicker control in WPF with the help of XAML and C#.

DatePicker is almost the same as calendar control except for one main difference. The DatePicker looks
like a dropdown with a calendar, meaning the user must select the dropdown to make the calendar
visible, on other hand the calendar is always visible to users.

Creating a DatePicker
In XAML the DatePicker tag is used to represent a DatePicker control.

<DatePicker/>

The DatePicker control is defined in the System.Windows.Controls namespace. The code snippet in
Listing 1 creates a DatePicker control and sets the name, height, width and horizontal, vertical alignment
properties for the same.

<DatePicker x:Name="DatePickerExample"
Height="25"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="115" />
Listing 1

The Width and Height attributes of the DatePicker element specify the width and the height of a
DatePicker. The Content attribute specifies the text of a DatePicker. The Name attribute sets the name
of the control, which is a unique identifier of a control.

When you run this code, you will see a TextBox with text “Select a date” and when you click on this
TextBox or the date, Calendar dropdown will appear where you can select a date. The selected date will
be shown in the TextBox as you can see in Figure 1.

299 @ C# Corner
Figure 1

Display Date
The DisplayDate property represents the date to be displayed. The default is today.

IsDropDownOpen
The IsDropDownOpen property indicates if the calendar part of the DatePicker control is visible or not.

Text Property
The Text property represents the text that is displayed in the DatePicker.

Selection Date and Selection Date Format


The SelectedDate property specifies the currently selected date. If multiple dates selection is enabled,
then the SelectedDates property is used which refers to a collection of currently selected dates.

BlackoutDates
The BlackoutDates property of the DatePicker class specifies a collection of dates which are not available
for selection. All non-selection dates are marked by a cross. For example, say in October month of year
2021, we would like to block dates from Oct 1st to Oct 7th and then all Sundays. We can achieve this with
BlackoutDates, listing 2 shows how to use BlackoutDates in XAML.

<DatePicker x:Name="DatePickerExample"
Height="25"
HorizontalAlignment="Left"
Margin="50"
VerticalAlignment="Top"
Width="115">
<DatePicker.BlackoutDates>
<CalendarDateRange Start="10/1/2021" End="10/9/2021"/>
<CalendarDateRange Start="10/10/2021" End="10/10/2021"/>
<CalendarDateRange Start="10/17/2021" End="10/17/2021"/>
<CalendarDateRange Start="10/24/2021" End="10/24/2021"/>
</DatePicker.BlackoutDates>
</DatePicker>

Listing 2

The final output looks like figure 2.

300 @ C# Corner
Figure 2

We can even achieve the same behavior programmatically, code listed in Listing 3 demonstrates how we
can do this in code-behind. The BlackoutDates.Add method takes a CalendarDateRange object, which is
a collection of two DateTime objects. The first date is the start date of the range and the second date is
the end date of the date range.

private void SetBlackOutDates()


{
DatePickerExample.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2021, 10, 1),
new DateTime(2021, 10, 9)
));
DatePickerExample.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2021, 10, 10),
new DateTime(2021, 10, 10)
));
DatePickerExample.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2021, 10, 17),
new DateTime(2021, 10, 17)
));
DatePickerExample.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2021, 10, 24),
new DateTime(2021, 10, 24)
));
}

Listing 3

DisplayDateStart and DisplayDateEnd


The Calendar control allows you to set the start and end display dates by using the DisplayDateStart and
DisplayDateEnd properties. Let’s say a client asks you to start October month from Oct 10th rather than
Oct 1st and end it on Oct 20th. Weird I know, but the client is god so let’s do these changes. We can use

301 @ C# Corner
the DisplayStartDate and DisplayEndDate properties to control the start and end date’s visibility of a
month.

The following code snippet sets the DisplayDate, DisplayDateStart and DisplayDateEnd attributes of the
Calendar element in XAML.

<DatePicker x:Name="DatePickerExample"
DisplayDateStart="10/10/2021"
DisplayDateEnd="10/20/2021"
Height="25"
HorizontalAlignment="Left"
Margin="50"
VerticalAlignment="Top"
Width="115"/>

Listing 4

Same thing can be achieved programmatically as well as shown in listing 5.

private void SetDisplayDates()


{
DatePickerExample.DisplayDate = new DateTime(2021, 10, 13);
DatePickerExample.DisplayDateStart = new DateTime(2021, 10, 10);
DatePickerExample.DisplayDateEnd = new DateTime(2021, 10, 20);
}

Listing 5

The new DatePicker looks like Figure 3.

Figure 3

FirstDayOfWeek and IsTodayHighlighted

302 @ C# Corner
By default, Sunday is the first day of the week. If you would like to change that it’s possible with the
FirstDayOfWeek property. The IsTodayHightlighted property is used to make today highlighted.

The following code snippet in listing 6 sets the FirstDayOfWeek to Tuesday and makes highlights today.
<DatePicker x:Name="DatePickerExample"
DisplayDateStart="10/1/2021"
DisplayDateEnd="10/30/2021"
FirstDayOfWeek="Tuesday"
Height="25"
HorizontalAlignment="Left"
IsTodayHighlighted="True"
Margin="50"
VerticalAlignment="Top"
Width="115">

Listing 6

Listing 7 shows how to do the same programmatically.

DatePickerExample.FirstDayOfWeek = DayOfWeek.Tuesday;
DatePickerExample.IsTodayHighlighted = true;

Listing 7

The new DatePicker looks like Figure 4, where you can see the start day of the week on Tuesday. And
today’s date when I am writing this chapter is 14th October.

Figure 4

Selected Date

303 @ C# Corner
The SelectedDate property specifies the current selected date. The following code snippet sets the
SelectedDates in XAML at design-time.
SelectedDate="10/15/2021"

After setting the above property you’d be able to see results as Figure 5 where October 15th is selected.
A light blue background color represents the selected date.

Figure 5

The following code snippet sets the SelectedDate property in WPF at run-time.

private void AddSelectedDates()


{
DatePickerExample.SelectedDate = (new DateTime(2021, 10, 15));
}
Listing 8

Formatting a DatePicker
Let’s format a DatePicker bit. We can change the border, background and foreground of the DatePicker.

The BorderBrush property of the Calendar sets a brush to draw the border of a DatePicker. You may use
any brush to fill the border. The following code snippet uses a linear gradient brush to draw the border
with a combination of red and blue color.

<DatePicker.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>

304 @ C# Corner
</DatePicker.BorderBrush>

Listing 9

The Background and Foreground properties of the DatePicker are used to set the background and
foreground colors of a DatePicker. You may use any brush to fill the border. The following code snippet
uses linear gradient brushes to draw the background and foreground of a DatePicker.

<DatePicker.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</DatePicker.Background>
<DatePicker.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Black" Offset="0.25" />
<GradientStop Color="Green" Offset="1.0" />
</LinearGradientBrush>
</DatePicker.Foreground>

Listing 10

Figure 6

Creating a DatePicker Dynamically


The code listed in Listing 11 creates a DatePicker control programmatically. First, it creates a DatePicker
object and sets its DisplayMode and SelectedMode and other properties and later the DatePicker is
added to the LayoutRoot.

private void CreateDynamicDatePicker()


{
DatePicker MonthlyCalendar = new DatePicker();
MonthlyCalendar.Name = "MonthlyCalendar";
MonthlyCalendar.Width = 300;
MonthlyCalendar.Height = 400;

305 @ C# Corner
MonthlyCalendar.Background = Brushes.LightBlue;
MonthlyCalendar.DisplayMode = CalendarMode.Month;
MonthlyCalendar.SelectionMode = CalendarSelectionMode.SingleRange;
MonthlyCalendar.DisplayDateStart = new DateTime(2010, 3, 1);
MonthlyCalendar.DisplayDateEnd = new DateTime(2010, 3, 31);
MonthlyCalendar.SelectedDates.Add(new DateTime(2010, 3, 5));
MonthlyCalendar.SelectedDates.Add(new DateTime(2010, 3, 15));
MonthlyCalendar.SelectedDates.Add(new DateTime(2010, 3, 25));
MonthlyCalendar.FirstDayOfWeek = DayOfWeek.Monday;
MonthlyCalendar.IsTodayHighlighted = true;
LayoutRoot.Children.Add(MonthlyCalendar);
}

Listing 11

Summary
In this chapter, we learnt how we can create a DatePicker control in WPF and C#. We also saw how to
set display modes, selection modes, blackout dates, selected dates, border, background, and foreground
properties. After that, In the end of the chapter, we saw how to create a DatePicker dynamically.

306 @ C# Corner
Expander
The WPF Expander represents a control with an expanded view where the contents can be expanded or
collapsed. There are two ways you can achieve this in WPF. We can create an Expander control at
design-time using the <Expander> element of XAML. We can also use the Expander class in C# to create
an expander at run-time. An Expander control provides a way to provide content in an expandable area
that resembles a window and it includes a header.

This XAML code shows how to create an Expander control in WPF.

<Expander x:Name="ExpanderControl"
Header="Click to Expand"
HorizontalAlignment="Left" >
<TextBlock x:Name="TextBlockContent"
FontSize="14"
FontWeight="Light"
Foreground="Black"
Margin="5"
Text="This is an Expander control. Within this control, all
contents will be wrapped. At run-time, you may expand or collapse this
control. Type more text here to be typed. Jump around and hype."
TextWrapping="Wrap" />
</Expander>

Listing 1

The default view of an Expander control looks like this.

Figure 1

307 @ C# Corner
If you click on the header, the expanded view will appear as shown in figure 2.

Figure 2

We can style the contents of the expander. Code snippet in listing 2 sets a few font styles to the content.

<Expander Name="ExpanderControl"
Background="DarkGray"
ExpandDirection="Down"
FontSize="20"
FontWeight="Bold"
Foreground="Lavender"
Header="Click to Expand"
HorizontalAlignment="Left"
IsExpanded="False" >
<TextBlock TextWrapping="Wrap" >
This is an Expander control. Within this control, all contents
will be wrapped. At run-time, you may expand or collapse this control. Type
more text here to be typed.Jump around and hype.
</TextBlock>
</Expander>

Listing 2

The new output looks like this.

308 @ C# Corner
Figure 3

How to create an Expander control dynamically


The Expander class in WPF represents an Expander control.

This code snippet in listing 3 creates an Expander control at run-time.


private void CreateDynamicExpander()
{
Expander dynamicExpander = new Expander();
dynamicExpander.Header = "Dynamic Expander";
dynamicExpander.HorizontalAlignment = HorizontalAlignment.Left;
dynamicExpander.Background = new SolidColorBrush(Colors.Lavender);
dynamicExpander.Width = 250;
dynamicExpander.IsExpanded = false;
dynamicExpander.Content = "This is a dynamic expander";
RootGrid.Children.Add(dynamicExpander);

Listing 3

How to set the direction of an Expander Control?


ExpandDirection property of Expander control sets the direction of Header. It can be Up, Down, Left,
and Right. The following code snippet sets the ExpandDirection to Up.
ExpandDirection="Up"

The control with Up direction looks like this.

Figure 4

How to add a Scrolling to an Expander Control

309 @ C# Corner
By adding a Scrollviewer control in the contents of an Expander adds scrolling to the Expander. Listing 4
demonstrated this behavior.

<Expander Name="ExpanderControl"
Background="LavenderBlush"
ExpandDirection="Down"
HorizontalAlignment="Left"
IsExpanded="False"
Foreground="Green"
FontSize="20"
FontWeight="Bold"
Width="350">
<Expander.Header>
<BulletDecorator>
<BulletDecorator.Bullet>
<Image Width="50"/>
</BulletDecorator.Bullet>
<TextBlock Margin="20,0,0,0">Flower Header</TextBlock>
</BulletDecorator>
</Expander.Header>
<Expander.Content>
<ScrollViewer Height="100" VerticalAlignment="Top" >
<TextBlock TextWrapping="Wrap" FontSize="14"
FontWeight="Light" Foreground="Black">
This is an Expander control. Within this control, all
contents will be wrapped.
At run-time, you may expand or collapse this control. Type
more text here to be typed.
Jump around and hype. This is an Expander control. Within
this control, all contents will be wrapped.
At run-time, you may expand or collapse this control. Type
more text here to be typed.
Jump around and hype.
</TextBlock>
</ScrollViewer>
</Expander.Content>
</Expander>

Listing 4

Expander control with a scroll viewer looks like Figure 5. You’d also notice that the style for header and
the content is different.

310 @ C# Corner
Figure 5

FlowDocumentReader
The FlowDocumentReader control is used to view FlowDocument elements. A flow document itself is
designed to adjust the content of the file. The content of the file is directly proportional to the size of
the window. Flow documents have some in- built features. We can load files such as txt or pdf.

It would be much easier to understand this behavior with an example.

The following code snippet in listing 1, we are creating FlowDocumentReader and then we will load a
text file by browsing through Windows’s file explorer. It uses OpenFileDialog to browse text files and
once a text file is selected, it is loaded in a FlowDocumentReader that allows you to view, paging, and
find options.

<Window x:Class="FlowDocumentReader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:FlowDocumentReader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="TextBoxFileName"
Height="32"
HorizontalAlignment="Left"
Margin="5 5 0 0"
VerticalAlignment="Top"
Width="400" />
<Button x:Name="ButtonBrowse"
Content="Browse"
Click="ButtonBrowse_Click"
Height="32"
HorizontalAlignment="Right"
Margin="5 5 0 0"
VerticalAlignment="Top"
Width="100"
Grid.Column="1"/>
<FlowDocumentReader x:Name="FlowDocReader"
Background="LightBlue"

311 @ C# Corner
Height="210"
HorizontalAlignment="Left"
Width="560"
Grid.ColumnSpan="2"
Grid.Row="1"/>
</Grid>
</Window>

Listing 1

We need a logic to load the file and assign it in a FlowDocument. We can add this logic on a Button’s
click event. Code snippet in listing 2 shows how to open a dialog box and load a file which can then be
assigned to a FlowDocument’s object.

using System;
using System.Windows;
using System.Windows.Documents;

namespace FlowDocumentReader
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

public void ButtonBrowse_Click(object sender, RoutedEventArgs e)


{

// Create OpenFileDialog
Microsoft.Win32.OpenFileDialog dlg = new
Microsoft.Win32.OpenFileDialog();

// Set filter for file extension and default file extension


dlg.DefaultExt = ".txt";
dlg.Filter = "Text documents (.txt)|*.txt";

// Display OpenFileDialog by calling ShowDialog method


Nullable<bool> result = dlg.ShowDialog();

// Get the selected file name and display in a TextBox


if (result == true)
{
// Open document
string filename = dlg.FileName;
TextBoxFileName.Text = filename;

Paragraph paragraph = new Paragraph();


paragraph.Inlines.Add(System.IO.File.ReadAllText(filename));
FlowDocument document = new FlowDocument(paragraph);
FlowDocReader.Document = document;

312 @ C# Corner
}
}
}
}

Listing 2

Now if you run the project, you’d see a TextBox, a Browse Button and a FlowDocumentReader as shown
in figure 1.

Figure 1

Once you click on a Browse Button and select a text file. It will load a path of the file into a TextBox and
a content of the file into a FlowDocumentReader. You would be able to see output same as figure 2

313 @ C# Corner
Figure 2

In figure 3, we are using a couple of in-build features of FlowDocumentReader. As you can see we are
searching for keyword “C#” and we zoomed in on a text. As we zoom in it will load the text which would
fit into the current size of the window rest will be cropped. You can always resize the window and adjust
the text as per your needs. You can navigate through pages with page navigation control next to search
control, followed by you can view documents into different layouts by selecting specific viewing mode
and lastly you can zoom in or out into the file.

Figure 3

314 @ C# Corner
Frame
The Frame control in WPF supports content navigation within content. A Frame can be hosted within a
Window, NavigationWindow, Page, UserControl, or a FlowDocument control. In nutshell, you can use
one window within another using Frames.

How to create a Frame in WPF?


Let’s create a UserControl which will act as a frame for our MainWindow. Code snippet in listing 1 has a
TextBlock and its background color has been set to gray.

<UserControl x:Class="Frame.FrameExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Frame"
mc:Ignorable="d"
Height="200" Width="400"
Background="Gray">
<Grid>
<TextBlock x:Name="TextBlockLabel"
Margin="10"
Text="This is the frame."/>
</Grid>
</UserControl>

Listing 1

315 @ C# Corner
Now it’s time to add Frame control in out MainWindow. Code snippet in listing 2 shows how to create a
Frame control and sets its Source property to load a UserControl that we created in listing 1.

<Window x:Class="Frame.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Frame"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="800">
<Grid>
<Grid Margin="10">
<TextBlock Text="Outside area of frame"/>
<Frame Source="FrameExample.xaml"/>
</Grid>
</Grid>
</Window>

Listing 2

When you run the program, you’d notice the Frame has loaded UserControl inside a MainWindow and
output looks like Figure 1.

Figure 1

Now you can manage the contents of a frame the way you want.

For example, the following code rotates the contents of the frame to 45 angles.

<Frame Source="Page1.xaml">
<Frame.LayoutTransform>
<RotateTransform Angle="45" />
</Frame.LayoutTransform>
</Frame>

Listing 3

316 @ C# Corner
The new output looks like figure 2.

Figure 2

How to Navigate to a URI in a WPF Frame?


Let’s show a frame on a Button-click event. For this we need to define a frame’s position. The following
code snippet in listing 4 creates a Frame within a Window and adds a Button control to the window. On
the Button’s click event handler we are going to navigate to a URI using a Frame.

<Window x:Class="Frame.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Frame"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="800">
<Grid>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Outside area of frame"/>
<Button Name="ButtonNavigation"
Content="Navigate to a frame"
Click="ButtonNavigation_Click"
Height="20"
HorizontalAlignment="Left"
Margin="0 10 0 0"
VerticalAlignment="Top"
Width="200"
Grid.Row="1"/>
<Frame x:Name="FrameUserControl"
Margin="0 10 0 0"

317 @ C# Corner
Grid.Row="2"/>
</Grid>
</Grid>
</Window>
Listing 4

Listing 5 is a click event handler of a Button. We are making use of the Navigate method, which is used
to navigate to a URI. The following code navigates to FrameExample.xaml.

private void ButtonNavigation_Click(object sender, RoutedEventArgs e)


{
FrameUserControl.Navigate(new System.Uri("FrameExample.xaml",
UriKind.RelativeOrAbsolute));
}

Listing 5

Figure 3 shows how the window would look before clicking a button.

Figure 3

Figure 4 shows how the window would look after clicking a button.

318 @ C# Corner
Figure 4

The following code snippet in listing 6 shows how to navigate to an external website URL.

FrameUserControl.Source = new Uri("http://www.c-


sharpcorner.com/Default.aspx", UriKind.Absolute);

Listing 6

If you wish to open a URI in a new browser window, then we first need to create an instance of a
NavigationWindow and then sets its Source to a URI.

NavigationWindow window = new NavigationWindow();


Uri source = new Uri("http://www.c-sharpcorner.com/Default.aspx",
UriKind.Absolute);
window.Source = source; window.Show();

Listing 7

319 @ C# Corner
GroupBox
A GroupBox control is used to arrange controls together, so if it's providing us the same feature as any
other panel out there why should you choose a GroupBox over a panel. Answer is simple: GroupBox also
lets us add a header to an area and within that area you can place child controls.

By default, a GroupBox can only have one child control but we can leverage containers to extend this
capability to add multiple children. We can use any panels such as a Grid, StackPanel, WrapPanel etc.

How to create a GroupBox in WPF?


To create a GroupBox we must use the GroupBox element in XAML. The following code snippet creates
a GroupBox control, sets its background and font. The code also sets the header by using
GroupBox.Header.

Let’s create a WPF application for user’s registration. Listing 1 has a Grid panel with TextBox, Label and
Buttons as child controls.

320 @ C# Corner
<Window x:Class="GroupBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:GroupBox"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="400">
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelUserName"
Content="User Name:"
Margin="0 10 0 0"/>
<Label x:Name="LabelDOB"
Content="DOB:"
Grid.Row="1"/>
<Label x:Name="LabelAge"
Content="Age:"
Grid.Row="2"/>
<Label x:Name="LabelEmailId"
Content="Email:"
Grid.Row="3"/>

<TextBox x:Name="TextBoxUserName"
Text="Alex"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>
<DatePicker x:Name="DatePickerDOB"
SelectedDate="1/1/2021"
DisplayDateStart="1/1/1990"
Width="150"
Grid.Column="1"
Grid.Row="1"/>
<Rectangle
Stroke="LightGray"
StrokeThickness="1"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>
<TextBlock x:Name="TextBlockAge"
Text="25"

321 @ C# Corner
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>

<TextBox x:Name="TextBoxEmail"
Text="Alex@gmail.com"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="3"/>
<StackPanel x:Name="StackPanelButtons"
Orientation="Horizontal"
Grid.ColumnSpan="2"
Grid.Row="4" >
<Button x:Name="ButtonRegister"
Height="20"
Width="100"
Content="Register"
HorizontalAlignment="Center"
Margin="20 10 0 0" />

<Button x:Name="ButtonReset"
Height="20"
Width="100"
Content="Reset"
HorizontalAlignment="Center"
Margin="20 10 0 0" />
</StackPanel>
</Grid>
</Window>
Listing 1

Let’s run this application. Below figure is an output of Listing 1, This is how controls nicely arrange with
panel. Grid in this case.

Figure 1

Now let’s wrap the grid around GroupBox. Advantage of GroupBox is that you can format the whole
group in a single attempt, you don’t have to style every single element in the container.

322 @ C# Corner
Code snippet in listing 2 wraps the GroupBox around the Grid

<GroupBox Margin="10,10,10,10" FontSize="10" FontWeight="SemiBold"


Background="LightGray">
<GroupBox.Header>
Registration Form
</GroupBox.Header>

<Grid HorizontalAlignment="Center"
VerticalAlignment="Center">

..

..

..

</Grid>

</GroupBox>

listing 2

Now let’s run this code and see how it looks. Also, you’d see that we have added a Header for
GroupBox.

Figure 2

As you may observe Background, font size and font weight has been applied to the whole form. Also, a
header has been applied. In this chapter, we learn how to use a WPF GroupBox. It's easy to use and
can save a lot of repeating code.

323 @ C# Corner
Imaging
The Image Class
The Image class is used to load and view an image in WPF. This class displays .bmp, .gif, .ico, .jpg, .png,
.wdp, and .tiff files. If a file is a multi-frame image, then only the first frame is displayed. The frame
animation is not supported by this class.

The Source property holds the object of a BitmapImage which takes Image as a parameter.

ImageViewer1.Source = new BitmapImage(new Uri("Creek.jpg",


UriKind.Relative));
Listing 1

In the above code snippet, you’d notice there is second parameter UriKind, It lets you select and option
if the image is relative to the application path or has an absolute path.

Let’s jump back to XAML, code snippet in listing 2 creates a WPF application with two labels, a button,
and an Image control. The XAML code looks like this:

<Grid x:Name="GridRoot"
Background="LightBlue">
<Grid.RowDefinitions>

324 @ C# Corner
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelFile"
Content="Current File:"
Height="23"
Margin="10,0,0,0"/>
<Label x:Name="FileNameLabel"
Height="25"
Margin="5,0,0,0"
Width="300" />
<Button x:Name="ButtonBrowse"
Click="ButtonBrowse_Click"
Content="Browse"
Height="23"
Margin="5,0,0,0"
Width="75"
Grid.Column="1"/>
<Image x:Name="ImageViewer"
Height="400"
Width="400"
Grid.ColumnSpan="2"
Grid.Row="1"/>
</Grid>
Listing 2

The application’s UI looks like figure 1

325 @ C# Corner
Figure 1.

The code snippet for Browse button’s click event handler is as follows.

private void ButtonBrowse_Click(object sender, RoutedEventArgs e)


{
OpenFileDialog dlg = new OpenFileDialog();
dlg.InitialDirectory = "c:\\";
dlg.Filter = "Image files (*.jpg)|*.jpg|All Files (*.*)|*.*";
dlg.RestoreDirectory = true;

if (dlg.ShowDialog() == true)
{
string selectedFileName = dlg.FileName;
FileNameLabel.Content = selectedFileName;
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(selectedFileName);
bitmap.EndInit();
ImageViewer.Source = bitmap;
}
}
Listing 3

Browse button will open up a dialog box which will let you select an image file, the same will be
displayed below the button and part of the file will be shown in a label.

Figure 2.

326 @ C# Corner
How to view an Image in WPF?
In listing 2, we set an image from the code behind. Same can be achieved in XAML as well, using the
same Source property. The following syntax shows a Windows.jpg file using Image control.

<Image Source="Windows.jpg" />

You can control the width and height of an image that is being displayed in Image control by setting its
Width and Height properties.

<Image Width="300" Height="200" Source=" Windows.jpg" />

One other way to set the Image.Source is by creating a BitmapImage. The following code snippet uses
BitmapImage created from a URI.

<Image Width="300">
<Image.Source>
<BitmapImage DecodePixelWidth="200" UriSource="Flower.jpg" />
</Image.Source>
</Image>

Listing 4

How to view an Image in WPF Dynamically?


The Image class in WPF represents an Image control. The following code snippet creates an Image
control, sets its width, height, and Source properties.

private void CreateViewImageDynamically()


{
// Create Image and set its width and height
Image dynamicImage = new Image();
dynamicImage.Width = 300;
dynamicImage.Height = 200;

// Create a BitmapSource
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(@"…\Windows.JPG");
bitmap.EndInit();

// Set Image.Source
dynamicImage.Source = bitmap;

// Add Image to Window


LayoutRoot.Children.Add(dynamicImage);
}

327 @ C# Corner
Listing 5

How to stretch an Image in WPF using Image control?


The Stretch property of Image describes how an Image should be stretched to fill its container. It causes
your image to stretch till it covers the whole area. When the container area and the image have
different aspect ratios, the image is distorted by this stretching. To make an Image preserve the aspect
ratio of the image, set Stretch property to Uniform.

The StretchDirection property of Image describes how scaling applies to content and restricts scaling to
named axis types. It has three values – UpOnly, DownOnly, and Both. The UpOnly value indicates that
the image is scaled upward only when it is smaller than the parent. The DownOnly value indicates that
the image is scaled downward when it is larger than the parent. The Both value stretches the image to
fit its parent.

The following code snippet sets Stretch and StretchDirection of an Image control.

private void CreateViewImageDynamically()


{
// Create Image and set its width and height
Image dynamicImage = new Image();
dynamicImage.Stretch = Stretch.Fill;
dynamicImage.StretchDirection = StretchDirection.Both;
dynamicImage.Width = 300;
dynamicImage.Height = 200;

// Create a BitmapSource
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(@"C:\Books\Book WPF\How do
I\ImageSample\ImageSample\Flower.JPG");
bitmap.EndInit();

// Set Image.Source
dynamicImage.Source = bitmap;

// Add Image to Window


LayoutRoot.Children.Add(dynamicImage);
}

Listing 6

How to rotate an Image in WPF?


The Rotation property of BitmapImage is used to rotate an image. It has four values – Rotate0,
Rotate90, Rotate180, and Rotate270. The following code snippet rotates an image to 270 degrees.

<Image Width="300">
<Image.Source>

328 @ C# Corner
<BitmapImage DecodePixelWidth="200" UriSource="Windows.jpg"
Rotation="Rotate180" />
</Image.Source>
</Image>

Listing 7

How to apply grayscale on an Image in WPF?


The FormatConvertedBitmap is used to apply formatting on images in WPF. The
FormatConvertedBitmap.Source property is a BitmapImage that will be used in the formatting process.

The code snippet in Listing 8 creates a BitmapImage.

BitmapImage bitmap = new BitmapImage();


bitmap.BeginInit();
bitmap.UriSource = new Uri(@"…\Windows.JPG");
bitmap.EndInit();
Listing 8

This code snippet in Listing 9 creates an instance of FormatConvertedBitmap and assigns the
BitmapImage as a source.

FormatConvertedBitmap grayBitmapSource = new FormatConvertedBitmap();


grayBitmapSource.BeginInit();
grayBitmapSource.Source = bitmap;
Listing 9

The DestinationFormat property of FormatConvertedBitmap is used to apply formatting on images. The


follow code snippet sets an image to gray.

grayBitmapSource.DestinationFormat = PixelFormats.Gray32Float;
grayBitmapSource.EndInit();
Listing 10

The complete source code looks like Listing 11.

private void GrayScaleButton_Click(object sender, RoutedEventArgs e)


{
// Create a BitmapSource
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(@"…\Windows.JPG");
bitmap.EndInit();

// Create a FormatConvertedBitmap
FormatConvertedBitmap grayBitmapSource = new FormatConvertedBitmap();

// BitmapSource objects like FormatConvertedBitmap can only have their


properties
// changed within a BeginInit/EndInit block.
grayBitmapSource.BeginInit();

329 @ C# Corner
// Use the BitmapSource object defined above as the source for this new
// BitmapSource (chain the BitmapSource objects together).
grayBitmapSource.Source = bitmap;

// Key of changing the bitmap format is Destination Format property of


BitmapSource.
// It is a type of PixelFormat. FixelFormat has dozens of options to set
// bitmap formatting.
grayBitmapSource.DestinationFormat = PixelFormats.Gray32Float;
grayBitmapSource.EndInit();

// Create a new Image


Image grayImage = new Image();
grayImage.Width = 300;
// Set Image source to new FormatConvertedBitmap
grayImage.Source = grayBitmapSource;

// Add Image to Window


LayoutRoot.Children.Add(grayImage);

Listing 11

How to crop an Image in WPF?


CroppedBitmap is used for cropping an image. It takes a BitmapImage as source and a shape of
rectangle to which you wish to crop an image.

The following code snippet crops and displays an image.

private void CropImageButton_Click(object sender, RoutedEventArgs e)


{
// Create a BitmapImage
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(@"…\Windows.JPG");
bitmap.EndInit();

// Create an Image
Image croppedImage = new Image();
croppedImage.Width = 200;
croppedImage.Margin = new Thickness(2);

// Create a CroppedBitmap from BitmapImage


CroppedBitmap cb = new CroppedBitmap((BitmapSource)bitmap,
new Int32Rect(20, 20, 100, 100));
// Set Image.Source to cropped image
croppedImage.Source = cb;

// Add Image to Window


LayoutRoot.Children.Add(croppedImage);

330 @ C# Corner
}

Listing 12

Label
This chapter demonstrates how to create and use a Label control in WPF using XAML and C#.

Creating a Label
Syntax:

<Label/>

The Width and Height attributes of the Label element specify the width and the height of a Label. The
Content attribute of the Label element sets the text of a Label. The Name attribute represents the name
of the control, which is a unique identifier of a control.

The code snippet in Listing 1 creates a Label control and sets the name, height, width, and content of a
Label control. The code also sets the font format for the text.

<Label Name="LabelExample"
Content="Hello! I am Label Control"
Height="40"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Width="200" />

331 @ C# Corner
Listing 1

The output looks like Figure 1.

Figure 1

The Background and Foreground properties used to set the background and foreground colors of the
Label control. The code snippet in Listing 2 sets the background, foreground, and alignment of a Label
control.

<Label Name="LabelExample"
Background="Black"
Content="Hello! I am Label Control"
Height="40"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="200" />

Listing 2

The new output looks like Figure 2.

Figure 2

Adding Contents to a Label Control

332 @ C# Corner
The Content property basically used to specify the text of a label. If we want to show some other
content rather than just a text, to achieve this all we need to do is add that control inside the opening
and closing bracket of a Label.

Note: Label only has one child element, as shown in Listing 3, StackPanel is the child of a Label in the
form of its content. If we try to add one more control as a child, WPF will give you an exception “The
property Content can only be set once.”

<Label Name="LabelExample">
<StackPanel Orientation="Horizontal">
<Ellipse Width="100" Height="100" Fill="Red" />
<Ellipse Width="80" Height="80" Fill="Orange" />
<Ellipse Width="60" Height="60" Fill="Yellow" />
<Ellipse Width="40" Height="40" Fill="Green" />
<Ellipse Width="20" Height="20" Fill="Blue" />
<Ellipse Width="15" Height="15" Fill="Indigo" />
<Ellipse Width="10" Height="10" Fill="Violet" />
</StackPanel>
</Label>

Listing 3

Listing 3 generates an output that looks like Figure 3.

Figure 3

Formatting a Label
The Background and Foreground properties of the Label set the background and foreground colors of a
Label. You may use any brush to fill the border. The following code snippet uses linear gradient brushes
to draw the background and foreground of a Label.

<Label.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Black" Offset="1.0" />
</LinearGradientBrush>

333 @ C# Corner
</Label.Background>
<Label.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="1.0" />
</LinearGradientBrush>
</Label.Foreground>

Listing 4

The new Label looks like Figure 4.

Figure 4

Setting Image as Background of a Label


The following code snippet in listing 5 sets the background of a Label to an image.

<Label.Background>
<ImageBrush ImageSource="Background.jpg" />
</Label.Background>

Listing 5

The new output looks like Figure 5.

Figure 5

Summary

334 @ C# Corner
In this chapter, we learnt how we can create a Label control in WPF and C#. We also saw how to format
a Label by setting its background, and foreground properties. At last, we saw how to set an image as the
background of a Label.

ListBox
In this chapter we will learn to create and use a ListBox control available in Windows Presentation
Foundation (WPF).

Introduction
The ListBox tag represents a ListBox control in XAML.

<ListBox></ListBox>

The Width and Height properties specify the width and the height of a ListBox. The Name property
specifies the name of the control, which is a unique identifier of a control. The Margin property specifies
the location of a ListBox on the parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

The following code snippet sets the name, height, and width of a ListBox control. The code also sets
horizontal alignment to left and vertical alignment to top.

<ListBox x:Name="ListBoxBeverage"
Height="200"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="194"/>

335 @ C# Corner
Listing 1
Adding ListBox Items

A ListBox control hosts a collection of ListBoxItem within XAML itself. The following code snippet adds
items to a ListBox control.

<ListBox x:Name="ListBoxBeverage"
Height="200"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="194">
<ListBoxItem Content="Coffee"></ListBoxItem>
<ListBoxItem Content="Tea"></ListBoxItem>
<ListBoxItem Content="Orange Juice"></ListBoxItem>
<ListBoxItem Content="Milk"></ListBoxItem>
<ListBoxItem Content="Iced Tea"></ListBoxItem>
<ListBoxItem Content="Mango Shake"></ListBoxItem>
</ListBox>

Listing 2

Code snippet in Listing 1 generates Figure 1.

Figure 1. ListBox with items

Adding ListBox Items Dynamically

In the previous section, we saw how to add items to a ListBox at design-time from XAML. We can add
items to a ListBox from the code as well.

336 @ C# Corner
Let’s change our UI and add a TextBox and a Button control to the page. The XAML code for the TextBox
and Button controls is shown in listing 3.

<TextBox Name="TextBoxBeverage"
Height="23"
HorizontalAlignment="Left"
Margin="8,14,0,0"
VerticalAlignment="Top"
Width="127" />
<Button Name="ButtonAddItem"
Content="Add Item"
Click="ButtonAddItem_Click"
Height="23"
HorizontalAlignment="Left"
Margin="140,14,0,0"
VerticalAlignment="Top"
Width="76" />

Listing 3
The final UI looks like Figure 2.

Figure 2

On Button’s click event handler, we are adding the content of TextBox to the ListBox by calling
ListBox.Items.Add method. The following code snippet adds TextBox contents to the ListBox items.

private void ButtonAddItem_Click(object sender, RoutedEventArgs e)


{
ListBoxBeverage.Items.Add(TextBoxBeverage.Text);
}

Listing 4

337 @ C# Corner
Now if you enter text in the TextBox and click the Add Item button, it will add contents of the TextBox to
the ListBox.

Figure 3. Adding ListBox items dynamically

Deleting ListBox Items

We can use ListBox.Items.Remove or ListBox.Items.RemoveAt method to delete an item from the


collection of items in the ListBox. The RemoveAt method takes the index of the item in the collection.

Now, Let’s modify our application and add a new button called Delete Item. The XAML code for this is
listed in the following code snippet.

<Button x:Name="ButtonDeleteItem"
Content="Delete Item"
Click="ButtonDeleteItem_Click"
Height="23"
HorizontalAlignment="Left"
Margin="220 14 0 0"
VerticalAlignment="Top"
Width="76"/>
Listing 5

The button’s click event handler looks like the following. On this button click, we find the index of the
selected item and call ListBox.Items.RemoveAt method as following.

private void ButtonDeleteItem_Click(object sender, RoutedEventArgs e)


{

338 @ C# Corner
ListBoxBeverage.Items.RemoveAt

(ListBoxBeverage.Items.IndexOf(ListBoxBeverage.SelectedItem));
}

Listing 6

Figure 4

Formatting and Styling


Formatting ListBox Items

The Foreground and Background attributes of ListBoxItem specify the background and foreground colors
of the item. The following code snippet sets background and foreground color of a ListBoxItem.

<ListBoxItem Background="LightCoral" Foreground="Red" Content="Coffee"/>

The FontFamily, FontSize, and FontWeight are used to set the styling of the font. The code snippet in
listing 7 sets font verdana, size 12, and bold of a ListBoxItem.

<ListBoxItem x:Name="ListBoxItemCoffee"
Background="LightCoral"
Content="Coffee"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red" />
Listing 7
Let’s style all the items of the ListBox.

339 @ C# Corner
<ListBoxItem x:Name="ListBoxItemCoffee"
Background="LightCoral"
Content="Coffee"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red" />
<ListBoxItem x:Name="ListBoxItemTea"
Background="LightGray"
Content="Tea"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Black" />
<ListBoxItem x:Name="ListBoxItemOrangeJuice"
Background="LightBlue"
Content="Orange Juice"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Purple" />
<ListBoxItem x:Name="ListBoxItemMilk"
Background="LightGreen"
Content="Milk"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Green" />
<ListBoxItem x:Name="ListBoxItemIcedTea"
Background="LightBlue"
Content="Iced Tea"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Blue" />
<ListBoxItem x:Name="ListBoxItemMangoShake"
Background="LightSlateGray"
Content="Mango Shake"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange" />

Listing 5

The new ListBox looks like Figure 5.

340 @ C# Corner
Figure 5. Formatted ListBox

Displaying Images in a ListBox

We can put any controls inside a ListBoxItem such as an image and text. To display an image next to
text, we can simply arrange an Image and a TextBlock control within a StackPanel. The Image.Source
property takes the name of the image you would like to display in the Image control and TextBlock.Text
property takes a string that you would like to display in the TextBlock.

The code snippet in listing 6 demonstrates how to add an image and text to a ListBoxItem.

<ListBox x:Name="ListBoxBeverage"
Height="200"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="207"
Grid.Row="1">
<ListBoxItem x:Name="ListBoxItemCoffee"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red">
<StackPanel Orientation="Horizontal">
<Image Source="Coffee.jpg" Height="30"/>
<TextBlock Text="Coffee"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemTea"
Background="LightGray"
FontFamily="Georgia"
FontSize="14"

341 @ C# Corner
FontWeight="Bold"
Foreground="Black">
<StackPanel Orientation="Horizontal">
<Image Source="Tea.jpg" Height="30"/>
<TextBlock Text="Tea"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemOrangeJuice"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Purple">
<StackPanel Orientation="Horizontal">
<Image Source="OJ.jpg" Height="30"/>
<TextBlock Text="Orange Juice"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemMilk"
Background="LightGreen"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Green">
<StackPanel Orientation="Horizontal">
<Image Source="Milk.jpg" Height="30"/>
<TextBlock Text="Milk"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemIcedTea"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Blue">
<StackPanel Orientation="Horizontal">
<Image Source="IceTea.jpg" Height="30"/>
<TextBlock Text="Iced Tea"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemMangoShake"
Background="LightSlateGray"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange">
<StackPanel Orientation="Horizontal">
<Image Source="MangoShake.jpg" Height="30"/>
<TextBlock Text="Mango Shake"/>
</StackPanel>
</ListBoxItem>
</ListBox>

Listing 6
After modifying our code as per listing 6, the final ListBox looks like figure 6.

342 @ C# Corner
Figure 6. ListBoxItems with Image and text

ListBox with CheckBoxes

You can easily add any item inside StackPanel. Let’s add a checkbox alongside the image.

The following code snippet adds a CheckBox besides an image and text to a ListBoxItem.

<ListBox x:Name="ListBoxBeverage"
Height="200"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="207"
Grid.Row="1">
<ListBoxItem x:Name="ListBoxItemCoffee"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxCoffee" Margin="5"/>
<Image Source="Coffee.jpg" Height="30"
Width="30"/>
<TextBlock Text="Coffee" Margin="5"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemTea"
Background="LightGray"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"

343 @ C# Corner
Foreground="Black">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxTea" Margin="5"/>
<Image Width="30" Source="Tea.jpg" Height="30"/>
<TextBlock Text="Tea" Margin="5"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemOrangeJuice"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Purple">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxOrangeJuice" Margin="5"/>
<Image Width="30" Source="OJ.jpg" Height="30"/>
<TextBlock Text="Orange Juice" Margin="5"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemMilk"
Background="LightGreen"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Green">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxOrangeMilk" Margin="5"/>
<Image Width="30" Source="Milk.jpg" Height="30"/>
<TextBlock Text="Milk" Margin="5"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemIcedTea"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Blue">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxIcedTea" Margin="5"/>
<Image Width="30" Source="IceTea.jpg" Height="30"/>
<TextBlock Text="Iced Tea" Margin="5"/>
</StackPanel>
</ListBoxItem>
<ListBoxItem x:Name="ListBoxItemMangoShake"
Background="LightSlateGray"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxMangoShake" Margin="5"/>
<Image Width="30" Source="MangoShake.jpg" Height="30"/>
<TextBlock Text="Mango Shake" Margin="5"/>
</StackPanel>
</ListBoxItem>
Listing 7

344 @ C# Corner
Now, the final ListBox looks like Figure 7.

Figure 7. ListBox with CheckBoxes

345 @ C# Corner
Data Binding
When it comes to data binding, we need to first understand the type of data. Data could be in any one
of the forms from the following list.

● Objects
● Relational database such as SQL Server
● XML/JSON
● Other controls

Data Binding with Objects


The ItemsSource property of ListBox is used to bind a collection of IEnumerable such as an ArrayList to
the ListBox control.

// Bind ArrayList with the ListBox


LeftListBox.ItemsSource = LoadListBoxData();

private ArrayList LoadListBoxData()


{
ArrayList itemsList = new ArrayList();
itemsList.Add("Coffee");
itemsList.Add("Tea");
itemsList.Add("Orange Juice");
itemsList.Add("Milk");
itemsList.Add("Mango Shake");
itemsList.Add("Iced Tea");
itemsList.Add("Soda");
itemsList.Add("Water");
return itemsList;
}

Listing 8

Transferring data from one ListBox to Another

We’ve come across the situation where we need 2 UI elements to communicate i.e. to share data
amongst each other.

The following figures show how we can move items from one ListBox to another. The Add button adds
the selected item to the right ListBox and removes it from the left ListBox. The Remove button removes
the selected item from the right ListBox and adds back to the left ListBox.

346 @ C# Corner
Figure 8: Programmatically Items have been added to the left list.

347 @ C# Corner
Figure 9: Moving items from left to right ListBox by selecting an item and clicking Add Button.

Figure 10: Moving items from right to left ListBox by selecting an item and clicking Remove Button.

The following XAML code snippet in listing 9 generates two ListBox controls and two Buttons.

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="ListBoxLeft"
Margin="5" />
<ListBox x:Name="ListBoxRight"
Margin="5"
Grid.Column="2"/>
<Button x:Name="ButtonAdd"
Height="25"
Margin="5"
VerticalAlignment="Center"
Click="AddButton_Click"
Content="Add &gt;&gt;"
Width="100"
Grid.Column="1"/>
<Button x:Name="ButtonRemove"

348 @ C# Corner
Height="25"
Margin="0 60 0 0"
Click="RemoveButton_Click"
VerticalAlignment="Center"
Content="&lt;&lt; Remove"
Width="100"
Grid.Column="1"/>
</Grid>

Listing 9

On the Window’s loaded event, we need to load data items into ListBox by setting the ItemsSource
property to an ArrayList.

public ArrayList myDataList { get; set; }


public string currentItemText { get; set; }
public int currentItemIndex { get; set; }

private void Window_Loaded(object sender, RoutedEventArgs e)


{
// Get data from somewhere and fill in my local ArrayList
myDataList = LoadListBoxData();
// Bind ArrayList with the ListBox
ListBoxLeft.ItemsSource = LoadListBoxData();
}

/// <summary>
/// Generate data. This method can bring data from a database or XML file
/// or from a Web service or generate data dynamically
/// </summary>
/// <returns></returns>
private ArrayList LoadListBoxData()
{
ArrayList itemsList = new ArrayList();
itemsList.Add("Coffee");
itemsList.Add("Tea");
itemsList.Add("Orange Juice");
itemsList.Add("Milk");
itemsList.Add("Mango Shake");
itemsList.Add("Iced Tea");
itemsList.Add("Soda");
itemsList.Add("Water");
return itemsList;
}

Listing 10

On Add Button’s click event handler, we have to get the value and index of the selected item from the
left ListBox and add that to the right ListBox by removing that item from the ArrayList, which is our data
source. The ApplyBinding method simply removes the current binding of the ListBox and rebinds with
the updated ArrayList.

private void AddButton_Click(object sender, RoutedEventArgs e)

349 @ C# Corner
{
// Find the right item and it's value and index
currentItemText = ListBoxLeft.SelectedValue.ToString();
currentItemIndex = ListBoxLeft.SelectedIndex;

ListBoxRight.Items.Add(currentItemText);
if (myDataList != null)
{
myDataList.RemoveAt(currentItemIndex);
}

// Refresh data binding


ApplyDataBinding();
}

/// <summary>
/// Refreshes data binding
/// </summary>
private void ApplyDataBinding()
{
ListBoxLeft.ItemsSource = null;
// Bind ArrayList with the ListBox
ListBoxLeft.ItemsSource = myDataList;
}

Listing 11

Similarly, on the Remove Button’s click event handler, we get the selected item’s text and index from
the right ListBox then add that to the ArrayList and remove it from the right ListBox.

private void RemoveButton_Click(object sender, RoutedEventArgs e)


{
// Find the right item and it's value and index
currentItemText = ListBoxRight.SelectedValue.ToString();
currentItemIndex = ListBoxRight.SelectedIndex;
// Add RightListBox item to the ArrayList
myDataList.Add(currentItemText);

ListBoxRight.Items.RemoveAt(ListBoxRight.Items.IndexOf(ListBoxRight.SelectedI
tem));

// Refresh data binding


ApplyDataBinding();
}

Listing 12

Data Binding with a Database

Let’s use the most famous Northwind.mdf database, it comes pre-configured with SQL Server. In our
application, we will read data from the Customers table. The Customers table looks like Figure 11.

350 @ C# Corner
Figure 11

We are going to fetch ContactName, Address, City, and Country columns into a WPF ListBox control. The
final ListBox looks like Figure 10.

351 @ C# Corner
Figure 12

Let’s look at the XAML for the same. We must create a DataTemplate type, let’s call it listBoxTemplate. A
data template is used to represent data in a formatted manner. The data template has two dock panels
where the first panel shows the name and the second panel shows address, city, and TextBlock controls
to show the country column.

<Window.Resources>
<DataTemplate x:Key="listBoxTemplate">
<StackPanel Margin="3">
<DockPanel >
<TextBlock FontWeight="Bold" Text="Name:"
DockPanel.Dock="Left"
Margin="5,0,10,0"/>
<TextBlock Text=" " />
<TextBlock Text="{Binding ContactName}" Foreground="Green"
FontWeight="Bold" />
</DockPanel>
<DockPanel >
<TextBlock FontWeight="Bold" Text="Address:" Foreground
="DarkOrange"
DockPanel.Dock="Left"
Margin="5,0,5,0"/>
<TextBlock Text="{Binding Address}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding City}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding Country}" />
</DockPanel>
</StackPanel>

352 @ C# Corner
</DataTemplate>
</Window.Resources>

Now we add a ListBox control and set its ItemsSource property as the first DataTable of the DataSet and
set ItemTemplate to the resource defined above.

<ListBox Margin="17,8,15,26" Name="listBox1" ItemsSource="{Binding


Tables[0]}"
ItemTemplate="{StaticResource listBoxTemplate}" />

Listing 13

Now in our code behind, we must define the following variables.

public SqlConnection connection;


public SqlCommand command;
string sql = "SELECT ContactName, Address, City, Country FROM Customers";
string connectionString = @"Data
Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NORTHWND.MDF;Integrated
Security=True;Connect Timeout=30;User Instance=True";

Now on Windows_Loaded method, we call BindData method and in BindData method, we create a
connection, data adapter, and fill the DataSet using SqlDataAdapter.Fill() method.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
BindData();
}

private void BindData()


{
DataSet dtSet = new DataSet();
using (connection = new SqlConnection(connectionString))
{
command = new SqlCommand(sql, connection);
SqlDataAdapter adapter = new SqlDataAdapter();
connection.Open();
adapter.SelectCommand = command;
adapter.Fill(dtSet, "Customers");
listBox1.DataContext = dtSet;

}
}

Listing 14

Data Binding with XML

Now let’s bind XML data to a ListBox control. The XmlDataProvider is used to bind XML data in WPF.

Here is an XmlDataProvider defined in XAML that contains books data. The XML data is defined within
the x:Data tag.

353 @ C# Corner
<XmlDataProvider x:Key="BooksData" XPath="Inventory/Books">
<x:XData>
<Inventory xmlns="">
<Books>
<Book Category="Programming" >
<Title>A Programmer's Guide to ADO.NET</Title>
<Summary>Learn how to write database applications using
ADO.NET and C#.
</Summary>
<Author>Mahesh Chand</Author>
<Publisher>APress</Publisher>
</Book>
<Book Category="Programming" >
<Title>Graphics Programming with GDI+</Title>
<Summary>Learn how to write graphics applications using
GDI+ and C#.
</Summary>
<Author>Mahesh Chand</Author>
<Publisher>Addison Wesley</Publisher>
</Book>
<Book Category="Programming" >
<Title>Visual C#</Title>
<Summary>Learn how to write C# applications.
</Summary>
<Author>Mike Gold</Author>
<Publisher>APress</Publisher>
</Book>
<Book Category="Programming" >
<Title>Introducing Microsoft .NET</Title>
<Summary>Programming .NET
</Summary>
<Author>Mathew Cochran</Author>
<Publisher>APress</Publisher>
</Book>
<Book Category="Database" >
<Title>DBA Express</Title>
<Summary>DBA's Handbook
</Summary>
<Author>Mahesh Chand</Author>
<Publisher>Microsoft</Publisher>
</Book>
</Books>

</Inventory>
</x:XData>
</XmlDataProvider>

Listing 15

To bind an XmlDataProvider, we have to bind the Source property inside the ItemsSource to the x:Key of
XmlDataProvider. Code snippet in Listing 16 does exactly what we need to read an XML file into ListBox.

<ListBox Width="400" Height="300" Background="LightGray">


<ListBox.ItemsSource>
<Binding Source="{StaticResource BooksData}"
XPath="*[@Category='Programming'] "/>

354 @ C# Corner
</ListBox.ItemsSource>

<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Title: " FontWeight="Bold"/>
<TextBlock Foreground="Green" >
<TextBlock.Text>
<Binding XPath="Title"/>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Listing 16

The output of the above code looks like Figure 11.

Figure 13

Data Binding with Controls

The last data binding type we are covering is to provide data exchange between a ListBox and other
controls using data binding in WPF.

355 @ C# Corner
Let’s create an application. In Figure 14, we have a ListBox with a list of colors and a TextBox, and a
Canvas. When we pick a color from the ListBox, the text of TextBox and color of Canvas changes
dynamically to the selected color in the ListBox and this is possible to do all in XAML without writing a
single line of code in the code behind the file.

Figure 14

The code snippet in Listing 17 is all we need.

<StackPanel Orientation="Vertical">
<TextBlock
FontWeight="Bold"
Margin="10"
Text="Pick a color from below list"
Width="200"/>
<ListBox x:Name="ListBoxColors"
Height="120"
HorizontalAlignment="Left"
Margin="10"
Width="200">
<ListBoxItem>Orange</ListBoxItem>

356 @ C# Corner
<ListBoxItem>Green</ListBoxItem>
<ListBoxItem>Blue</ListBoxItem>
<ListBoxItem>Gray</ListBoxItem>
<ListBoxItem>LightGray</ListBoxItem>
<ListBoxItem>Red</ListBoxItem>
</ListBox>
<TextBox x:Name="TextBoxColor"
Height="25"
HorizontalAlignment="Left"
Margin="10"
Width="200">
<TextBox.Text>
<Binding ElementName="ListBoxColors"
Path="SelectedItem.Content"/>
</TextBox.Text>
</TextBox>
<Canvas x:Name="CanvasColors"
Height="200"
HorizontalAlignment="Left"
Margin="10"
Width="200">
<Canvas.Background>
<Binding ElementName="ListBoxColors"
Path="SelectedItem.Content"/>
</Canvas.Background>
</Canvas>
</StackPanel>

Listing 17

Pay close attention to TextBox in XAML, you will notice there is a Binding within the TextBox.Text
property, which sets the binding of Text property to another control then just pass the name of the
element who is acting as a source as a ElementName, finally just specify the property of that control
which is holding the data which we are fetching in a Path. So in the code below, we are setting the
SelectedItem.Content property of ListBox to TextBox.Text property.

<TextBox.Text>
<Binding ElementName="ListBoxColors" Path="SelectedItem.Content"/>
</TextBox.Text>

Same applies to the Canvas.Background property. Now, every time you select an item in the ListBox, the
TextBox.Text and Canvas.Background properties are set to that selected item in the ListBox.

<Canvas.Background>
<Binding ElementName="ListBoxColors" Path="SelectedItem.Content"/>
</Canvas.Background>

Summary
In this chapter, we discussed how to create and use a ListBox control available in WPF. We saw how to
add items to a ListBox, change item properties, add images and checkboxes. In the end of the chapter,

357 @ C# Corner
we learned how data binding works in ListBox and how to bind ListBox with data coming from objects,
databases, and other controls.

358 @ C# Corner
ListView
In this chapter we will learn to create and use a ListView control available in Windows Presentation
Foundation (WPF).

Introduction
The ListView tag represents a ListView control in XAML.

<ListView></ListView>

The Width and Height properties specify the width and the height of a ListView. The Name property
specifies the name of the control, which is a unique identifier of a control. The Margin property specifies
the location of a ListView on the parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

The following code snippet sets the name, height, and width of a ListView control. The code also sets
horizontal alignment to left and vertical alignment to top.

<ListView x:Name="ListViewBeverage"
Height="200"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="194"/>

Listing 1
Adding ListView Items

A ListView control hosts a collection of ListViewItem within XAML itself. The following code snippet adds
items to a ListView control.

<ListView x:Name="ListViewBeverage"
Height="200"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="194">
<ListViewItem Content="Coffee"></ListViewItem>
<ListViewItem Content="Tea"></ListViewItem>
<ListViewItem Content="Orange Juice"></ListViewItem>
<ListViewItem Content="Milk"></ListViewItem>
<ListViewItem Content="Iced Tea"></ListViewItem>
<ListViewItem Content="Mango Shake"></ListViewItem>
</ListView>

Listing 2

Code snippet in Listing 1 generates Figure 1.

359 @ C# Corner
Figure 1. ListView with items

Adding ListView Items Dynamically

In the previous section, we saw how to add items to a ListView at design-time from XAML. We can add
items to a ListView from the code as well.

Let’s change our UI and add a TextBox and a Button control to the page. The XAML code for the TextBox
and Button controls is shown in listing 3.

<TextBox Name="TextBoxBeverage"
Height="23"
HorizontalAlignment="Left"
Margin="8,14,0,0"
VerticalAlignment="Top"
Width="127" />
<Button Name="ButtonAddItem"
Content="Add Item"
Click="ButtonAddItem_Click"
Height="23"
HorizontalAlignment="Left"
Margin="140,14,0,0"
VerticalAlignment="Top"
Width="76" />

Listing 3
The final UI looks like Figure 2.

360 @ C# Corner
Figure 2

On Button’s click event handler, we are adding the content of TextBox to the ListView by calling
ListView.Items.Add method. The following code snippet adds TextBox contents to the ListView items.

private void ButtonAddItem_Click(object sender, RoutedEventArgs e)


{
ListViewBeverage.Items.Add(TextBoxBeverage.Text);
}

Listing 4

Now if you enter text in the TextBox and click the Add Item button, it will add contents of the TextBox to
the ListView.

361 @ C# Corner
Figure 3. Adding ListView items dynamically

Deleting ListView Items

We can use ListView.Items.Remove or ListView.Items.RemoveAt method to delete an item from the


collection of items in the ListView. The RemoveAt method takes the index of the item in the collection.

Now, Let’s modify our application and add a new button called Delete Item. The XAML code for this is
listed in the following code snippet.

<Button x:Name="ButtonDeleteItem"
Content="Delete Item"
Click="ButtonDeleteItem_Click"
Height="23"
HorizontalAlignment="Left"
Margin="220 14 0 0"
VerticalAlignment="Top"
Width="76"/>
Listing 5

The button’s click event handler looks like the following. On this button click, we find the index of the
selected item and call ListView.Items.RemoveAt method as following.

private void ButtonDeleteItem_Click(object sender, RoutedEventArgs e)


{
ListViewBeverage.Items.RemoveAt

(ListViewBeverage.Items.IndexOf(ListViewBeverage.SelectedItem));
}

362 @ C# Corner
Listing 6

Figure 4

Formatting and Styling


Formatting ListView Items

The Foreground and Background attributes of ListViewItem specify the background and foreground
colors of the item. The following code snippet sets background and foreground color of a ListViewItem.

<ListViewItem Background="LightCoral" Foreground="Red" Content="Coffee"/>

The FontFamily, FontSize, and FontWeight are used to set the styling of the font. The code snippet in
listing 7 sets font verdana, size 12, and bold of a ListViewItem.

<ListViewItem x:Name="ListViewItemCoffee"
Background="LightCoral"
Content="Coffee"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red" />
Listing 7
Let’s style all the items of the ListView.

<ListViewItem x:Name="ListViewItemCoffee"
Background="LightCoral"
Content="Coffee"
FontFamily="Verdana"

363 @ C# Corner
FontSize="12"
FontWeight="Bold"
Foreground="Red" />
<ListViewItem x:Name="ListViewItemTea"
Background="LightGray"
Content="Tea"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Black" />
<ListViewItem x:Name="ListViewItemOrangeJuice"
Background="LightBlue"
Content="Orange Juice"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Purple" />
<ListViewItem x:Name="ListViewItemMilk"
Background="LightGreen"
Content="Milk"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Green" />
<ListViewItem x:Name="ListViewItemIcedTea"
Background="LightBlue"
Content="Iced Tea"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Blue" />
<ListViewItem x:Name="ListViewItemMangoShake"
Background="LightSlateGray"
Content="Mango Shake"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange" />

Listing 5

The new ListView looks like Figure 5.

364 @ C# Corner
Figure 5. Formatted ListView

Displaying Images in a ListView

We can put any controls inside a ListViewItem such as an image and text. To display an image next to
text, we can simply arrange an Image and a TextBlock control within a StackPanel. The Image.Source
property takes the name of the image you would like to display in the Image control and TextBlock.Text
property takes a string that you would like to display in the TextBlock.

The code snippet in listing 6 demonstrates how to add an image and text to a ListViewItem.

<ListView x:Name="ListViewBeverage"
Height="200"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="207"
Grid.Row="1">
<ListViewItem x:Name="ListViewItemCoffee"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red">
<StackPanel Orientation="Horizontal">
<Image Source="Coffee.jpg" Height="30"/>
<TextBlock Text="Coffee"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemTea"
Background="LightGray"
FontFamily="Georgia"
FontSize="14"

365 @ C# Corner
FontWeight="Bold"
Foreground="Black">
<StackPanel Orientation="Horizontal">
<Image Source="Tea.jpg" Height="30"/>
<TextBlock Text="Tea"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemOrangeJuice"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Purple">
<StackPanel Orientation="Horizontal">
<Image Source="OJ.jpg" Height="30"/>
<TextBlock Text="Orange Juice"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemMilk"
Background="LightGreen"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Green">
<StackPanel Orientation="Horizontal">
<Image Source="Milk.jpg" Height="30"/>
<TextBlock Text="Milk"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemIcedTea"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Blue">
<StackPanel Orientation="Horizontal">
<Image Source="IceTea.jpg" Height="30"/>
<TextBlock Text="Iced Tea"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemMangoShake"
Background="LightSlateGray"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange">
<StackPanel Orientation="Horizontal">
<Image Source="MangoShake.jpg" Height="30"/>
<TextBlock Text="Mango Shake"/>
</StackPanel>
</ListViewItem>
</ListView>

Listing 6
After modifying our code as per listing 6, the final ListView looks like figure 6.

366 @ C# Corner
Figure 6. ListViewItems with Image and text

ListView with CheckBoxes

You can easily add any item inside StackPanel. Let’s add a checkbox alongside the image.

The following code snippet adds a CheckBox besides an image and text to a ListViewItem.

<ListView x:Name="ListViewBeverage"
Height="200"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="207"
Grid.Row="1">
<ListViewItem x:Name="ListViewItemCoffee"
Background="LightCoral"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Red">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxCoffee" Margin="5"/>
<Image Source="Coffee.jpg" Height="30"
Width="30"/>
<TextBlock Text="Coffee" Margin="5"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemTea"
Background="LightGray"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"

367 @ C# Corner
Foreground="Black">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxTea" Margin="5"/>
<Image Width="30" Source="Tea.jpg" Height="30"/>
<TextBlock Text="Tea" Margin="5"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemOrangeJuice"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Purple">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxOrangeJuice" Margin="5"/>
<Image Width="30" Source="OJ.jpg" Height="30"/>
<TextBlock Text="Orange Juice" Margin="5"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemMilk"
Background="LightGreen"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Green">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxOrangeMilk" Margin="5"/>
<Image Width="30" Source="Milk.jpg" Height="30"/>
<TextBlock Text="Milk" Margin="5"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemIcedTea"
Background="LightBlue"
FontFamily="Verdana"
FontSize="12"
FontWeight="Bold"
Foreground="Blue">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxIcedTea" Margin="5"/>
<Image Width="30" Source="IceTea.jpg" Height="30"/>
<TextBlock Text="Iced Tea" Margin="5"/>
</StackPanel>
</ListViewItem>
<ListViewItem x:Name="ListViewItemMangoShake"
Background="LightSlateGray"
FontFamily="Georgia"
FontSize="14"
FontWeight="Bold"
Foreground="Orange">
<StackPanel Orientation="Horizontal">
<CheckBox Name="CheckBoxMangoShake" Margin="5"/>
<Image Width="30" Source="MangoShake.jpg" Height="30"/>
<TextBlock Text="Mango Shake" Margin="5"/>
</StackPanel>
</ListViewItem>
Listing 7

368 @ C# Corner
Now, the final ListView looks like Figure 7.

Figure 7. ListView with CheckBoxes

Data Binding in ListView


The ItemsSource property of ListView is used to bind a collection of IEnumerable such as an ArrayList to
the ListView control.

The following code snippet creates an ArrayList object.

/// <summary>
/// Generate data. This method can bring data from a database or XML file
/// or from a Web service or generate data dynamically
/// </summary>
/// <returns></returns>
private ArrayList LoadListViewData()
{
ArrayList itemsList = new ArrayList();
itemsList.Add("Coffee");
itemsList.Add("Tea");
itemsList.Add("Orange Juice");
itemsList.Add("Milk");
itemsList.Add("Mango Shake");
itemsList.Add("Iced Tea");
itemsList.Add("Soda");
itemsList.Add("Water");
return itemsList;
}

Listing 8

369 @ C# Corner
On the Window loaded event, we create and load data items to the ListView by setting the ItemsSource
property to an ArrayList.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
// Get data from somewhere and fill in my local ArrayList
myDataList = LoadListViewData();
// Bind ArrayList with the ListView
LeftListView.ItemsSource = myDataList;
}
Summary
In this chapter, we discussed how to create and use a ListView control available in WPF. We learned
how we can add items to a ListView, change item properties, add images add check boxes. In the end of
this article, we learned to bind data to ListView.

GridView in WPF
The View property of ListView is a type of ViewBase class that supports two view types – GridView and a
custom view. Data can be represented in tabular format associated with rows and columns.

The following code snippet in listing 9 sets the View property of a ListView to GridView mode.

<ListView>
<ListView.View>
<GridView />
</ListView.View>
</ListView>

Listing 9

A GridView is used as a supplement to a ListView to provide style and layout. The GridView does not
have its own control related properties such as background and foreground colors, font properties, size,
and location. The container ListView is used to provide all these control related properties.

GridView
The GridView element in XAML represents a GridView at design-time. The Columns property of
GridView returns a collection of GridViewColumn objects. The GridViewColumn element in XAML
represents a GridView column. AllowsColumnReorder property ensures whether columns in a GridView

370 @ C# Corner
can be reordered by a user by dragging and dropping from one position to another.
ColumnHeaderToolTip property specifies the content of a tooltip that appears when the mouse pointer
is hover over one of the column headers.

The code snippet in Listing 10 creates a GridView control and adds four columns.

The Header property of GridViewColumn specifies the header of a column. The Width property specifies
the width of a column and the DisplayMemberBinding property is used to bind a GridViewColumn to a
property of data binding object.

<ListView x:Name="ListViewActors">
<ListView.View>
<GridView AllowsColumnReorder="true"
ColumnHeaderToolTip="Actors">
<GridViewColumn
DisplayMemberBinding="{Binding Path=Name}"
Header="Name"
Width="120"
/>
<GridViewColumn
DisplayMemberBinding="{Binding Path=Age}"
Header="Age"
Width="50"
/>
<GridViewColumn
DisplayMemberBinding="{Binding Path=oscarWinner}"
Header="MVP"
Width="50"
/>
</GridView>
</ListView.View>
</ListView>

Listing 10

We are binding a list of actors to GridView, let’s add a few actors to the list in code behind. Code snippet
in listing 11 creates a list of actors and adds 3 entries to the list.

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Actor> items = new List<Actor>();
items.Add(new Actor() { Name = "Johnny Depp", Age = 58,
oscarWinner = false});
items.Add(new Actor() { Name = "leonardo dicaprio", Age = 46,
oscarWinner = true });
items.Add(new Actor() { Name = "Robert Downey jr.", Age = 56,
oscarWinner = false });
ListViewActors.ItemsSource = items;

371 @ C# Corner
}
}
public class Actor
{
public string Name { get; set; }

public int Age { get; set; }

public bool oscarWinner { get; set; }


}

Listing 11

The output of listing 10 and 11 looks like Figure 8.

Figure 8

The GridView class in WPF represents a GridView control. The GridViewColumn class represents a
GridView column. The code listed in Listing 13 creates a GridView control and adds four columns to it
dynamically.

private void CreateDynamicGridView()


{
// Create a GridView
GridView grdView = new GridView();
grdView.AllowsColumnReorder = true;
grdView.ColumnHeaderToolTip = "Actors";

GridViewColumn nameColumn = new GridViewColumn();


nameColumn.DisplayMemberBinding = new Binding("Name");
nameColumn.Header = "Actor Name";
nameColumn.Width = 120;
grdView.Columns.Add(nameColumn);

GridViewColumn ageColumn = new GridViewColumn();


ageColumn.DisplayMemberBinding = new Binding("Age");
ageColumn.Header = "Age";
ageColumn.Width = 30;

372 @ C# Corner
grdView.Columns.Add(ageColumn);

GridViewColumn mvpColumn = new GridViewColumn();


mvpColumn.DisplayMemberBinding = new Binding("Oscar");
mvpColumn.Header = "Oscar ";
mvpColumn.Width = 50;
grdView.Columns.Add(mvpColumn);

ListViewActors.View = grdView;
}

Listing 13

Adding a ContextMenu to a GridView Header


The ColumnHeaderContextMenu property of GridView is used to get or set a ContextMenu when you
right click on the header of a GridView control. The code snippet listed in Listing 14 adds a ContextMenu
to a GridView header.

<GridView AllowsColumnReorder="true"
ColumnHeaderToolTip="Actors">
<!-- Add a ContextMenu to GridView Header -->
<GridView.ColumnHeaderContextMenu>
<ContextMenu >
<MenuItem Header="Ascending" />
<MenuItem Header="Descending" />
</ContextMenu>
</GridView.ColumnHeaderContextMenu>
<!-- Add GridVeiw Columns -->
<GridViewColumn
DisplayMemberBinding="{Binding Path=Name}"
Header="Name"
Width="120"
/>
<GridViewColumn
DisplayMemberBinding="{Binding Path=Age}"
Header="Age"
Width="50"
/>
<GridViewColumn
DisplayMemberBinding="{Binding Path=oscarWinner}"
Header="MVP"
Width="50" />
</GridView>

Listing 14

The output of the listing looks like Figure9.

373 @ C# Corner
Figure 9

Adding a CheckBox to a GridView Header


The ColumnHeaderTemplate property specifies the template for the column header. Using this property,
you can customize GridView column headers the way you want. You may add CheckBoxes or Images to
the column headers.

The code snippet in Listing 15 creates a DataTemplate resource with a CheckBox and DarkBlue
foreground color of text that we can set as a ColumnHeaderTemplate of a GridView.

<Window.Resources>
<DataTemplate x:Key="OrangeHeaderTemplate">
<DockPanel>
<CheckBox/>
<TextBlock FontSize="10" Foreground="DarkBlue"
FontWeight="Bold" >
<TextBlock.Text>
<Binding/>
</TextBlock.Text>
</TextBlock>
</DockPanel>
</DataTemplate>
</Window.Resources>

Listing 15

The code snippet in Listing 5 sets the ColumnHeaderTemplate of a GridView.

<GridView
ColumnHeaderTemplate="{StaticResource OrangeHeaderTemplate}"
AllowsColumnReorder="true"
ColumnHeaderToolTip="Authors">
Listing 16

The output of listing looks like Figure 10.

374 @ C# Corner
Figure 10

375 @ C# Corner
Menus
In WPF, the Menu and the MenuItem classes represent a menu and a menu item respectively. A Menu is
a collection of menu items with a command associated with each menu item. A menu item may have
children called submenus. This chapter discusses how to work with menus in WPF applications using
XAML and C#.

Creating a Menu as Design Time


In XAML, the Menu tag is used to create a menu control.

The Name property defines the name of the menu and Height and Width specifies the height and width
of a menu control.

<Menu Name="MenuExample"
Height="22"
Width="200" />

Listing 1

To set the position of a menu control in a Window, the Margin, HorizontalAlignment and
VerticalAlignment properties may be used. The following code snippet sets horizontal, vertical
alignments, margin, and background color of a menu control.

<Menu Name="MenuExample"
Background="DarkGray"
Height="22"
HorizontalAlignment="Left"
Margin="10, 10, 5, 5"
VerticalAlignment="Top"
Width="200" />

Listing 2

Let’s run the project and see how it looks so far.

Figure 1

376 @ C# Corner
Setting Menu Control Properties

There are three ways to set menu control properties. 1. You may use the Properties windows, 2. Set
properties in XAML manually, 3. Set properties at run-time using WPF code.

If you right click on the menu control and select Properties, you would be able to see the Properties
window same as Figure 2.

377 @ C# Corner
Figure 2. Properties Window

As you can see from Figure 2, you can set all properties of a Menu control through this Window such as
border thickness, opacity, bitmap effects, background and foreground colors, alignments, width and
height, layouts, and fonts etc.

Adding Menu Items and Sub Menus to a Menu

Now let’s add menu items and sub menus to the menu control. The MenuItem tag adds a menu item to
the menu control. The following syntax shows how to create a MenuItem. The Header attribute is the
name of the MenuItem.

<MenuItem Header="Menu Item Name" />

A MenuItem can have other MenuItem tags as children, also known as sub menus and can go up to
several levels. The following code adds three children menu items to the first menu item.

<MenuItem Header="_File">
<MenuItem Header="_Open" IsCheckable="true"/>
<MenuItem Header="_Close" IsCheckable="true"/>
<MenuItem Header="_Save" IsCheckable="true"/>
</MenuItem>

Listing 3

The output looks like Figure 3.

Figure 3. A menu with menu items

A separator is used to separate categories of menu items. We can add a separator to a menu control by
using <Separator /> tag.

Let us show you how to add separators in between Menu Items.

<MenuItem Header="_File">
<MenuItem Header="_Open" IsCheckable="true"/>

378 @ C# Corner
<Separator/>
<MenuItem Header="_Close" IsCheckable="true"/>
<Separator/>
<MenuItem Header="_Save" IsCheckable="true"/>
</MenuItem>

Listing 4

The window with added separators looks like figure 4.

Listing 4

We can also add sub menus and sub menu items using the MenuItem tag within parent a MenuItem tag.
The following code adds a separator and sub menus and sub menu items to the menu.

<MenuItem Header="_File">
<MenuItem Header="_Open" IsCheckable="true"/>
<Separator/>
<MenuItem Header="_Close" IsCheckable="true"/>
<Separator/>
<MenuItem Header="_Save" IsCheckable="true"/>
<Separator/>
<MenuItem Header="Sub Items">
<MenuItem Header="Child1 SubItem" IsCheckable="true"/>
<MenuItem Header="Child2 SubItem" IsCheckable="true">
<MenuItem Header="GrandChild2 SubItem" IsCheckable="true"/>
</MenuItem>
</MenuItem>
</MenuItem>
Listing 5

Now, our new output looks like Figure 5.

379 @ C# Corner
Figure 5. A menu with menu items

Adding Tooltips to Menus

The MenuItem.ToolTip tag adds a tooltip to a menu item. The following code adds a tooltip to the Open
menu item.

<MenuItem Header="_Open" IsCheckable="true">


<MenuItem.ToolTip>
<ToolTip>
Open a file.
</ToolTip>
</MenuItem.ToolTip>
</MenuItem>

The output with the tooltip looks like Figure 6.

Figure 6. A menu with a tooltip

Adding a CheckBox to a Menu Item

380 @ C# Corner
By setting the IsCheckable property of a MenuItem to true makes a menu item a CheckBox in front of
the header text.

<MenuItem IsCheckable="true">

We have set IsCheckable to true for Open, Close and Save menu items in Listing 5

<MenuItem Header="_File" >


<MenuItem Header="_Open" IsCheckable="true">
<MenuItem.ToolTip>
<ToolTip>
Open a file.
</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<Separator/>
<MenuItem Header="_Close" IsCheckable="true"/>
<Separator/>
<MenuItem Header="_Save" IsCheckable="true"/>
<Separator/>
<MenuItem Header="Sub Items">
<MenuItem Header="Child1 SubItem" IsCheckable="False"/>
<MenuItem Header="Child2 SubItem" IsCheckable="False">
<MenuItem Header="GrandChild2 SubItem" IsCheckable="False"/>
</MenuItem>
</MenuItem>
</MenuItem>

Listing 6

As you can see in figure 6, now you can select the menu items if IsCheckable is true.

Figure 6. A menu with a checkbox

381 @ C# Corner
Adding a Keyboard Shortcut to a Menu Item

InputGestureText property is used to add keyboard shortcut to the menu item. The following code adds
CTRL+O to a menu item.
<MenuItem Header="_Save" IsCheckable="true" InputGestureText="Ctrl+S"/>

Above syntax adds the shortcut to save menu, in figure 7 you’d notice that there is Ctrl+S text shown
next to the menu item indicating keyboard shortcut key.

Figure 7. A menu with keyboard shortcut key

Adding an Event Trigger to a MenuItem

The Click event is used to add the menu item click event handler. The following code adds a click event
handler for a menu item.
<MenuItem Click="SaveMenuItem_Click"
Header="_Save"
IsCheckable="true"
InputGestureText="Ctrl+S"/>

Listing 7
The event handler is defined like the following in the code behind. We have added a message box when
the save menu item is clicked.
private void SaveMenuItem_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("File saved successfully!");
}

Listing 8

382 @ C# Corner
Figure 8

Creating a Menu Control at Run-time

The following code creates a menu and adds menu items dynamically.

Menu mainMenu = new Menu();


mainMenu.Background = Brushes.LightGreen;
mainMenu.Height = 300;
mainMenu.Width = 200;

MenuItem item1 = new MenuItem();


item1.Width = 50;
item1.Header = "First";
mainMenu.Items.Add(item1);

MenuItem item2 = new MenuItem();


item2.Width = 50;
item2.Header = "Two";
item1.Items.Add(item2);

MenuItem item3 = new MenuItem();


item3.Width = 50;
item3.Header = "Third";
item1.Items.Add(item3);

Listing 9

Let’s style background little bit

Let us begin with setting background toLinearGradientBrush.

<Menu.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FF3A60AD" Offset="0.528" />
<GradientStop Color="#FF6A85D8" Offset="0.01" />
<GradientStop Color="#FF3464C4" Offset="1" />

383 @ C# Corner
<GradientStop Color="#FF202E7E" Offset="1" />
</LinearGradientBrush>
</Menu.Background>

Listing 10

Figure 9

How to Add multiple menu items horizontally to a WPF Menu

Let's say you need to add menu items horizontally. All you need to do is, expand your Menu width so all
items will fit. then you can set layout of the Grid. Listing 11 add menus horizontally with icons for each
menu item.

<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu Name="MenuExample"
BorderThickness="2"
FontSize="16"
FontWeight="Bold"
Foreground="White"
Height="35"
Margin="10"
VerticalAlignment="Top"
Width="400">
<Menu.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FF3A60AD" Offset="0.528" />
<GradientStop Color="#FF6A85D8" Offset="0.01" />
<GradientStop Color="#FF3464C4" Offset="1" />
<GradientStop Color="#FF202E7E" Offset="1" />
</LinearGradientBrush>
</Menu.Background>
<Menu.BitmapEffect>
<DropShadowBitmapEffect />
</Menu.BitmapEffect>

384 @ C# Corner
<MenuItem Header="Tools" IsCheckable="true">
<MenuItem.Icon>
<Image Source="Tools.png" Width="20" Height="20" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Settings" IsCheckable="true" Foreground="Orange"
FontSize="16">
<MenuItem.Icon>
<Image Source="Settings.png" Width="20" Height="20" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Security" IsCheckable="true" Foreground="White"
FontSize="16">
<MenuItem.Icon>
<Image Source="Security.png" Width="20" Height="20" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Database" IsCheckable="true" Foreground="LightGreen"
FontSize="16">
<MenuItem.Icon>
<Image Source="Database.png" Width="15" Height="15" />
</MenuItem.Icon>
</MenuItem>
</Menu>
</Grid>.

Listing 11

The final output of listing 11 looks like figure 10.

Figure 10

Summary

In this chapter, we discussed how we can use a Menu and MenuItem controls to create menus in a WPF
application. We also saw how we can set menu properties, add menu items at design-time as well as at
run-time and add menu item event handlers. In the end we learned how to style background of menu
and add icons to menu items and how to place them horizontally.

385 @ C# Corner
PasswordBox
Introduction
WPF comes with a built-in PasswordBox control that allows you to handle and manage passwords in a
WPF application. You can think of a PasswordBox control as a TextBox control with a masking feature.
The PasswordBox control allows you to hide the characters and limit the number of characters to be
typed in the editable area.

This chapter demonstrates how to create and use a PasswordBox control in WPF.

Properties
In XAML the PasswordBox element represents a PasswordBox control. The code snippet in listing 1
creates a PasswordBox and sets a few of its properties such as Height, Width, Foreground, and
Background.

<PasswordBox x:Name="PasswordBoxExample"
Background="LightBlue"
Foreground="DarkBlue"
Height="42"
Margin="22,28,28,0"
VerticalAlignment="Top"
Width="200" />
Listing 1
The default PasswordBox looks like Figure 1.

Figure 1

The MaxLength property is used to get and set the maximum number of characters you can enter in a
PasswordBox.

The Password property is used to get and set the current password in a PasswordBox. It is used to hold
the user input. Same as Text property in TextBox.

386 @ C# Corner
The PasswordBox is not a PasswordBox without its masking feature. By default, the “dot” character is
used as a masking character as we saw in previous examples. But we can change that character with the
PasswordChar property. It is used to get and set the masking character for the PasswordBox.

The following code snippet in listing 2 sets the MaxLength, PasswordChar, and Password properties of a
PasswordBox control.

<PasswordBox x:Name="PasswordBoxExample"
Background="LightBlue"
Foreground="DarkBlue"
Height="42"
Margin="22,28,28,0"
MaxLength="25"
Password="YourPassword"
PasswordChar="*"
VerticalAlignment="Top"
Width="200" />
Listing 2

The output looks like Figure 2. The editing will stop as soon as you type 25 characters in the
PasswordBox. Since we have set MaxLength to 25.

Figure 2

The SecurePassword property gets the password currently held by the PasswordBox as a SecureString.
The SecureString specifies text that should be kept confidential. The text is encrypted to protect the
privacy and deleted from computer memory when no longer needed.

Events
Besides the above discussed properties, the PasswordBox has a very important event called
PasswordChanged. This even occurs when the value of the Password property is changed. The following
code snippet sets this property and shows a property event handler.

<PasswordBox x:Name="PasswordBoxExample"
Background="LightBlue"
Foreground="DarkBlue"
Height="42"
Margin="22,28,28,0"
MaxLength="25"
Password="YourPassword"

387 @ C# Corner
PasswordChanged="PasswordBoxExample_PasswordChanged"
PasswordChar="*"
VerticalAlignment="Top"
Width="200" />
Listing 3

Here is the PasswordChanged event handler. You may want to use this property when you need to
execute some code when a password is being changed.

private void PasswordBoxExample_PasswordChanged(object sender,


RoutedEventArgs e)
{
MessageBox.Show("Password changed");
}
Listing 4

Create a PasswordBox Dynamically


The following code snippet creates a PasswordBox and sets its properties at run-time.

private void CreatePasswordBoxDynamically()


{
PasswordBox pw = new PasswordBox();
pw.Height = 30;
pw.Width = 200;
pw.Background = new SolidColorBrush(Colors.LightBlue);
pw.Foreground = new SolidColorBrush(Colors.DarkBlue);
pw.MaxLength = 25;
pw.PasswordChar = '*';

RootLayout.Children.Add(pw);
}
Listing 5

Here is the code-behind sample written in Visual Basic .NET.

Sub CreatePasswordBoxDynamically()
Dim pw As New PasswordBox()
pw.Height = 30
pw.Width = 200
pw.Background = New SolidColorBrush(Colors.LightBlue)
pw.Foreground = New SolidColorBrush(Colors.DarkBlue)
pw.MaxLength = 25
pw.PasswordChar = "*"

RootLayout.Children.Add(pw)

End Sub
Listing 6

388 @ C# Corner
Popup
A popup window is a window that floats over a page or window allowing the user to take some quick
action. For example, Alert users about timeouts, or take user input to update the value etc. Fortunately,
WPF comes with a Popup control to provide this functionality.

This tutorial shows you how to create and use a Popup control available in Windows Presentation
Foundation (WPF) and XAML.

Introduction
The Popup element represents a WPF Popup control in XAML.
<Popup/>

The Width and Height properties specify the width and the height of a Popup. The Name property
specifies the name of the control, which is a unique identifier of a control. The Margin property specifies
the location of a Popup on the parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

The following code snippet in listing 1 sets the name, height, and width of a Popup control. The code
also sets horizontal alignment to left and vertical alignment to top.

<Popup Name="PopupExample"
Height="200"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="200"/>
Listing 1

To make a popup control visible, you need to set IsOpen property to true.
IsOpen="True"

Adding Popup Contents


A Popup control can have only one child. The following code snippet adds a TextBlock to the popup
control.

<Popup Name="PopupExample"
Height="200"
HorizontalAlignment="Left"
IsOpen="True"
Margin="10"
VerticalAlignment="Top"
Width="200">
<TextBlock Name="TextBlockPopUp"

389 @ C# Corner
Background="LightBlue"
Text="This is Popup"/>
</Popup>

Listing 2

If you wish to add more contents to the popup control, you can use panels such as stack panel or grid
and place more contents inside a panel. The following code snippet creates a stack panel to add a
TextBlock and a Button as a child for a Popup.

<Popup Name="PopupExample"
Height="200"
HorizontalAlignment="Left"
IsOpen="True"
Margin="10"
VerticalAlignment="Top"
Width="200">
<StackPanel>
<TextBlock Name="TextBlockPopUp"
Background="LightBlue"
Text="This is Popup"/>
<Button x:Name="ButtonSave"
Content="Save"/>
</StackPanel>
</Popup>

Listing 3

The popup created using the above code looks like Figure 1.

Figure 1: Popup window

390 @ C# Corner
Animated Popup
Once you have a popup content defined, you can do anything with this content depending on the
controls. For instance, if you are using an image as a content, you can do anything with popup that you
can possibly do with an image.

The following code shows how to animate a popup window.

<StackPanel x:Name="StackPanelExample">
<CheckBox Name="CheckBoxPopupExample"
Content="Popup Window"
Margin="10,10,0,0"/>
<Button x:Name="ButtonPopupExample"
HorizontalAlignment="Left"
Width="129"
Margin="10">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="theTransform"

Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0" To="360" Duration="0:0:5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
Start Animation
</Button>
<Popup IsOpen="{Binding ElementName=CheckBoxPopupExample,Path=IsChecked}"
PlacementTarget="{Binding ElementName=CheckBoxPopupExample}"
AllowsTransparency="True"
PopupAnimation="Slide"
HorizontalOffset="150"
VerticalOffset="100">

<Canvas
Background="Green"
Height="100"
Margin="150"
Width="110">
<Canvas.RenderTransform>
<RotateTransform x:Name="theTransform" />
</Canvas.RenderTransform>
<TextBlock
Text=" Rotating Popup"
TextWrapping="Wrap"
Foreground="LightGray"/>
</Canvas>
</Popup>
</StackPanel>

391 @ C# Corner
Listing 4

Figure 2 is a result of listing 4. If you select checkbox it will show the green popup and when you click on
a start animation button it will start rotating.

Figure 2

Placement of a Popup
The Placement property of Popup describes the position of a Popup on the screen. If you do not set any
positioning or placement of a popup, the popup will appear in the top left corner of the window.

The PlacementMode enumeration represents the Placement property. The following code snippet sets
Placement property to AbsolutePoint.
Placement="AbsolutePoint"

If you add the above property in the code, it will look like figure 3.

392 @ C# Corner
Figure 3

The following illustrations and definitions from MSDN show how the PlacementMode enumeration
values help you place the Popup window and adjust its position when screen boundaries obscure its
content.

PlacementMode = Absolute

A position of the Popup that is relative to the upper-left corner of the screen and offset by the
HorizontalOffset and VerticalOffset properties.

If a screen edge hides all or part of the Popup, the control re-aligns with the obscuring edge.

393 @ C# Corner
PlacementMode = AbsolutePoint

A position of the Popup control that is relative to the upper-left corner of the screen and offset by the
HorizontalOffset and VerticalOffset properties.

If a screen edge hides all or part of the Popup, the control opens in the opposite direction by starting at
the point that is defined by the offset properties.

394 @ C# Corner
PlacementMode = Bottom

A position of the Popup where the control aligns its upper edge with the lower edge of the
PlacementTarget and aligns its left edge with the left edge of the PlacementTarget.

If the lower edge of the screen hides all or part of the Popup, the control re-aligns with the upper edge
of the PlacementTarget. If the upper edge of the screen hides all or part of this new position, the control
re-aligns with the lower edge of the screen. After these adjustments, if the control is still partially hidden
by the upper edge of the screen, the control realigns with the upper edge of the screen.

395 @ C# Corner
If a vertical screen edge hides all or part of the Popup, the control realigns with the obscuring screen
edge.

PlacementMode = Center

A position of the Popup control where the control centers itself over the PlacementTarget.

396 @ C# Corner
If a screen edge hides all or part of the Popup, the control realigns with the obscuring screen edge.

PlacementMode = Left

A Popup control that aligns its right edge with the left edge of the PlacementTarget and its upper edge
with the upper edge of the PlacementTarget.

If a horizontal screen edge hides all or part of the Popup, the control realigns with the obscuring screen
edge.

397 @ C# Corner
If a vertical screen edge hides all or part of the Popup, the control realigns on the opposite side of the
PlacementTarget.

PlacementMode = Mouse

A position of the Popup control where it aligns its upper edge with the lower edge of the bounding box
of the mouse, and it aligns its left edge with the left edge of the mouse bounding box.

If a horizontal screen edge hides all or part of the Popup, the control displays on the opposite side of the
mouse bounding box.

398 @ C# Corner
If a vertical screen edge hides all or part of the Popup, the control realigns with the obscuring screen
edge.

PlacementMode = MousePoint

A position of the Popup control that aligns its upper edge with the lower edge of the mouse bounding
box and its left edge with the left edge of the mouse bounding box.

399 @ C# Corner
If a screen edge hides all or part of the Popup, the control realigns on the opposite side of the mouse
bounding box.

400 @ C# Corner
PlacementMode = Relative

A position of the Popup control that is relative to the upper-left corner of the PlacementTarget and at an
offset that is defined by the HorizontalOffset and VerticalOffset property values.

If a screen edge hides all or part of the Popup, the control realigns with the obscuring screen edge.

Placement Mode = RelativePoint

A position of the Popup control that is relative to the upper-left corner of the PlacementTarget and at
an offset that is defined by the HorizontalOffset and VerticalOffset property values.

401 @ C# Corner
If a screen edge hides all or part of the Popup, the control opens in the opposite direction by starting at
the point that is defined by the offset properties.

402 @ C# Corner
PlacementMode = Right

A position of the Popup control that aligns its left edge with the right edge of the PlacementTarget and
aligns its upper edge with the upper edge of the PlacementTarget.

If a vertical screen edge hides all or part of the Popup, the control displays on the opposite side of the
PlacementTarget.

If the upper or lower screen edge hides all or part of the Popup, the control realigns with the obscuring
screen edge.

Placement Mode = Top

A position of the Popup control that aligns its lower edge with the upper edge of the PlacementTarget
and aligns its left edge with the left edge of the PlacementTarget.

403 @ C# Corner
If the upper edge of the screen hides all or part of the Popup, the control displays below the
PlacementTarget. If the lower edge of the screen hides the Popup in the new position, the control
realigns with the lower edge of the screen. If the control is still obscured by the upper screen edge in the
third position, the control realigns with the upper screen edge.

If a vertical screen edge hides all or part of the Popup, the control realigns with the obscuring screen
edge.

404 @ C# Corner
Summary

In this chapter, I discussed how to create and use a Popup control available in WPF. The chapter also
shows how to animate a popup.

405 @ C# Corner
ProgressBar
This chapter shows you how to create and use a ProgressBar control available in Windows Presentation
Foundation (WPF) and XAML.

Introduction
In XAML, The ProgressBar tag is used to represent a WPF ProgressBar control.
<ProgressBar/>

The Width and Height properties specify the width and the height of a ProgressBar. The Name property
specifies the name of the control, which is a unique identifier of a control. The Margin property specifies
the position of a ProgressBar on a parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

The following code snippet sets the name, height, and width of a ListView control. The code also sets
horizontal alignment to left and vertical alignment to top.
<ProgressBar Name="ProgressBarExample"
Height="30"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="300"/>
Listing 1

The progress bar looks like Figure 1.

Figure 1.

Setting up ProgressBar Value


The Value property of ProgressBar sets up the current value of a ProgressBar. In the syntax we are
setting the Value property to 50 and now ProgressBar looks like Figure 2.

Value="50"

406 @ C# Corner
Figure 2

Let’s play around this a bit, say you want to show the progress with text. Code snippet in listing 2 adds a
TextBlock and bound its Text property with ProgressBar’s Value.

Note: It’s always better to create a common style for controls which are co depended on each other with
respect to UI. So if one property is changed will be applied to both of them together.

<ProgressBar Name="ProgressBarExample"
Height="30"
HorizontalAlignment="Center"
Margin="10"
Value="50"
VerticalAlignment="Center"
Width="300"/>
<TextBlock Name="TextBlockProgressBarExample"
Text="{Binding ElementName=ProgressBarExample, Path=Value,
StringFormat={}{0}%}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />

Listing 2
Output of Listing 2 looks like Figure 3.

Figure 3

407 @ C# Corner
Dynamically Setting a ProgressBar Value
We can use a timer or animation to set a ProgressBar’s value dynamically. The following code creates a
DoubleAnimation object and sets ProgressBar.Value by using the ProgressBar.BeginAnimation method.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
Duration duration = new Duration(TimeSpan.FromSeconds(20));
DoubleAnimation doubleanimation = new DoubleAnimation(200.0, duration);
ProgressBarExample.BeginAnimation(ProgressBar.ValueProperty,
doubleanimation);
}

Listing 3

If you run the application, the ProgressBar run looks like Figure 4,5. Basically it will react to a changing
value.

Figure 4

Figure 5

408 @ C# Corner
Flow Direction
The FlowDirection property sets the flow of ProgressBar. You can set this value either LeftToRight or
RightToLeft. The default value is LeftToRight. By default, it is always set to LeftToRight. Let’s change this
and observe the changes.

FlowDirection="RightToLeft"

Output would look like Figure 6 if you set FlowDirection="RightToLeft"

Figure 6

Adding a ProgressBar to a StatusBar


You probably saw several applications like Internet Explorer where you can see the progress of a page
loading in the status bar at the bottom of the page. Figure 7 demonstrates how it would look like.

Figure 7

The code snippet in listing 4 adds a StatusBar to WPF using XAML. And adds ProgressBar, TextBlock as
items of a StatusBar.

409 @ C# Corner
<StatusBar Name="StatusBarExample"
Background="LightBlue"
VerticalAlignment="Bottom">
<StatusBarItem>
<TextBlock>Status:</TextBlock>
</StatusBarItem>
<StatusBarItem>
<ProgressBar Name="ProgressBarExample"
Height="30"
HorizontalAlignment="Center"
Margin="10"
Value="40"
VerticalAlignment="Center"
Width="300"/>
</StatusBarItem>
<TextBlock Name="TextBlockProgressBarExample"
Text="{Binding ElementName=ProgressBarExample, Path=Value,
StringFormat={}{0}%}" />
</StatusBar>

Listing 4

We can even dynamically add items to a StatusBar. In listing 5 we are doing the same.

private void CreateDynamicProgressBarControl()


{
ProgressBar PBar2 = new ProgressBar();
PBar2.IsIndeterminate = false;
PBar2.Orientation = Orientation.Horizontal;
PBar2.Width = 200;
PBar2.Height = 20;
Duration duration = new Duration(TimeSpan.FromSeconds(20));
DoubleAnimation doubleanimation = new DoubleAnimation(200.0, duration);
PBar2.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);
SBar.Items.Add(PBar2);
}

Listing 5

Summary
In this chapter I discussed how to create and use a ProgressBar control available in WPF.

410 @ C# Corner
RadioButton
This chapter explains how to create and use a RadioButton control in Windows Presentation Foundation
(WPF).

Introduction
A RadioButton is usually used in a group with multiple options where one must be selected. It acts as a
toggle button meaning it can hold 2 states either true or false. It can also be extended to support 3
states with nullable boolean but for now let’s keep simple with default 2 states.
The RadioButton tag represents a RadioButton control in XAML.

<RadioButton></RadioButton>

The Width and Height properties specify the width and the height of a RadioButton. The Name property
specifies the name of the control, which is a unique identifier of a control. The Margin property specifies
the location of a RadioButton on the parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

The Background and Foreground properties specify the background and foreground colors of a
RadioButton.

The following code snippet in listing 1 sets the name, height, and width of a RadioButton control. The
code also sets horizontal alignment to left and vertical alignment to top.

<RadioButton x:Name="RadioButtonCSharpCorner"
Background="LightSalmon"
Content="C# Corner"
Foreground="DarkBlue"
Height="15"
HorizontalAlignment="Left"
Margin="10"
Width="150"
VerticalAlignment="Top" />

Listing 1

The RadioButton looks like following:

411 @ C# Corner
Figure 1: RadioButton when value is false

Figure 2: RadioButton when value is true

RadioButton Grouping
The GroupName property of a RadioButton assigns a RadioButton to a group. The magic of this feature
is the single selection meaning only one RadioButton can be selected at once and by selecting a one
RadioButton deselect the previously selected RadioButton. Let’s understand this behavior with an
example.

The following code assigns four RadioButton controls to a group called AppleProducts.

<RadioButton
Content="iPhone"
Margin="10"
GroupName="AppleProducts"/>
<RadioButton
Content="ipad"
Margin="10,30,10,10"
GroupName="AppleProducts"/>
<RadioButton
Content="Apple watch"

412 @ C# Corner
Margin="10,50,10,10"
GroupName="AppleProducts"/>
<RadioButton
Content="Apple TV"
Margin="10,70,10,10"
GroupName="AppleProducts"/>

Listing 2

The output looks like Figure 3. If you select iPad, the iPhone’s selection will be removed, and iPad will be
selected.

Figure 3

Adding a Checked Event Handler


RadioButton control has Checked event, event is raised when you check a radio button. The following
code snippet adds the event handler.

<RadioButton
Content="iPhone"
Checked="RadioButtoniPhone_Checked"
Margin="10"
GroupName="AppleProducts"/>

Listing 3

The following checked event handler sets the foreground and background color of the iPhone
RadioButton to green and rest to red.

private void RadioButtoniPhone_Checked(object sender, RoutedEventArgs e)


{
RadioButtoniPhone.Foreground = Brushes.Green;
RadioButtoniPhone.Background = Brushes.Green;
RadioButtoniPad.Foreground = Brushes.Red;
RadioButtoniPad.Background = Brushes.Red;
RadioButtonAppleWatch.Foreground = Brushes.Red;
RadioButtonAppleWatch.Background = Brushes.Red;
RadioButtonAppleTV.Foreground = Brushes.Red;

413 @ C# Corner
RadioButtonAppleTV.Background = Brushes.Red;
}

Listing 4

New RadioButton group looks like Figure 4.

Figure 3

Finding a Selected Item in the Group


The IsChecked property of RadioButton is used to ensure if a RadioButton is checked or not. The
following code snippet in listing 5 is demonstrating use of this property. On the iPhone RadioButton’s
click event handler we are checking if other RadioButton’s are unchecked and showing the summary in
MessageBox.

private void RadioButtoniPhone_Checked(object sender, RoutedEventArgs e)


{
string message = string.Empty;
if (RadioButtoniPhone.IsChecked == true)
{
message = RadioButtoniPhone.Content.ToString() + " is
selected,";
}
if (RadioButtoniPad.IsChecked == false)
{
message += Environment.NewLine +
RadioButtoniPad.Content.ToString() + " is unselected,";
}
if (RadioButtonAppleWatch.IsChecked == false)
{
message += Environment.NewLine +
RadioButtonAppleWatch.Content.ToString() + " is unselected,";
}
if(RadioButtonAppleTV.IsChecked == false)
{

414 @ C# Corner
message += Environment.NewLine +
RadioButtonAppleTV.Content.ToString() + " is unselected.";
}
MessageBox.Show(message.ToString());
}

Listing 5

If the user selects the iPhone, output would look like figure 5.

Figure 5

415 @ C# Corner
RichTextBox
This chapter shows you how to create and use a RichTextBox control available in Windows Presentation
Foundation (WPF) and XAML.

Introduction
The RichTextBox control allows you to view and edit text, paragraphs, images, tables, and other rich text
format contents.

In XAML, The RichTextBox tag is used to represent a RichTextBox control.

<RichTextBox/>

The Width and Height properties represent the width and the height of a RichTextBox. The Name
property represents the name of the control, which is a unique identifier of a control. The Margin
property tells the location of a RichTextBox on the parent control. The HorizontalAlignment and
VerticalAlignment properties are used to set horizontal and vertical alignments.

The following code snippet sets the name, height, and width of a RichTextBox control. The code also
sets horizontal alignment to left and vertical alignment to top.

<RichTextBox x:Name="RichTextBoxExample"
Height="300"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="500" />

Listing 1

Let’s run the listing 1 to see the output.

416 @ C# Corner
Figure 1: Empty RichTextBox

Displaying and Edit Text


A RichTextBox control hosts a collection of RichTextBoxItem. The following code snippet adds items to a
RichTextBox control.

<RichTextBox x:Name="RichTextBoxExample"
Height="300"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="500">
<FlowDocument>
<Paragraph>
This is a flow document. This can be edited!
<Bold>Start writing</Bold>
</Paragraph>

<Paragraph Foreground="Blue">
Your paragraph starts from here.
</Paragraph>
</FlowDocument>
</RichTextBox>

Listing 2

The code in listing 2 generates Figure 2 where you can start editing text right away.

417 @ C# Corner
Figure 2: RichTextBox with editable text

Creating and Using RichTectBox Dynamically


In the previous section, we saw how to create and use RichTextBox in XAML. WPF provides a
RichTextBox class that represents a RichTextBox control. In this section, we will see how to use this class
to create and use a RichTextBox control dynamically.

The code listed in Listing 3 creates a FlowDocument, adds a paragraph to the flow document and sets
the Document property of the RichTextBox as FlowDocument.

private void CreateAndLoadRichTextBox()


{
// Create a FlowDocument
FlowDocument mcFlowDoc = new FlowDocument();

// Create a paragraph with text


Paragraph para = new Paragraph();
para.Inlines.Add(new Run("This is a flow document. This can be
edited!"));
para.Inlines.Add(new Bold(new Run("Start writing.)));

// Add the paragraph to blocks of paragraph


mcFlowDoc.Blocks.Add(para);

// Create RichTextBox, set its hegith and width


RichTextBox mcRTB = new RichTextBox();
mcRTB.Width = 560;
mcRTB.Height = 280;

418 @ C# Corner
// Set contents
mcRTB.Document = mcFlowDoc;

// Add RichTextbox to the container


ContainerPanel.Children.Add(mcRTB);
}

Listing 3

Enable Spelling Check


RichTextBox control comes with spelling check functionality out-of-box. By setting SpellCheck.IsEnabled
property to true enables spell checking in a RichTextBox.

SpellCheck.IsEnabled="True"

Now if you type some text, the misspelled word would be underlined with red color. And if you right
click on the same it will give you possible suggestions. See in Figure 3.

Figure 3. RichTextBox with Spell Check Enabled

Loading a Document in RichTextBox


We can use RichTextBox.Items.Remove or RichTextBox.Items.RemoveAt method to delete an item from
the collection of items in the RichTextBox. The RemoveAt method takes the index of the item in the
collection.

419 @ C# Corner
Now, we modify our application and add a new button called Delete Item. The XAML code for this
Button looks like below.

private void OpenMenuItem_Click(object sender, RoutedEventArgs e)


{
OpenFileDialog dlg = new OpenFileDialog();
dlg.InitialDirectory = "c:\\";
dlg.Filter = "Text files (*.txt)|*.txt|All Files (*.*)|*.*";
dlg.RestoreDirectory = true;
LoadTextDocument(dlg.FileName);
}

private void LoadTextDocument(string fileName)


{
TextRange range;
System.IO.FileStream fStream;
if (System.IO.File.Exists(fileName))
{
range = new
TextRange(RichTextBoxExample.Document.ContentStart,
RichTextBoxExample.Document.ContentEnd);
fStream = new System.IO.FileStream(fileName,
System.IO.FileMode.OpenOrCreate);
range.Load(fStream, System.Windows.DataFormats.Text);
fStream.Close();
}
}
Listing 4

Converting RichTextBox Contents to a String


There is no direct method or property in RichTextBox that can extract the document or contents of a
RichTextBox to a string. To convert the contents to a string, we first need to read the contents of a
RichTextBox in a TextRange object and use TextRange.Text property to convert it to a string.

The following code snippet in listing 5 reads a RichTextBox contents from start to end and converts to a
string.

string ConvertRichTextBoxContentsToString(RichTextBox rtb)


{
TextRange textRange = new TextRange(rtb.Document.ContentStart,
rtb.Document.ContentEnd);
return textRange.Text;
}

Listing 5

Summary
In this chapter, we discussed how to create and use a RichTextBox control available in WPF. We saw
how we can load text programmatically or load a text file.

420 @ C# Corner
ScrollViewer
Implementing Scrolling using WPF ScrollViewer in C# and XAML
Content and data focused Windows applications often require vertical and/or horizontal scrolling
functionality to conveniently display large content on the screen. The WPF ScrollViewer control can be
used to implement vertical and horizontal scrolling on Windows controls.

The ScrollViewer class in C# and .NET represents a WPF ScrollViewer control at run-time. At design-time,
the <ScrollViewer> element in XAML represents a ScrollViewer control. The code examples in this
tutorial explains the use of the Scroll Viewer control and how to implement scrolling functionality in
WPF Windows apps using C# and XAML.

To implement scrolling functionality on a content control, the content control is placed as the default
content of a ScrollViewer control using its Content property. A ScrollViewer can only have one child,
typically a Panel element that can host a Children collection of elements.

The simplest way to enable scrolling on a content control is by placing the content control inside a
ScrollViewer control. The following code snippet places a StackPanel control within a ScorllViewer
control.
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<StackPanel HorizontalAlignment="Left"
VerticalAlignment="Top">
<TextBlock Text="Resize window to auto enable or disable scrolling."/>
<Separator/>
<Rectangle Fill="DodgerBlue"
Height="400"
Width="380"/>
</StackPanel>
</ScrollViewer>

Listing 1

The code places a TextBlock and a Rectangle control on a StackPanel. The StackPanel is placed within a
ScrollViewer. The scrolling is enabled by default and both horizontal and vertical scrollbars are visible
when the content (Rectangle) is bigger than the parent control i.e. StackPanel.

You can resize the Window and you will see the ScrollViewer appears and disappears when the
Windows is smaller and larger than the content, respectively.

421 @ C# Corner
Figure 1: When content is smaller than the parent.

Figure 2: When content is larger than the parent.

The ScrollViewer control responds to both mouse and keyboard commands. You can use the
ScrollChanged event to detect a change in a ScrollViewer state.

The VerticalScrollBarVisibility and HorizontalScrollBarVisibility properties enable or disable vertical and


horizontal scrolling capabilities on a ScrollViewer. It has four values - Auto, Disabled, Hidden, and Visible
that are self-explanatory. In most cases, you may want to keep the default Auto property that shows, or
hides scroll bars as needed.

422 @ C# Corner
The following code snippet sets both vertical and horizontal scrollbars to Auto.

If you set scrollbar to visible, it will occupy the space even when it’s not being used.

<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible">

Figure 3: Vertical scrollbar is occupying space

You can disable and hide scrollbars by setting these values to Disabled and Hidden respectively. The
Visible value makes sure the scrollbars are visible all the time regardless of the content needed scrolling
or not.

Let’s add a ScrollViewer control as the root content of a Window. Then place a RichTextBox with 2
paragraphs as child controls as a part of the content.

<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<RichTextBox Margin="10,10" Name="RichTextBox1" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="500" Height="300">
<FlowDocument>
<Paragraph>
<Bold>C# Corner: OUR MISSION</Bold>

423 @ C# Corner
Free Education is Our Basic Need! Our mission is to empower
millions of developers worldwide by providing the latest unbiased news, advice, and tools
for learning, sharing, and career growth. We’re passionate about nurturing the next young
generation and help them not only to become great programmers, but also exceptional human
beings.
</Paragraph>
<Paragraph>
<Bold>C# Corner: ABOUT US</Bold>
C# Corner, headquartered in Philadelphia, PA, is an online global
community of 3 million software developers. C# Corner serves 5+ million visitors with 9
million page views each month. We publish the latest news and articles on cutting-edge
software development topics. Developers share their knowledge and connect via content,
forums, and chapters. Thousands of members benefit from our monthly events, webinars, and
conferences. We also provide tools for career growth such as career advice, resume
writing, training, certifications, books and whitepapers, and videos. We also connect
developers with their potential employers via our Job board.
</Paragraph>
</FlowDocument>
</RichTextBox>
</ScrollViewer>

Listing 2

The above code generates the following app that allows users to scroll its content.

Figure 4

How to enable scrollbar in a WPF TextBox

424 @ C# Corner
The simplest way to add scrolling functionality to a TextBox control is by enabling its horizontal and
vertical scrolling. The HorizontalScrollBarVisibility and VerticalScrollBarVisibility properties are used to
set horizontal and vertical scroll bars of a TextBox.

The following code snippet enables vertical scrollbar in a TextBox control.

<TextBox x:Name="TextBoxWithScrollbar"
Height="80"
TextWrapping="Wrap"
Text="Free Education is Our Basic Need! Our mission is to empower
millions of developers worldwide by providing the latest unbiased news, advice, and tools
for learning, sharing, and career growth. We're passionate about nurturing the next young
generation and help them not only to become great programmers, but also exceptional human
beings."
VerticalScrollBarVisibility="Visible"
Width="300"/>

Listing 3

Figure 5 is a result of listing 3.

Figure 5

Note: There are some controls which have properties dedicated for scrollbars such as TextBox, TextBlock
etc. For the rest of the controls you can wrap the control around ScrollViewer as we saw in earlier
examples.

425 @ C# Corner
Slider Control
This chapter shows you how to use the Slider control available in WPF.

Slider Control
The Slider element in XAML represents a WPF Slider control.

<Slider></Slider>

Slider Control Properties


The Width and Height property specify the width and the height of the control. The Name property
specifies the name of the control, which is a unique identifier of the control. The Background property is
used to set the background color of the control. The Minimum and Maximum properties specify the
minimum and maximum values of the slider range.

The code snippet in Listing 1 creates a Slider control and sets its name, height, width, background,
maximum, and minimum properties.
<Grid Background="Black"
Margin="10">
<Slider Name="SliderExample"
Height="20"
Maximum="100"
Minimum="0"
Width="300" />
</Grid>

Listing 1

The code snippet in Listing 1 generates output that looks like Figure 1.

Figure 1

The IsFocused property indicates whether the slider will have focus or not and the IsDirectionReversed
property represents the direction of increasing value. By default, the slider control sits on the UI in
horizontal direction.
By setting this property to True it changes the direction.

426 @ C# Corner
Figure 2

By using the Orientation property, a slider control can be placed vertically.

The code snippet in Listing 2 sets the orientation of a slider control vertical.

<Slider Name="SliderExample"
Height="100"
HorizontalAlignment="Center"
Orientation="Vertical"
Maximum="100"
Minimum="0"/>

Listing 2

The code snippet in Listing 2 generates output that looks like Figure 3.

427 @ C# Corner
Figure 3

The Application
Now we are going to create a real-world application that will use Slider controls values to generate a
color from the combination of three values Red, Green, and Blue respectively. From these three values,
we will create a color and fill an ellipse with that color.

First, we need to create a UI page with one circle and three slider controls that looks like Figure 4.

Figure 4

The code that generates Figure 3 is listed in Listing 3.

<Canvas Name="LayoutRoot"
Background="Black"
Margin="10">
<!-- Create an Ellipse -->
<Ellipse Name="EllipseNewColor"
Fill="Gray"
Height="200"
Stroke="Black"
StrokeThickness="2"
Width="200"
Canvas.Left="80"

428 @ C# Corner
Canvas.Top="20">
</Ellipse>
<!-- Create Slider controls -->
<TextBlock x:Name="TextBlockRed"
Foreground="White"
Text="Red"
Canvas.Left="35"
Canvas.Top="225"/>
<Slider Name="RedSlider"
Height="20"
Maximum="255"
Minimum="0"
ValueChanged="RedSlider_ValueChanged"
Width="300"
Canvas.Left="30"
Canvas.Top="240" />

<TextBlock x:Name="TextBlockGreen"
Foreground="White"
Text="Green"
Canvas.Left="35"
Canvas.Top="255"/>
<Slider Name="GreenSlider"
Height="20"
Maximum="255"
Minimum="0"
ValueChanged="GreenSlider_ValueChanged"
Width="300"
Canvas.Left="30"
Canvas.Top="270" />

<TextBlock x:Name="TextBlockBlue"
Foreground="White"
Text="Blue"
Canvas.Left="35"
Canvas.Top="285"/>
<Slider Name="BlueSlider"
Height="20"
Maximum="255"
Minimum="0"
ValueChanged="BlueSlider_ValueChanged"
Width="300"
Canvas.Left="30"
Canvas.Top="300"/>
</Canvas>

Listing 3

Let’s write a logic for ValueChanged events. In the listing 4, we simply form a new color from the values
of the slider controls and create a brush which will be applied to fill the circle.

private void RedSlider_ValueChanged(object sender,


RoutedPropertyChangedEventArgs<double> e)

429 @ C# Corner
{
UpdateCircleWithColors();
}

private void GreenSlider_ValueChanged(object sender,


RoutedPropertyChangedEventArgs<double> e)
{
UpdateCircleWithColors();
}

private void BlueSlider_ValueChanged(object sender,


RoutedPropertyChangedEventArgs<double> e)
{
UpdateCircleWithColors();
}

private void UpdateCircleWithColors()


{
Color clr = Color.FromArgb(255, Convert.ToByte(RedSlider.Value),
Convert.ToByte(GreenSlider.Value), Convert.ToByte(BlueSlider.Value));
EllipseNewColor.Fill = new SolidColorBrush(clr);
}
Listing 4

Now if you run the application and change slider values, you will see the fill color of the circle changes
accordingly. See Figure 4.

Figure 4

430 @ C# Corner
Summary
In this chapter, we discussed how to create and use a Slider control available in WPF. We also saw how
to create a real-world application using slider controls.

431 @ C# Corner
Tab Control
In this chapter, we discuss how to create and use the TabControl in WPF.

Tab Control
The XAML TabControl element represents a tab control

A Tab Control has tab items and each tab item represents a container that is used to host other controls.
A typical example of a Tab control is the Visual Studio designer as shown in Figure 1. If you click on
the MainWindow.xaml tab item, you will see XAML code but if you click on MainWindow.xaml.cs, you
will see C# code behind and so on.

Figure 1

Create a Tab Control

The TabControl element in XAML represents a Tab Control.


<TabControl/>

The code snippet in Listing 1 creates a Tab Control and sets it height, width, margin and alignment. The
code also adds a TabItems.
<TabControl Name="TabControlExample"
Height="250"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="445">
<TabItem Name="TabItemFirst"
Header="Tab Item 1">
</TabItem>
<TabItem Name="TabItemSecond"
Header="Tab Item 2">

432 @ C# Corner
</TabItem>
</TabControl>

Listing 1

Listing 1 creates output shown in figure 2.

Figure 2

Adding Tab Items

A Tab Control is nothing without a Tab Item. The <TabItem \> element in XAML represents a Tab Item.
The Header property of a TabItem represents the header text of the header. The following code creates
a TabItem with the header text “Circle”.

<TabItem Header="Circle">
</TabItem>

Listing 2

A tab item can host other XAML controls like a panel or grid control. For example, the following code
adds a StackPanel to the tab item and on that StackPanel, it creates a circle with height and width 100.
<TabItem Header="Circle">
<StackPanel>
<Ellipse
Fill="gold"
Height="100"
Margin="0 50 0 0"
Stroke="black"
StrokeThickness="5"
Width="100" />

433 @ C# Corner
</StackPanel>
</TabItem>

Listing 3

Using the same preceding approach, I add 2 more tab items to the tab control. Let’s call them Rectangle
and Polygon.

<TabControl Name="TabControlExample"
Height="250"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="445">
<TabItem Header="Circle">
<StackPanel>
<Ellipse
Fill="gold"
Height="100"
Margin="0 50 0 0"
Stroke="black"
StrokeThickness="5"
Width="100" />
</StackPanel>
</TabItem>
<TabItem Header="Rectangle">
<StackPanel>
<Rectangle
Fill="Yellow"
Height="100"
Margin="0 50 0 0"
Stroke="Blue"
StrokeThickness="5"
Width="100" >
</Rectangle>
</StackPanel>
</TabItem >
<TabItem Header="Polygon">
<StackPanel>
<Polygon
Fill="Yellow"
Margin="120 50 0 0"
Points="100,50 50,100 150,100 100,50 100,30"
Stroke="green"
StrokeThickness="5"/>
</StackPanel>
</TabItem>
</TabControl>

Listing 4

If I run the application, the Circle tab shows a circle that looks as in Figure 3.

434 @ C# Corner
Figure 3

If I click on Rectangle and Polygon, the output looks as in Figure 4 and Figure 5 respectively.

Figure 4

435 @ C# Corner
Figure 5

Formatting Tab Items

Let's get a little creative. How about making our tab headers and tab control areas look pretty.

In a Tab Control, both a Tab Header and Tab Item are loosely coupled, and we can treat them as any 2
separate WPF controls. That’s been said, we can place any child controls on them, format them and do
whatever we want. So, if we want to place a DataGrid control in a TabItem header, we can do that.

Now let's format our Tab Item Header and Tab Item container area. We will format our Tab Item that
looks as in Figure 6, where we will use multiple colors for the background and change the text of the Tab
Item Header and let’s also change the background of the Tab Item container area to a gradient
background.

436 @ C# Corner
Figure 6

To do this, let’s add StackPanel on TabItem.Header and set its background to a LinearGradientBrush.
Then, let’s add Ellipse and a TextBlock on the TabItem Header.

Then as the content of the TabItem, we added a StackPanel and changed its background to
a LinearGradientBrush. See Listing 3.

<TabControl Name="TabControlExample"
Height="250"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="445">
<TabItem >
<!-- Create Tab Header -->
<TabItem.Header>
<!-- Place a StackPanel on TabHeader so we can place multiple
controls on it -->
<StackPanel Orientation="Horizontal">
<StackPanel.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0" >
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Black"/>
<GradientStop Offset="0.25" Color="DarkGray"/>
<GradientStop Offset="0.5" Color="Gray"/>
<GradientStop Offset="0.75" Color="LightGray"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</StackPanel.Background>
<Ellipse
Fill="Yellow"
Height="20"
Stroke="Black"
StrokeThickness="2"

437 @ C# Corner
Width="20"/>
<TextBlock
FontFamily="Georgia"
FontSize="18"
FontWeight="Bold"
Margin="2"
Text="Circle"
VerticalAlignment="Center"/>
</StackPanel>
</TabItem.Header>

<!-- Place a StackPanel on TabItem to place children controls -->


<StackPanel Margin="5 0 0 0">
<StackPanel.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="DarkBlue"/>
<GradientStop Offset="0.25" Color="Blue"/>
<GradientStop Offset="0.5" Color="LightBlue"/>
<GradientStop Offset="0.75" Color="LightSeaGreen"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</StackPanel.Background>
<Ellipse
Fill="gold"
Height="100"
Margin="0 50 0 0"
Stroke="black"
StrokeThickness="5"
Width="100" />
</StackPanel>
</TabItem >
</TabControl>

Listing 5

Position Tab Items

The TabStripPlacement property of a TabControl is used to position Tab Items. The value
of TabStripPlacement can be Left, Top, Bottom and Right.
TabStripPlacement="Bottom"

If we set the value to Bottom, it will look like figure 7.

438 @ C# Corner
Figure 7

How to add a Context Menu to a Tab Control

TabItem.ContextMenu is used to add a ContextMenu to a TabItem. The following code snippet creates
a TabControl where the first TabItem has a ContextMenu with three Menu items.

<TabControl>
<TabItem Name="TabItemColors" Header="Color Tab">
<TabItem.ContextMenu>
<ContextMenu MenuItem.Click="ContextMenuClickEventHandler">
<MenuItem Header="Red" Name="RedMenuItem"/>
<MenuItem Header="Blue" Name="BlueMenuItem"/>
<MenuItem Header="Orange" Name="OrangeMenuItem"/>
</ContextMenu>
</TabItem.ContextMenu>
<TabItem.Content>
Tab Item data here
</TabItem.Content>
</TabItem>
<TabItem Name="TabItemShape" Header="Shape Tab"></TabItem>
</TabControl>

Listing 6

Listing 7 adds the logic for MenuItem’s click event handler.

void ContextMenuClickEventHandler(object sender, RoutedEventArgs e)


{
if (e.Source == RedMenuItem)
{
TabItemColors.Header = "Red Item";
TabItemColors.Foreground = Brushes.Red;

439 @ C# Corner
}
else if (e.Source == BlueMenuItem)
{
TabItemColors.Header = "Blue Item";
TabItemColors.Foreground = Brushes.Blue;
}
else if (e.Source == OrangeMenuItem)
{
TabItemColors.Header = "Orange Item";
TabItemColors.Foreground = Brushes.Orange;
}
}

Listing 7

If you run your application, and right click on color’s tab. You’d be able to see output as figure 8.

Figure 8

Summary

In this Chapter, we saw how to create and use a TabControl in a WPF application. We also saw how to
make a tab item header and its contents more interactive by simply adding a few lines of code to
our XAML file.

440 @ C# Corner
TextBlock
Textblock is a read-only control which is used to display the text, meaning the user is not allowed to
enter any input. The text can be assigned from other means such as code-behind, ViewModel or other
controls. Textblocks supports multi line paragraphs. Hence the name Text-Block. Block of text.

Creating a TextBlock
The TextBlock element represents a WPF TextBlock control in XAML.

<TextBlock/>

The Width and Height attributes of the TextBlock element represent the width and the height in UI. The
Text property of the TextBlock specifies the content of a TextBlock. The Name attribute specifies the
name of the control, which is a unique identifier of a control. The Foreground, Background properties
sets the foreground and the background color of contents respectively.

The code snippet in Listing 1 creates a TextBlock control and sets its name, height, width, foreground,
background, the content and the TextAlignment of a TextBlock control. TextAlignment specifies the
positioning of the content inside a TextBlock. Unlike a TextBox control, the TextBlock does not have a
default border around it.

<TextBlock Name="TextBlockExample"
Background="LightCyan"
Foreground="Red"
Height="30"
Text="WPF is fun."
TextAlignment="Center"
Width="200" />

Listing 1

The output looks like Figure 1.

Figure 1

As you can see from Figure 1, by default the TextBlock is placed in the center of the page. We can place
a TextBlock control wherever we want by using the Margin, VerticalAlignment and HorizontalAlignment
attributes that sets the margin, vertical alignment, and horizontal alignment of a control.

441 @ C# Corner
The code snippet in Listing 2 sets the position of the TextBlock control in the left top corner of the page.

<TextBlock Name="TextBlock1"
Background="LightGray"
Foreground="Red"
HorizontalAlignment="Left"
Height="30"
Margin="10"
Text="WPF is fun."
TextAlignment="Center"
VerticalAlignment="Top"
Width="200" />

Listing 2

Figure 2 shows what the output of listing 2 looks like after positioning a TextBlock.

Figure 2

Creating a TextBlock Dynamically


The code listed in Listing 3 creates a TextBlock control programmatically. First, it creates a TextBlock
object and sets its width, height, contents and foreground and later the TextBlock is added to the
LayoutRoot.

Private void CreateATextBlock()


{
TextBlock txtBlock = new TextBlock();
txtBlock.Height = 50;
txtBlock.Width = 200;
txtBlock.Text = “Text Box content”;
txtBlock.Foreground = new SolidColorBrush(Colors.Red);

LayoutRoot.Children.Add(txtBlock);
}

Listing 3

442 @ C# Corner
Formatting Fonts of TextBlock
The FontSize, FontFamily, FontWeight, FontStyle, and FontStretch properties are used to format the text
of a TextBlock. The code snippet in Listing 4 sets the font properties of a TextBlock.

FontSize="14" FontFamily="Verdana" FontWeight="Bold"

Listing 4

The new output looks like Figure 2.

Figure 3

The FontSource property allows loading custom fonts dynamically. The following code snippet sets the
FontSource property.

Uri fontUri = new Uri("SomeFont.ttf", UriKind.Relative);


StreamResourceInfo MySRI = Application.GetResourceStream(fontUri);
TextBlockExample.FontSource = new FontSource(MySRI.Stream);

Wrapping, Alignment and Padding

The TextWrapping property wraps the content within a width of a control. Let’s understand this by first
setting its value to “NoWrap” with width of 200,

Text="This is a No wrap example!!! "


TextWrapping="NoWrap"
Width="200"

Listing 5

The figure 4 is an output of a TextBlock after merging code snippets in listing 5. As you can observe some
of our content is being trimmed because it’s going out of the width of a TextBlock.

443 @ C# Corner
Figure 4

Now let’s set TextWrapping="Wrap", figure 5 shows how contents are wrapped with respect to width.

Figure 5

The TextAlignment property sets the text alignment in a TextBlock, which is of type TextAlignment
enumeration. A text can be aligned left, center, or right. We have used this property in listing 1 to align
content horizontally. You can set it to Left or Right as per requirements.

TextAlignment="Right"

The Padding property sets the space between a boundary and the text. And it can be applied to all sides
or a selected side of the boundary. The padding spacing is based on left, right, top, and bottom. If you
specify only a single value, the padding will be applied to all four sides and if you specify two values, it
will be applied to LeftTop and BottomRight sides. And if you specify all 4 values then it will be applicable
to all those sides.

Listing 6 shows all these properties in a complete sample.

<TextBlock Name="TextBlock1"
Background="LightGray"
Foreground="Red"
Height="40"
Margin="10"
Padding="0 10 0 0"
Text="This is fun"
TextWrapping="Wrap"
Width="200"
FontSize="14"

444 @ C# Corner
TextAlignment="Center"
FontFamily="Verdana"
FontWeight="Bold"/>

Listing 6

Figure 6 shows what the output of listing 6 looks like. We have managed to bring text into center by
setting padding of top to 10 and rest sides to 0.

Figure 6

Inlines

The Inlines property specifies the collection of inline text within a TextBlock control. Each item is
represented by a Run object. A Run object is used to specify the inline text and can be treated as its own
text control and have its foreground and font related properties.

Listing 7 sets the Inlines property of the TextBlock and sets different fonts and foreground colors.

<TextBlock.Inlines>
<Run FontWeight="Bold" FontSize="14" Text="This is first part." />
<Run FontStyle="Italic" Foreground="Red" Text="This is red text. " />
<Run FontStyle="Italic" FontSize="18" Text="Here is some linear gradient
text. ">
<Run.Foreground>
<LinearGradientBrush>
<GradientStop Color="Green" Offset="0.0" />
<GradientStop Color="Purple" Offset="0.25" />
<GradientStop Color="Orange" Offset="0.5" />
<GradientStop Color="Blue" Offset="0.75" />
</LinearGradientBrush>
</Run.Foreground>
</Run>
<Run FontStyle="Italic" Foreground="Green" Text="How about adding some
green? " />
</TextBlock.Inlines>

Listing 7

445 @ C# Corner
The new output looks like Figure 7.

Figure 7

TextDecorations

The TextDecorations property represents the text decorations that are applied to the content of a
TextBlock. You can set it to Underline, Baseline, OverLine, Strikethrough.

Figure 8 shows how TextBlock would look and sets the TextDecorations="Underline".

Figure 8

Background

We have seen how to use Background property with a single color, we can extend this feature to set the
Background property to LinearGradientBrush.

<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</TextBlock.Background>
Listing 8

Figure 9 is an output of code snippet in listing 8.

446 @ C# Corner
Figure 9

We can extend this to one step further. The code snippet in Listing 9 sets an image as background of a
TextBlock.

<TextBlock.Background>
<ImageBrush ImageSource="Garden.jpg" Opacity="0.6"/>
</TextBlock.Background>

Summary
In this chapter, we discussed how we can create and format a TextBlock control in WPF and C#. Later
we saw how to create a TextBlock control dynamically. Then we learned to set various properties of a
TextBlock such as fonts, Inlines, and text decorations.

447 @ C# Corner
TextBox
This chapter demonstrates how to create and use a TextBox control in WPF using XAML and C#.

Creating a TextBox
The TextBox element represents a WPF TextBox control in XAML.

<TextBox/>

The Width and Height attributes of the TextBox element specify the width and the height of a TextBox.
The Text property sets the content of a TextBox. The Name attribute specifies the name of the control,
which is a unique identifier of a control.

The code snippet in Listing 1 creates a TextBox control and sets the name, height, width, and content of
a TextBox control. There are 2 more properties HorizontalContentAlignment and
VerticalContentAlignment, these properties used to position the content/text of a TextBox.

<TextBox Name="TextBoxExample"
HorizontalContentAlignment="Center"
Height="30"
VerticalContentAlignment="Center"
Width="200"
Text="This is a TextBox's example."/>

Listing 1

The output looks like Figure 1.

Figure 1

As you can see in Figure 1, by default the TextBox is placed in the center of the page. We can place a
TextBox control wherever we want by using the Margin, VerticalAlignment and HorizontalAlignment
attributes.

The code snippet in Listing 2 sets the position of the TextBox control to the left top corner of the page.

<TextBox Name="TextBoxExample"

448 @ C# Corner
HorizontalContentAlignment="Center"
HorizontalAlignment="Left"
Height="30"
Margin="5"
VerticalContentAlignment="Center"
VerticalAlignment="Top"
Width="200"
Text="This is a TextBox's example."/>

Listing 2

Figure 2

Formatting a TextBox
The BorderBrush property is used to set the border color of a TextBox. You can use any brush to fill the
border. The code snippet in Listing 3 uses a linear gradient brush to draw the border will be a
combination of red and blue color as shown in figure 3.

<TextBox.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</TextBox.BorderBrush>
Listing 3

449 @ C# Corner
Figure 3

The Background and Foreground properties of the TextBox are used to set the background and
foreground colors of a TextBox. You can use any brush to fill the border. The following code snippet in
listing 4 uses linear gradient brushes to draw the background and foreground of a TextBox.

<TextBox.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</TextBox.Background>
<TextBox.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="White" Offset="1.0" />
</LinearGradientBrush>
</TextBox.Foreground>

Listing 4

The new TextBox looks like Figure 3.

450 @ C# Corner
Figure 4

Setting Image as Background of a TextBox


The code snippet in Listing 5 sets the background of a TextBox to an image. We can use the ImageBrush
tag inside TextBox’s Background tag to set the image as a Background.

<TextBox.Background>
<ImageBrush ImageSource="YourImage.jpg" />
</TextBox.Background>

Listing 5

Creating a TextBox Dynamically


The code snippet in Listing 6 creates a TextBox control programmatically. First, it creates a TextBox
object and sets its width, height, contents, background and foreground and later the TextBox is added to
the LayoutRoot.

private void CreateATextBox()


{
TextBox txtb= new TextBox();
txtb.Height = 50;
txtb.Width = 200;
txtb.Text = "Text Box content";
txtb.Background = new SolidColorBrush(Colors.Orange);
txtb.Foreground = new SolidColorBrush(Colors.Black);
LayoutRoot.Children.Add(txtb);
}

Listing 6

Styling Fonts of TextBox’s Contents


The FontSize, FontFamily, FontWeight, FontStyle, and FontStretch properties are used to format the text
of a TextBox. The code snippet in Listing 7 sets the font properties of a TextBox.

451 @ C# Corner
FontSize="14" FontFamily="Verdana" FontWeight="Bold"

Listing 7

The new output looks like Figure 5.

Figure 5

The FontSource property allows you to load custom fonts dynamically. The following code snippet sets
the FontSource property.

Uri fontUri = new Uri("SomeFont.ttf", UriKind.Relative);


StreamResourceInfo MySRI = Application.GetResourceStream(fontUri);
TextBox1.FontSource = new FontSource(MySRI.Stream);

Listing 8

Non-Editable TextBox
The IsReadOnly property of the TextBox sets the text box to “read only” mode. By default, it is false.

IsReadOnly="True"

Restricting Text Size of a TextBox


The MaxLength property of the TextBox sets the number of characters to be allowed in a text box.

MaxLength="250"

Scrolling, Alignment, and Wrapping

The HorizontalScrollBarVisibility and VerticalScrollBarVisibility properties are used to set horizontal and
vertical scroll bars of a TextBox, which is of type ScrollBarVisibility enumeration. The ScrollBarVisibility
enumeration has four values – Disabled, Auto, Hidden, and Visible. The following code snippet sets the
horizontal and vertical scroll bars visible in a TextBox.

452 @ C# Corner
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Auto"

Wrapping
The TextWrapping property wraps the content within a width of a control. Let’s understand this by first
setting its value to “NoWrap” with a width of 150.

<TextBox Name="TextBoxExample"
FontFamily="Verdana"
FontSize="14"
FontWeight="Bold"
HorizontalContentAlignment="Center"
Height="30"
Margin="5"
TextWrapping="NoWrap"
VerticalContentAlignment="Center"
Width="150"
Text="This is a TextBox's Wrapping example.">

Listing 9

Figure 6: The content is trimmed which is more than the size of the width.

Now let’s set TextWrapping="Wrap", figure 7 shows how contents are wrapped with respect to width.

453 @ C# Corner
Figure 7: The content is wrapped around the next line once it reaches the width size.

Alignment
The TextAlignment property sets the text alignment in a TextBox, which is of type TextAlignment
enumeration. A text can be aligned left, center, or right. There is one more property you can use for the
same purpose, which is HorizontalContentAlignment which does the exact same job, but if you have
used both properties then precedence will be given to the TextAlignment property.

TextAlignment="Right"

The AcceptReturn property sets if the return is accepted in a TextBox or not. i.e. If the user presses the
enter key will it go to a new line or not.

AcceptsReturn="True"

Figure 8

AcceptsReturn="False"

Figure 9

Listing 10 shows all these properties in a complete sample.

<TextBox Name="TextBoxExample"
AcceptsReturn="True"
FontFamily="Verdana"
FontSize="14"
FontWeight="Bold"

454 @ C# Corner
HorizontalContentAlignment="Right"
Height="60"
IsReadOnly="False"
Margin="5"
MaxLength="250"
TextAlignment="Center"
TextWrapping="Wrap"
VerticalContentAlignment="Center"
Width="180"
Text="This is a TextBox's Wrapping example.">

Listing 10

Selection in TextBox
The Select and SelectAll methods are used to select text in a TextBox. The Select method is used to
select a specific range in a TextBox whereas the SelectAll method selects all the text in a TextBox.

The SelectionBrush property is used to set the color of the selected text. It makes the selected color
highlighted and The SelectedText property returns the selected text in a TextBox.

The code in Listing 11 sets the highlights of the selected text and on Button’s click event handler, It
shows the popup with selected text.

private void TextBoxExampleSelectedText()


{
string textBoxData = "C# Corner, headquartered in Philadelphia,
PA, is an online global community of 3 million software developers. " +
"C# Corner serves 5+ million visitors with 9 million page
views each month. " +
"We publish the latest news and articles on cutting-edge
software development topics. " +
"Developers share their knowledge and connect via content,
forums, and chapters. " +
"Thousands of members benefit from our monthly events,
webinars, and conferences. " +
"We also provide tools for career growth such as career
advice, resume writing, training, certifications, books and whitepapers, and
videos." +
"We also connect developers with their potential employers
via our Job board.";

TextBoxExample.Text = textBoxData;
TextBoxExample.FontFamily = new FontFamily("Georgia");
TextBoxExample.FontSize = 12;
TextBoxExample.SelectionBrush = new SolidColorBrush(Colors.Blue);
TextBoxExample.SelectionStart = 100;
TextBoxExample.SelectionLength = 200;
}

private void ButtonShowSelectedText_Click(object sender,


RoutedEventArgs e)
{
MessageBox.Show(TextBoxExample.SelectedText);

455 @ C# Corner
}

Listing 11

The new output looks like Figure 10.

Figure 10

Figure 11 shows a popup with selected text from the TextBox.

Figure 11

Summary

456 @ C# Corner
In this chapter, we learned to create and format a TextBox control in WPF and C#. Later we learned to
create a TextBox control dynamically. Then we saw how to set various properties of a TextBox to
understand its features such as making it non editable, restrict the size of text, and highlighting of the
selected text.

457 @ C# Corner
Dispatcher Timer
This chapter demonstrates how to implement a timer in WPF using the DispatchTimer class.

In this chapter, we are going to create a WPF application that has a ListBox control and this control is
being updated every second. The application looks like Figure 1.

Figure 1

Creating a DispatchTimer
XAML does not support any timer feature and WPF does not have a Timer control or class. The
DispatchTimer class defined in the System.Windows.Threading namespace can be used to add timer
functionality in WPF.

The following code snippet creates a DispatchTimer object.

DispatcherTimer dispatcherTimer = new DispatcherTimer();

Setting Tick and Interval

458 @ C# Corner
The Tick event handler executes when a DispatchTimer starts on specified Interval. The following code
snippet sets the Tick and Interval of a DispatchTimer.

dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);


dispatcherTimer.Interval = new TimeSpan(0, 0, 1);

Listing 1

Start DispatchTimer
The Start method is used to start a DispatchTimer.

dispatcherTimer.Start();

Complete Code Example


The code snippet in Listing 2 creates a DispatchTimer, sets its Tick event and Interval property then calls
its Start method. The Start method starts the timer and the Tick event handler is executed on the given
Interval value. In this code snippet, on the Tick event handler, we are updating a ListBox control and
adding the current time. we also set the selected item of the ListBox to the currently added item and
made sure this item is visible in the ListView.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
listBoxExample.Items.Add(DateTime.Now.Hour.ToString() + ":" +
DateTime.Now.Second.ToString());
CommandManager.InvalidateRequerySuggested();
listBoxExample.Items.MoveCurrentToLast();
listBoxExample.SelectedItem = listBoxExample.Items.CurrentItem;
listBoxExample.ScrollIntoView(listBoxExample.Items.CurrentItem);
}

Listing 2

Complete Code Example in VB.NET


Imports System.Windows.Threading
Class Window1

459 @ C# Corner
Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs) _
Handles MyBase.Loaded
Dim dt As DispatcherTimer = New DispatcherTimer()
AddHandler dt.Tick, AddressOf dispatcherTimer_Tick
dt.Interval = New TimeSpan(0, 0, 1)
dt.Start()
End Sub
Public Sub dispatcherTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
listBoxExample.Items.Add(DateTime.Now.Hour.ToString() + ":" +
DateTime.Now.Second.ToString())
CommandManager.InvalidateRequerySuggested()
listBoxExample.Items.MoveCurrentToLast()
listBoxExample.SelectedItem = listBoxExample.Items.CurrentItem
listBoxExample.ScrollIntoView(listBoxExample.Items.CurrentItem)
End Sub
End Class
Listing 3

Summary
In this Chapter, we discussed how we can create a DispatchTimer control to build timer applications in
WPF and C#. Then we saw how to update a ListBox control every second with the current time.

460 @ C# Corner
ToolTip
A ToolTip is a pop-up window that displays information in a small window. When we want to briefly
describe the content on the control, we can use tooltip.

Creating a ToolTip
The ToolTip element represents a ToolTip control in XAML.

<ToolTip/>

Most controls have ToolTip as in built property. Let’s take an example. Say we have a “Save” Button on a
screen.

Figure 1

By looking at Button, User doesn’t get much idea about the purpose of the Button. Let’s add a tooltip to
give more context to the user. Listing 1 shows how we can make use of ToolTip property inside a Button
control.

<Button x:Name="ButtonSave"
Content="Save"
Height="20"
ToolTip="User details will be stored in a database."
Width="200"/>
Listing 1

When the user hover mouse over a Button, they can able to see the tooltip as shown in figure 2.

461 @ C# Corner
Figure 2

We can achieve this same with the external ToolTip tag. Listing 2 shows how we can use the ToolTip tag.

<Button x:Name="ButtonSave"
Content="Save"
Height="20"
Width="200">
<Button.ToolTip>
<ToolTip Content="User details will be stored in a
database."/>
</Button.ToolTip>
</Button>
Listing 2

Say now you want to extend this capability, rather than just showing a sentence let’s we want to show
username and age too. We can use a grid to arrange this information.
We can achieve this by using Button.ToolTip. Code snippet in listing 3 creates a grid with label and
textblock.

<Button x:Name="ButtonSave"
Content="Save"
Height="20"
Width="200">
<Button.ToolTip>
<Grid Width="150">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="User Name:"
HorizontalAlignment="Right"/>
<TextBlock
Text="Alex"
FontWeight="Bold"
VerticalAlignment="Center"
Grid.Column="1"/>
<Label Content="Age:"

462 @ C# Corner
HorizontalAlignment="Right"
Grid.Row="1"/>
<TextBlock
Text="25"
FontWeight="Bold"
VerticalAlignment="Center"
Grid.Column="1"
Grid.Row="1"/>
</Grid>
</Button.ToolTip>
</Button>
Listing 3

Let’s see what output looks like. Figure 3 shows what the output of Listing 2 looks like.

Figure 3

The IsOpen property ensures if a ToolTip is visible or not. The HorizontalOffset and VerticalOffset
properties specify the horizontal and vertical distance between the target control and the tooltip
window. The Content property specifies the contents of the ToolTip.

The code snippet in Listing 4 creates a ToolTip control and sets the horizontal offset, vertical offset and
content.

<ToolTip Content="User details will be stored in a database."


HorizontalOffset="20"
IsOpen="True"
VerticalOffset="20"/>

Listing 4

The output looks like Figure 4.

463 @ C# Corner
Figure 4

ToolTip Service
To display a tooltip for a control, the ToolTipService class must be used. The SetToolTip and GetToolTip
static methods are used to set and get the tooltip of a control.

The following code snippet creates a ToolTipService.ToolTip for a control over a TextBlock.

<TextBlock Text="This is TextBlock's content!!"


HorizontalAlignment="Center"
VerticalAlignment="Center">
<ToolTipService.ToolTip >
<ToolTip Content="This is TextBlock's tooltip!"/>
</ToolTipService.ToolTip>
</TextBlock>

Listing 5

Figure 5

The code snippet in Listing 6 sets a ToolTip of a Button control with ToolTipService.

<Button Content="This is Button's content!!"


HorizontalAlignment="Center"

464 @ C# Corner
VerticalAlignment="Center"
Width="200">
<ToolTipService.ToolTip >
<ToolTip Content="This is Button's tooltip!"/>
</ToolTipService.ToolTip>
</Button>

Listing 6

If you run the application and mouse over a Button, the output looks like Figure 6.

Figure 6

Creating a Fancy Tooltip


The ToolTip content can be customized and can be mapped with multiple controls. The code snippet in
Listing 7 creates a ToolTip with an image and text.

<!-- Create a button -->


<Button Content="Mouse over me" Width="150" Height="30"
Canvas.Top="50" Canvas.Left="20">
<!-- Create a tooltip by using the ToolTipService -->
<ToolTipService.ToolTip >
<ToolTip HorizontalOffset="0" VerticalOffset="0">
<!-- Add a StackPanel to the tooltip content -->
<StackPanel Width="250" Height="150">
<!-- Add an image -->
<StackPanel.Background>
<ImageBrush ImageSource="Background.jpg"
Opacity="0.4"/>
</StackPanel.Background>
<!-- Add a text block -->
<TextBlock >
<Run Text="This is a tooltip with an image and text"
FontFamily="Georgia"
FontSize="14"
Foreground="Blue"/>
</TextBlock>
</StackPanel>
</ToolTip>
</ToolTipService.ToolTip>

465 @ C# Corner
</Button>

Listing 7

The new tooltip looks like Figure 7.

Figure 7

466 @ C# Corner
TreeView
This chapter shows you how to create and use a TreeView control available in Windows Presentation
Foundation (WPF).

Introduction
A TreeView represents data in a hierarchical view in a parent child relationship where a parent node can
be expanded or collapsed. The left side bar of Windows Explorer is an example of a TreeView.

Figure 1

The TreeView tag represents a WPF TreeView control in XAML.

<TreeView></TreeView>

The Width and Height properties specify the width and the height of a TreeView. The Name property
specifies the name of the control, which is a unique identifier of a control. The Margin property
positions the TreeView on the parent control. The HorizontalAlignment and VerticalAlignment
properties are used to set horizontal and vertical alignments.

<TreeView Name="TreeViewExample"
Height="200"
HorizontalAlignment="Left"

467 @ C# Corner
Margin="10"
VerticalAlignment="Top"
Width="200" />

Listing 1
Adding TreeView Items
A TreeView control hosts a collection of TreeViewItem. The Header property is the text of the item that
is displayed on the top of the view. The following code snippet adds a parent item and six child items to
a TreeView control.
<TreeView Name="TreeViewExample"
Height="200"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="200">
<TreeViewItem Header="Cold Drinks">
<TreeViewItem Header="Coke"></TreeViewItem>
<TreeViewItem Header="Pepsi"></TreeViewItem>
<TreeViewItem Header="Orange Juice"></TreeViewItem>
<TreeViewItem Header="Milk"></TreeViewItem>
<TreeViewItem Header="Iced Tea"></TreeViewItem>
<TreeViewItem Header="Mango Shake"></TreeViewItem>
</TreeViewItem>
</TreeView>

Listing 2

By default, the parent node is collapsed but when you click on it, the expanded view looks like Figure 2.

468 @ C# Corner
Figure 2: By default, parent node is collapsed

Figure 3: When parent node is expanded

Adding TreeView Items Dynamically


In the previous section, we saw how to add items to a TreeView at design-time from XAML. We can add
items to a TreeView from the code.

Let’s change our UI and add a TextBox and a button control. The XAML code for the TextBox and Button
controls look like listing 3.

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Name="TextBoxTreeViewItem"
Height="25"
HorizontalAlignment="Left"
Margin="10 0 0 0"
VerticalAlignment="Center"
Width="150" />
<Button Name="ButtonAddItem"
Click="AddItemButton_Click"
Content="Add Item"
Height="25"

469 @ C# Corner
HorizontalAlignment="Left"
Margin="180 0 0 0"
VerticalAlignment="Center"
Width="75"/>
<TreeView Name="TreeViewExample"
Height="200"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="245"
Grid.Row="1">
<TreeViewItem x:Name="Parent"
Header="Cold Drinks"/>
</TreeView>
</Grid>

Listing 3

On the Add Item button click event handler, we are going to add a new item to the first parent node of
the TreeView.

private void AddItemButton_Click(object sender, RoutedEventArgs e)


{
TreeViewItem newChild = new TreeViewItem();
newChild.Header = TextBoxTreeViewItem.Text;
Parent.Items.Add(newChild);
}

Listing 4

The final UI looks like figure 4 and 5.

Figure 4: Adding TreeView items dynamically

470 @ C# Corner
Figure 5

On the button's click event handler, we are adding the content of TextBox to the TreeViewItem by
calling TreeViewItem.Items.Add method.

Now if you enter text in the TextBox and click the Add Item button, it will add the contents of the
TextBox to the TreeView.

Deleting TreeView Items


We can use the TreeView.Items.Remove or TreeView.Items.RemoveAt method to delete an item from
the collection of items in the TreeView. The RemoveAt method takes the index of the item in the
collection.

Now, we modify our application and add a new button called Delete Item. The XAML code for this
button looks like below.

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Name="TextBoxTreeViewItem"
Height="25"
HorizontalAlignment="Left"
Margin="10 0 0 0"
VerticalAlignment="Center"
Width="150" />
<Button Name="ButtonAddItem"
Click="AddItemButton_Click"
Content="Add Item"
Height="25"
HorizontalAlignment="Left"

471 @ C# Corner
Margin="180 0 0 0"
VerticalAlignment="Center"
Width="75"/>
<Button Name="ButtonDeleteItem"
Click="DeleteItemButton_Click"
Content="Delete Item"
Height="25"
HorizontalAlignment="Left"
Margin="265 0 0 0"
VerticalAlignment="Center"
Width="75"/>
<TreeView Name="TreeViewExample"
Height="200"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="330"
Grid.Row="1">
<TreeViewItem x:Name="Parent"
Header="Cold Drinks"/>
<TreeViewItem x:Name="HotDrinks"
Header="Hot Drinks"/>
</TreeView>
</Grid>
Listing 5

When you run the code in listing 5, You’d see the output like figure 5.

Figure 6

The delete button’s click event handler looks like the following. On this button click, we find the index of
the selected item and call TreeView.Items.RemoveAt method as following.

private void DeleteItemButton_Click(object sender, RoutedEventArgs e)


{
TreeViewExample.Items.RemoveAt

472 @ C# Corner
(TreeViewExample.Items.IndexOf(TreeViewExample.SelectedItem));
}
Listing 6

The above code removes root items from the TreeView, not the subitems. To remove sub items, first we
need to find the selected item and then we need to call TreeViewItem.Items.RemoveAt method.

Figure 7: Selecting “Cold Drinks” and clicking delete button

Figure 8: “Cold Drinks” has been deleted

473 @ C# Corner
Styling a TreeView Items
A TreeView control is placed inside a StackPanel that contains a ScrollVewer control so when the width
or height of the panel is more than the visible area, the scroll viewer gets active and provides horizontal
and vertical scrolling functionality.

To style a TreeView, we can use individual TreeViewItems and set their properties. Alternatively, we can
use System.Resources and set Style property. The following code snippet sets TreeViewItem foreground,
font size, and font weight properties.

<Window.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Window.Resources>

Listing 7

The new TreeView looks like Figure 9.

Figure 9: Formatted TreeViewItem

TreeView with CheckBoxes


Currently our TreeViewItem has headers which are nothing but texts, to add more controls such as
CheckBox, all we have to do is add a parent control such as stack panel or any panel that you desire
inside a <TreeViewItem.Header> tag, then add CheckBox and TextBlock as a children to the stack panel.
Here in listing 8 we are doing as described for the first child.

474 @ C# Corner
<TreeViewItem Name="Child1">
<TreeViewItem.Header>
<CheckBox Name="CoffieCheckBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Coffie"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
Listing 8

Now let’s add a few more children the same way. As you may see, we are setting the name of the
CheckBoxes using the Name property. If you need to access these CheckBoxes, you may access them in
the code using their Name property.
<TreeView Name="TreeViewExample"
Height="200"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="330"
Grid.Row="1">
<TreeViewItem x:Name="Parent"
Header="Beverage">
<TreeViewItem Name="Child1">
<TreeViewItem.Header>
<CheckBox Name="CoffeeCheckBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Coffee"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Name="Child2">
<TreeViewItem.Header>
<CheckBox Name="IcedTeaCheckBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Iced Tea"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Name="Child3">
<TreeViewItem.Header>
<CheckBox Name="MangoShakeCheckBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Mango Shake"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Name="Child4">
<TreeViewItem.Header>
<CheckBox Name="MilkCheckBox">
<StackPanel Orientation="Horizontal">

475 @ C# Corner
<TextBlock Text="Milk"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Name="Child5">
<TreeViewItem.Header>
<CheckBox Name="TeaCheckBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Tea"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem Name="Child6">
<TreeViewItem.Header>
<CheckBox Name="OrangeJuiceCheckBox">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Orange Juice"></TextBlock>
</StackPanel>
</CheckBox>
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem>
</TreeView>
Listing 9

Now, the new TreeView looks like Figure 10.

Figure 10: TreeView with CheckBoxes

476 @ C# Corner
Summary
In this chapter, we discussed how to create and use a TreeView control available in WPF. We saw how
to add items to a TreeView, change item properties, add check boxes.

477 @ C# Corner
ViewBox
Most XAML elements do not support stretch and scale properties. ViewBox can be used to add stretch
and scale functionality to a XAML element. This chapter and code examples demonstrate how to stretch
and scale a XAML element using XAML Viewbox.

The following table describes the Viewbox properties.

Property Description

Child Represents the single child of a Viewbox element.

Stretch Describes how content is resized to fill its allocated space. It has values None,
Fill, Uniform, and UniformToFill.

StretchDirection Gets or sets the StretchDirection, which determines how scaling is applied to
the contents of a Viewbox. It has values Both, DownOnly, and UpOnly.

Note: A Viewbox element can have one child element only. Adding more than one child element to a
Viewbox will throw an error.

The Viewbox element represents a WPF ViewBox control in XAML.


<Viewbox />

Viewbox has a Stretch property that defines how contents supposed to fit in the space and it has 4
values: Fill, None, Uniform or UniformToFill.

The code example in Listing 1 creates a Viewbox control and sets its stretch to fill its content, the
content in here is an Ellipse element.

<Grid>
<Viewbox Name="ViewboxExample"
Height="200"
HorizontalAlignment="Center"
Stretch="Fill"
VerticalAlignment="Center"
Width="300">
<Ellipse Fill="BurlyWood" Height="100" Width="100" />
</Viewbox>
</Grid>

Listing 1

You can observe in designer, the Ellipse is occupying all the space of the parent. As shown in Figure 1.

478 @ C# Corner
Figure 1: Stretch="Fill"
Now, let’s change the value to uniform.

Figure 2: Stretch="Uniform"
let’s change the value to UniformToFill.

479 @ C# Corner
Figure 3: Stretch=" UniformToFill"
At last but not the least “None”

480 @ C# Corner
Figure 4: Stretch="None"

Dynamic Viewbox

The Viewbox class in C# represents a Viewbox control. To create a Viewbox dynamically, we can create a
Viewbox object and set its properties. Then we can use the Viewbox.Child property to set the child of a
Viewbox.

The following code example in Listing 2 creates a Viewbox dynamically and adds an Ellipse to the
Viewbox at at run-time.

private void CreateViewboxDynamically()


{
// Create a Viewbox object
Viewbox dynamicViewbox = new Viewbox();
// Set StretchDirection and Stretch properties
dynamicViewbox.StretchDirection = StretchDirection.Both;
dynamicViewbox.Stretch = Stretch.Fill;
dynamicViewbox.MaxWidth = 300;
dynamicViewbox.MaxHeight = 200;
// Create an Ellipse dynamically
Ellipse redCircle = new Ellipse();
redCircle.Height = 100;
redCircle.Width = 100;
redCircle.Fill = new SolidColorBrush(Colors.Red);

481 @ C# Corner
// Set Viewbox.Child to Ellipse
dynamicViewbox.Child = redCircle;
// Add Viewbox to Grid panel's child
RootLayout.Children.Add(dynamicViewbox);
}

Listing 2

482 @ C# Corner
6.1 : Find Controls by Name in WPF
The FindName method of the FrameworkElement class is used to find elements or controls by their
Name properties. The FrameworkElement class is the mother of all controls in WPF.

Let’s create a small application to test this method. We have TextBox to accept the user's input, Button
to call the method and at last, we have a ListBox listing all the controls that have been searched so far.

Code snippet in listing 1 shows how to create an app with the requirements we just discussed. We have
3 controls, their names are “TextBoxFindName”, “ButtonFindName” and “ListBoxFindName”.
<Grid Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Name="TextBoxFindName"
Height="25"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Center"
Width="200" />
<Button Name="ButtonFindName"
Content="Find By Name"
Click="ButtonFindName_Click"
Height="25"
HorizontalAlignment="Left"
Margin="250 10 10 10"
VerticalAlignment="Center"
Width="110" />
<ListBox Name="ListBoxFindName"
Height="150"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="350"
Grid.Row="1"/>
</Grid>

Listing 1

Let’s add logic for Button’s click event handler in listing 2, we are calling FindName method to find the
control by its name.

private void ButtonFindName_Click(object sender, RoutedEventArgs e)


{
object item = LayoutRoot.FindName(TextBoxFindName.Text);
string listItem = string.Empty;
if (item is TextBox)
{
TextBox txt = (TextBox)item;
txt.Background = new SolidColorBrush(Colors.LightYellow);
ListBoxFindName.Items.Add("TextBox is found: " +txt.Name);
}

483 @ C# Corner
else if (item is ListBox)
{
ListBox lst = (ListBox)item;
ListBoxFindName.Items.Add("ListBox is found: " + lst.Name);
}
else if (item is Button)
{
Button btn = (Button)item;
btn.Background = new SolidColorBrush(Colors.LightSeaGreen);
ListBoxFindName.Items.Add("Button is found: " + btn.Name);
}
else
{ ListBoxFindName.Items.Add("This name is not associated with any
control.");
} }

Listing 2

If you enter “TextBoxFindName” in the TextBox and click the “Find By Name” button, you will see output
like Figure 1.

Figure 1

Now let’s enter some wrong value such as “TextBoxFindNameTest” in the TextBox and click the “Find By
Name” button, you will see output like Figure 2.

484 @ C# Corner
Figure 2

At last, let’s enter the name of any other control, say ListBox which is “ListBoxFindName” and click “Find
By Name” button, you will see output like Figure 3.

Figure 3

485 @ C# Corner
6.2 : Building Transparent Controls
All WPF controls are inherited from UIElement. The Opacity property of UIElement is used to set
transparency of a control. The value of Opacity falls between 0.0 and 1.0 where 0.0 is fully transparent
and 1.0 is fully opaque.

The following code snippet creates a button control.

<Button x:Name="ButtonTransparent"
Content="Click Me!"
Height="30"
Width="200"/>

Listing 1

The output looks like Figure 1.

Figure 1

The following code sets the Opacity value of the Button control to 50%.

<Button x:Name="ButtonTransparent"
Content="Click Me!"
Height="30"
Opacity="0.5"
Width="200"/>
Listing 2

The new output looks like Figure 2.

486 @ C# Corner
Figure 2

Now let’s say you want to create a Button where only the background of the Button will be transparent,
but you want no transparency on the content of the Button, you can simply use the Button Background
property to set Opacity. We can use solid brush for background and manage the opacity specifically.
<Button x:Name="ButtonTransparent"
Content="Click Me!"
Height="30"
Width="200">
<Button.Background>
<SolidColorBrush Color="Black" Opacity="0.5" />
</Button.Background>
</Button>

Listing 3

The new output looks like Figure 3.

487 @ C# Corner
Figure 3

If you set Opacity on both the Button and its contents, the opacity will be multiplied. For example, the
following code sets Opacity of Button and as well as the background.
<Button x:Name="ButtonTransparent"
Content="Click Me!"
Height="30"
Opacity="0.5"
Width="200">
<Button.Background>
<SolidColorBrush Color="Black" Opacity="0.5" />
</Button.Background>
</Button>

Listing 4

The new output looks like Figure 4, where Opacity of background has been multiplied.

Figure 4

The following code snippet creates a Button control and sets its Opacity value dynamically.

private void CreateTransparentControls()


{
Button tpButton = new Button();
tpButton.Width = 200;
tpButton.Height = 30;
SolidColorBrush grayBrush = new SolidColorBrush(Colors.Gray);
grayBrush.Opacity = 0.25;
tpButton.Background = grayBrush;
tpButton.Content = "Click Me!";
// RootLayout is root Grid container on the Window
RootLayout.Children.Add(tpButton);
}

Listing 5

488 @ C# Corner
Chapter 7: Graphics and Media
If you have worked with Windows Graphics Device Interface (GDI) or Graphics Device Interface for .NET
(GDI+), you must be aware of the limitations of graphics capabilities in these two APIs. In brief, there
was a rendering performance issue and there was no 3D or multimedia support, limited animations, and
transformations plus slow performance as well. If you wanted to have these features, you would have to
use external APIs such as DirectX, CGI, and others.

Graphics API in WPF is designed to resolve the issues we had in GDI and GD+. WPF now offers an
integrated API that provides faster and smooth rendering, vector graphics, multimedia, 3D, animation,
transformations, and content composition.

This chapter introduces graphics API available in WPF and builds complex graphics applications. The
chapter starts with an understanding of the Shape object, its methods, and properties. After that, it
discusses shapes derived from the Shape object and how to draw and fill them. We will learn 2D and 3D
graphics, animation, and multimedia, we will also discuss how to apply various drawing effects such as
transformation and rotation on shapes.

GDI+ and WPF


If you come from GDI+ background, you must be familiar with the Pen and Brushes concepts where a
pen is used to draw a shape and a brush is used to fill a shape. In GDI+, the drawing is managed by the
Graphics class, which has Draw and Fill methods to draw and fill shapes. For example, the
DrawRectangle and the FillRectangle methods are used to draw and fill a rectangle.

This is no longer true in WPF, where a Rectangle class represents a rectangle and Stroke property is used
to draw an outline of the rectangle and Fill property is used to fill the rectangle.

Windows Forms and WPF


In Windows Forms, a Form object manages the entire rendering and drawing process. To draw graphics
shapes on a Form, we usually use the paint event of a Form. The paint event of a Form is fired every
time a Form needs to render and display child controls. The paint event is also fired when a Form
resizes, closes, or moves.

In WPF, every object has its own drawing and rendering events and processing.

ASP.NET and Silverlight


ASP.NET does not support any graphics capabilities. The way to build graphics capabilities in ASP.NET
applications is to use GDI+ in the background on the server, generate images and display images in a
Web browser.

489 @ C# Corner
This is no longer true in Silverlight. Silverlight is a subset of WPF that is used to build Web applications
with WPF and support almost the same graphics model that is supported by WPF.

Shapes
We are familiar with 2D arrays in C# where every element in the array is represented by 2 points.

In 2D graphics we are following the same concept. There are different kinds of shapes available and
most formally they have 2 coordinates, X & Y. So, if you want to draw a line, you'll need 2 points
(vertices) and each point (vertex) will have 2 coordinates on the graph.

E.g., “point1 = 30,10” & “point2 = 220,10”. This will draw a straight line.

In WPF, each 2-dimensional graphics shape such as a line or a rectangle is represented by a class object.
For example, the Line object represents a line shape, and a Rectangle object represents a rectangle
shape.

All of the shape classes are defined in the System.Windows.Shapes namespace. Table 1 describes the
classes defined in the System.Windows.Shapes namespace.

Class Description

Ellipse Draws an ellipse. Inherited from the Shape class.

Line Draws a straight line between two points. Inherited from the Shape class.

Path Draws a series of connected lines and curves. Inherited from the Shape class.

Polygon Draws a polygon, which is a connected series of lines that form a closed shape.
Inherited from the Shape class.

Polyline Draws a series of connected straight lines. Inherited from the Shape class.

Rectangle Draws a rectangle. Inherited from the Shape class.

Shape Provides a base class for shape elements, such as Ellipse, Polygon, and Rectangle.

Table 1

Like other controls, WPF has two ways to work with graphics controls. One is, at design-time using XAML
elements and their attributes and another is, at run-time using WPF classes.

In design-time behavior, XAML has an element for each shape. For example, the <Line /> element
represents a line and the <Rectangle /> element represents a rectangle shape. These elements have
attributes that represent object properties. For example, the following code snippet creates a line with

490 @ C# Corner
stroke, stroke thickness, and X1, Y1 are the starting point of a line and X2 and Y2 are the endpoints of a
line.

<Line x:Name="TwoDLine"
X1="100" Y1="100"
X2="300" Y2="100"
Stroke="DarkGray"
StrokeThickness="2"/>

Listing 1

In run-time behavior, each shape is represented by a class object. For example, the Line object
represents a line, and the Rectangle object represents a rectangle. The code snippet in Listing 2 creates
a Line object and sets its X1, Y1, X2, Y2, HorizontalAlignment, VerticalAlignment, and StrokeThickness
properties in the code.

Line aLine = new Line();


aLine.X1 = 100;
aLine.X2 = 300;
aLine.Y1 = 100;
aLine.Y2 = 100;
aLine.HorizontalAlignment = HorizontalAlignment.Left;
aLine.VerticalAlignment = VerticalAlignment.Center;
aLine.StrokeThickness = 3;
Listing 2

Both design-time and run-time have their own pros and cons. In most of the cases, you will be creating
your shapes at design-time because it is the fastest way to create and load shapes when the parameters
of a shape are predefined. You use a run-time method when the parameters of shapes are not
predefined and change at run-time depending on the user input and needs.

The Shape Class


Before we start working with shapes, we need to understand the parent class Shape.

The Shape class is an abstract class that is defined in the System.Windows namespace. This class cannot
be instantiated directly but can be inherited by derived classes. The Line, Rectangle, Ellipse, Path,
Polygon, and Polyline and the Shape derived classes that represent a line, a rectangle, an ellipse, a path,
a polygon, and a polyline respectively.

Shape Class Properties


The Fill, Stroke, Opacity, Stretch, and Geometry are some major properties of the Shape class. There are
more properties that are discussed later in this chapter.

Stroke, StrokeThickness and Fill

491 @ C# Corner
The Stroke property of the Shape class defines the Brush that is used to paint the outline or border of a
shape and the StrokeThickness property defines the width of the outline of a shape.

The Fill property is used to paint the interior of a shape. The Fill property takes a Brush (color) and uses
the brush to fill a shape.

The code snippet in Listing 3 creates an ellipse shape in XAML and uses Fill property to fill a DimGray
color in the ellipse, sets the Stroke to 2 and Stroke color to black.

<!-- This XAML creates an ellipse and fills with yellow


color with black border -->
<Ellipse x:Name="DimGrayEllipse"
Fill="DimGray"
Height="100"
Stroke="Black"
Stroke ="2"
Width="200">
Listing 3

The code listed in Listing 3 creates an ellipse filled with DimGray color and border with black color. The
result generated by Listing 4 looks exactly like the output generated by Listing 2.

/// <summary>
/// This method uses Fill property of the Shape class to
/// fill an ellipse shape
/// </summary>
public void FillAShape()
{
// Create an Ellipse
Ellipse GrayEllipse = new Ellipse();
GrayEllipse.Width = 200;
GrayEllipse.Height = 100;

// Create a Yellow and a Black Solid Brush


SolidColorBrush dimGrayBrush = new SolidColorBrush();
dimGrayBrush.Color = Colors. DimGray;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Fill an Ellipse/Shape with Yellow Brush


// And set Stroke and StrokeThickness
GrayEllipse.Fill = dimGrayBrush;
GrayEllipse.StrokeThickness = 2;
GrayEllipse.Stroke = blackBrush;

// Add the Ellipse to the StackPanel.


LayoutRoot.Children.Add(GrayEllipse);
}
Listing 4

The output of Listing 2 and Listing 3 generates an ellipse filled with yellow color and black border looks
like Figure 1.

492 @ C# Corner
Figure 1. Gray ellipse with black stroke

Opacity

The Opacity property specifies the transparency of the shape. The value of Opacity is between 0 and 1,
where 0 is fully transparent and 1 is fully opaque. The code listed in Listing 6 generates a semi-
transparent shape.
<Ellipse x:Name="DimGrayEllipse"
Fill="DimGray"
Height="100"
Opacity="0.5"
Stroke="Black"
StrokeThickness="2"
Width="200"/>

Listing 5

The output of Listing generates Figure 2.

Figure 2. Drawing transparent shapes

493 @ C# Corner
StartLineCap and EndLineCap

The StrokeStartLineCap and StrokeEndLineCap properties define the start and end line caps of a shape.
The PenLineCap enumeration defined in Table 2 is used to set the values of the StrokeStartLineCap and
StrokeEndLineCap properties.

Member name Description

Flat A cap that does not extend past the last point of the line.

Square A rectangle that has a height equal to the line thickness and a length equal to half
the line thickness.

Round A semicircle that has a diameter equal to the line thickness.

Triangle An isosceles right triangle whose base length is equal to the thickness of the line.

Table 2. PenLineCap enumeration

By default, the start and end line caps are flat. Figure 3 shows the flat, round, square, and triangle line
caps.

Figure 3. Start and End Line Caps

The code snippet in Listing 6 creates four polylines’ shapes with flat, round, ellipse and triangle start and
end line caps. The output looks like Figure 3.

<Polyline
Points="20,30 70,30 50,100 100, 100"
Stroke="Blue"
StrokeThickness="20"
StrokeStartLineCap="Flat"
StrokeEndLineCap="Flat"
/>

<Polyline Margin="80,0,0,0"
Points="20,30 70,30 50,100 100, 100"
Stroke="Blue"
StrokeThickness="20"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"/>

494 @ C# Corner
<Polyline Margin="160,0,0,0"
Points="20,30 70,30 50,100 100, 100"
Stroke="Blue"
StrokeThickness="20"
StrokeStartLineCap="Square"
StrokeEndLineCap="Square"/>

<Polyline Margin="240,0,0,0"
Points="20,30 70,30 50,100 100, 100"
Stroke="Blue"
StrokeThickness="20"
StrokeStartLineCap="Triangle"
StrokeEndLineCap="Triangle"/>
Listing 6

DashCap, DashArray, DashOffset, LineJoin, and MiterLimit

The StrokeDashCap property specifies how the end of a dash is drawn when StrokeStartLineCap and
StrokeEndLineCap are not used. It is a type of PenLineCap enumeration, which is defined in Table 2.

The StrokeDashArray property specifies the pattern of dashes and gaps for the outline of a shape. It is a
collection of Double values.

The StrokeDashOffset property specifies the distance within the dash pattern where a dash begins.

The StrokeLineJoin property specifies the type of join that is used at the vertices of a shape. It is a type
of PenLineJoin enumeration, which is defined in Table 3.

Member name Description

Miter Regular angular vertices.

Bevel Beveled vertices.

Round Rounded vertices.

Table 3. PenLineJoin enumeration

By default, Miter is the line join. Figure 4 shows the Miter, Bevel, and Round joins in polylines.

Figure 3. Start and End Line Caps

495 @ C# Corner
A miter forms a corner by beveling the ends of two joined lines. When two-line segments are joined at a
sharp angle, the miter may extend beyond the thickness of the line that strokes the path.

The StrokeMiterLimit property specifies the limit on the ratio of the miter length to the stroke thickness
of a shape. The value of the miter limit is always greater than or equal to 1.

Stretch

The Stretch property describes how a shape fills its space. The Stretch enumeration, which is defined in
the System.Windows.Media namespace, is used to set the Stretch property. The Stretch enumeration
has four members – None, Fill, Uniform, and UniformToFill and defined in Table 3.

Member name Description

None The content preserves its original size.

Fill The content is resized to fill the destination dimensions. The aspect ratio is
not preserved.

Uniform The content is resized to fit in the destination dimensions while it preserves
its native aspect ratio.

UniformToFill The content is resized to fill the destination dimensions while it preserves
its native aspect ratio. If the aspect ratio of the destination rectangle
differs from the source, the source content is clipped to fit in the
destination dimensions.

Table 2. The System.Windows.Media.Stretch enumeration

We will discuss the Stretch property use in more detail in the Imaging section of this chapter.

Geometry, GeometryTransform and RenderedGeometry

The Geometry property specifies the geometry of the shape. Two geometry related properties of the
Shape class are GeometryTransform and RenderedGeometry. We will discuss these properties in more
detail in the Transformations section of this chapter.

496 @ C# Corner
Line
The Line object represents a line shape in WPF and draws a line between two points. The X1 and Y1
properties of the Line represent the start point and X2 and Y2 properties represent the end point of the
line. The Stroke property sets the color of the line and StrokeThickness represents the width of the line.
A line shape does not have an interior so Fill property has no effect on a line.

Creating a Line

The Line element in XAML creates a line shape. The following code snippet creates a Line by setting its
start point (X1, Y1) to (50, 50) and end point (X2, Y2) to (200, 200). That means a line is drawn from
point (50, 50) to (200, 200). The code also sets the color of the line to red and width 4.

<Line x:Name="RedLine"
X1="50" Y1="50"
X2="200" Y2="200"
Stroke="Red"
StrokeThickness="4" />

Listing 7

The output looks like Figure 4.

Figure 4. A line

The CreateALine method in Listing 8 draws same line in Figure 4 dynamically.

/// <summary>
/// Creates a line at run-time
/// </summary>
public void CreateALine()
{

497 @ C# Corner
// Create a Line
Line redLine = new Line();
redLine.X1 = 50;
redLine.Y1 = 50;
redLine.X2 = 200;
redLine.Y2 = 200;

// Create a red Brush


SolidColorBrush redBrush = new SolidColorBrush();
redBrush.Color = Colors.Red;

// Set Line's width and color


redLine.StrokeThickness = 4;
redLine.Stroke = redBrush;

// Add line to the Grid.


LayoutRoot.Children.Add(redLine);
}

Listing 8

Rectangle
The Rectangle object represents a rectangle shape and draws a rectangle with the given height and
width. The Width and Height properties of the Rectangle class represent the width and height of a
rectangle shape. The Fill property fills the interior of a rectangle. The Stroke property sets the color and
StrokeThickness represents the width of the outer line of a rectangle.

Creating a Rectangle

The Rectangle element in XAML creates a rectangle shape. The following code snippet creates a
rectangle by setting its width and height properties to 200 and 100 respectively. The code also sets the
black stroke of width 4 and fills the body with LightBlue color.
<Rectangle x:Name="TwoDRectangle"
Height="100"
Fill="LightBlue"
Stroke="Black"
StrokeThickness="4"
Width="200" />

Listing 9

The output looks like Figure 5.

498 @ C# Corner
Figure 5. A rectangle

The CreateARectangle method in Listing 10 draws the same rectangle in Figure 5 dynamically.

/// <summary>
/// Creates a blue rectangle with black border
/// </summary>
public void CreateARectangle()
{
// Create a Rectangle
Rectangle blueRectangle = new Rectangle();
blueRectangle.Height = 100;
blueRectangle.Width = 200;

// Create a blue and a black Brush


SolidColorBrush blueBrush = new SolidColorBrush();
blueBrush.Color = Colors.Blue;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Set Rectangle's width and color


blueRectangle.StrokeThickness = 4;
blueRectangle.Stroke = blackBrush;
// Fill rectangle with blue color
blueRectangle.Fill = blueBrush;

// Add Rectangle to the Grid.


LayoutRoot.Children.Add(blueRectangle);
}

Listing 10
We can also have a rectangle with rounded corners, The RadiusX and RadiusY properties set the x-axis
and y-axis radii of the ellipse that is used around the corner of a rectangle. By adding the following lines
of code to Listing 10 will create a rounded rectangle, which looks like Figure 6.

// Set roundness
blueRectangle.RadiusX = 20;
blueRectangle.RadiusY = 20;

499 @ C# Corner
Or you can do the same in xaml by adding the following properties to the listing 9.
RadiusX="20"
RadiusY="20"

Figure 6. A rounded rectangle

Ellipse
The Ellipse object represents an ellipse shape in WPF and draws an ellipse with the given height and
width. The Width and Height properties of the Ellipse class represent the width and height of an ellipse.
The Fill property fills the interior of an ellipse. The Stroke property sets the color and StrokeThickness
represents the width of the outer line of an ellipse.

Creating an Ellipse

The following code snippet creates an ellipse by setting its width and height properties to 200 and 100
respectively. The code also sets the black stroke of width 4.

<Ellipse
Width="200"
Height="100"
Fill="LightBlue "
Stroke="Black"
StrokeThickness="4" />
Listing 11

The output looks like Figure 7.

500 @ C# Corner
Figure 7. An Ellipse

The CreateAnEllipse method in Listing 12 draws the same rectangle in Figure 7 dynamically.

/// <summary>
/// Creates a blue ellipse with black border
/// </summary>
public void CreateAnEllipse()
{
// Create an Ellipse
Ellipse blueRectangle = new Ellipse();
blueRectangle.Height = 100;
blueRectangle.Width = 200;

// Create a blue and a black Brush


SolidColorBrush blueBrush = new SolidColorBrush();
blueBrush.Color = Colors.Blue;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Set Ellipse's width and color


blueRectangle.StrokeThickness = 4;
blueRectangle.Stroke = blackBrush;
// Fill rectangle with blue color
blueRectangle.Fill = blueBrush;

// Add Ellipse to the Grid.


LayoutRoot.Children.Add(blueRectangle);
}
Listing 12

A circle is an ellipse with an equal width and height. If you set both width and height to 200 in the above
code listed in Listing 7, it will generate a circle as shown in figure 8.

501 @ C# Corner
Figure 8. An Ellipse with circle shape

Path
A graphics path is a set of connected lines, curves, and other simple graphics objects, including
rectangles, ellipses, and text. A path works as a single graphics object, so an effect applied to the
graphics path will be applied to all the components of the path. For example, if a graphics path contains
a line, a rectangle, and an ellipse and we draw the path using a red stroke, all three components (line,
rectangle, and ellipse) of the graphics path will be drawn with the red stroke.

The Path object represents a path shape. The Path object draws both closed and open paths. A closed
path is a shape that has the same start and end points, and an open path is a shape that has different
start and end points.

The Fill property fills the interior of an ellipse. The Stroke property sets the color and StrokeThickness
represents the width of the outer line of an ellipse.

The Data property of the Path object defines a shape or a collection of shapes in the form of Geometry.

The following code snippet creates an arc shape using a path.

<Path Stroke="Black" StrokeThickness="4"


Data="M 80,200 A 100,50 45 1 0 100,50" />

Listing 13

The output looks like Figure 9.

502 @ C# Corner
Figure 9

Before we discuss paths any further, we need to be fully aware of the Geometry class, its members, and
its related classes.

Understanding Geometry
The Geometry class that defines the geometry of a shape plays a vital role in creating paths. This class
cannot be used directly but used in the forms of its derived classes LineGeometry, RectangleGeometry,
EllipseGeometry, GroupGeometry, PathGeometry, CombinedGeometry, and StreamGeometry. These
geometry objects can be used for clipping, hit testing, and rending the complex shapes.

The LineGeometry class represents the geometry of a line. The StartPoint and EndPoint properties of the
LineGeometry class define the start and end points of a line. The following code snippet creates the
geometry of a line.

<LineGeometry StartPoint="20,50" EndPoint="200,50" />

The RectangleGeometry class represents the geometry of a rectangle. The Rect property of the
RectangleGeometry defines the starting points, width, and height of a rectangle. The following code
snippet creates the geometry of a rectangle.

<RectangleGeometry Rect="80,167 150 30"/>

The EllipseGeometry class represents the geometry of an ellipse. The Center property of the
EllipseGeometry defines the center of an ellipse. The RadiusX and RadiusY define the width and height
of an ellipse. The following code snippet creates the geometry of an ellipse.

503 @ C# Corner
<EllipseGeometry Center="80,150" RadiusX="50" RadiusY="50" />

The GeometryGroup creates a composite geometry that is a combination of multiple Geometry objects.

The code in Listing 14 creates a GeometryGroup with three geometry shapes – a line, an ellipse, and a
rectangle and sets the Data property of a path.

<Path Stroke="Black" StrokeThickness="3" Fill="Blue" >


<Path.Data>
<GeometryGroup >
<LineGeometry StartPoint="20,200" EndPoint="300,200" />
<EllipseGeometry Center="80,150" RadiusX="50" RadiusY="50" />
<RectangleGeometry Rect="80,167 150 30"/>
</GeometryGroup>
</Path.Data>
</Path>

Listing 14

The output of Listing 14 looks like Figure 10.

Figure 10. A composite shape

The FillRule property of the GeometryGroup class specifies how the intersecting areas of geometry
objects in a GeometryGroup are combined. It has two values – EvenOdd and NonZero. The default value
of the FillRule is EvenOdd. In this case, the intersecting area of two shapes is not filled. In the case of
NonZero, the interesting area of two shapes is filled. By setting the FillRule to NonZero generates Figure
11.

504 @ C# Corner
Figure 11. A composite shape with NonZero FillRule

The code listed in Listing 15 creates Figure 11 dynamically. As you can see from Listing 15, we have
created a LineGeometry, an EllipseGeometry, and a RectangleGeometry and then added a
GroupGeometry further adding all three geometries to the GroupGeometry. After that, all we must do is
simply set the Data property of Path to GroupGeometry.

/// <summary>
/// Creates a blue path with black stroke
/// </summary>
public void CreateAPath()
{
// Create a blue and a black Brush
SolidColorBrush blueBrush = new SolidColorBrush();
blueBrush.Color = Colors.Blue;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Create a Path with black brush and blue fill


Path bluePath = new Path();
bluePath.Stroke = blackBrush;
bluePath.StrokeThickness = 3;
bluePath.Fill = blueBrush;

// Create a line geometry


LineGeometry blackLineGeometry = new LineGeometry();
blackLineGeometry.StartPoint = new Point(20, 200);
blackLineGeometry.EndPoint = new Point(300, 200);

// Create an ellipse geometry


EllipseGeometry blackEllipseGeometry = new EllipseGeometry();
blackEllipseGeometry.Center = new Point(80, 150);
blackEllipseGeometry.RadiusX = 50;
blackEllipseGeometry.RadiusY = 50;

505 @ C# Corner
// Create a rectangle geometry
RectangleGeometry blackRectGeometry = new RectangleGeometry();
Rect rct = new Rect();
rct.X = 80;
rct.Y = 167;
rct.Width = 150;
rct.Height = 30;
blackRectGeometry.Rect = rct;

// Add all the geometries to a GeometryGroup.


GeometryGroup blueGeometryGroup = new GeometryGroup();
blueGeometryGroup.Children.Add(blackLineGeometry);
blueGeometryGroup.Children.Add(blackEllipseGeometry);
blueGeometryGroup.Children.Add(blackRectGeometry);

// Set Path.Data
bluePath.Data = blueGeometryGroup;
LayoutRoot.Children.Add(bluePath);
}

Listing 15

If we need to generate a single geometry, we don’t need to use a GeometryGroup. We simply must set a
geometry as the Data of the Path. The following code snippet sets an EllipseGeometry as the Data
property of a Path.

<Path Stroke="Black" StrokeThickness="3" Fill="Blue" >


<Path.Data>
<EllipseGeometry Center="80,150" RadiusX="50" RadiusY="50" />
</Path.Data>
</Path>
Listing 16

Figure 12 shows output of code snippet of listing 16.

Figure 12

506 @ C# Corner
Polygon
A polygon is a series of connected lines which is a closed shape. A closed shape is a shape that has the
same start point and end point.

The Polygon object represents a polygon shape and draws a polygon for the given connected points. The
Fill property fills the interior of an ellipse. The Stroke property sets the color of the outer line and
StrokeThickness represents the width of the outer line of a polygon. The Points property of the Polygon
specifies a collection of Points that defines the points in a polygon. The FillRule property specifies how
the interior of the polygon is determined.

Creating a Polygon

The Polygon element in XAML creates a polygon shape. The following code snippet creates a polygon by
setting its Points property to the connected points in a polygon. The code also sets the black stroke of
width 4 and fills it with yellow color.
<Polygon Fill="Yellow"
Points="50, 100 200, 100 200, 200 300, 30"
Stroke="Black"
StrokeThickness="4"/>

Listing 16

The output looks like Figure 13.

Figure 13. A Polygon

The code snippet for CreateAPolygon method in Listing 17 draws the same rectangle in Figure 13
dynamically.

507 @ C# Corner
private void CreateAPolygon()
{
// Create a blue and a black Brush
SolidColorBrush yellowBrush = new SolidColorBrush();
yellowBrush.Color = Colors.Yellow;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Create a Polygon
Polygon yellowPolygon = new Polygon();
yellowPolygon.Stroke = blackBrush;
yellowPolygon.Fill = yellowBrush;
yellowPolygon.StrokeThickness = 4;

// Create a collection of points for a polygon


System.Windows.Point Point1 = new System.Windows.Point(50, 100);
System.Windows.Point Point2 = new System.Windows.Point(200, 100);
System.Windows.Point Point3 = new System.Windows.Point(200, 200);
System.Windows.Point Point4 = new System.Windows.Point(300, 30);
PointCollection polygonPoints = new PointCollection();
polygonPoints.Add(Point1);
polygonPoints.Add(Point2);
polygonPoints.Add(Point3);
polygonPoints.Add(Point4);

// Set Polygon.Points properties


yellowPolygon.Points = polygonPoints;

// Add Polygon to the page


LayoutRoot.Children.Add(yellowPolygon);
}
Listing 17

Polyline
A polyline is a collection of connected straight lines. The Polyline object represents a polyline shape and
draws a polyline with the given points. The Points property represents the points to draw the polyline.
The Stroke property sets the color and StrokeThickness specifies the width of the line of a polyline.

Creating a Polyline

The following code snippet creates a polyline by setting its Points property. The code also sets the black
stroke of width 4.

<Polyline
Points="10,100 100,200 200,30 250,200 200,150"
Stroke="Black"
StrokeThickness="4" />
Listing 18

508 @ C# Corner
The output looks like Figure 14.

Figure 14. A Polyline

The CreateAPolyline method in Listing 19 draws the same rectangle in Figure 14 dynamically.

private void CreateAPolyline()


{
// Create a blue and a black Brush
SolidColorBrush yellowBrush = new SolidColorBrush();
yellowBrush.Color = Colors.Yellow;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Create a polyline
Polyline yellowPolyline = new Polyline();
yellowPolyline.Stroke = blackBrush;
yellowPolyline.StrokeThickness = 4;

// Create a collection of points for a polyline


System.Windows.Point Point1 = new System.Windows.Point(10, 100);
System.Windows.Point Point2 = new System.Windows.Point(100, 200);
System.Windows.Point Point3 = new System.Windows.Point(200, 30);
System.Windows.Point Point4 = new System.Windows.Point(250, 200);
System.Windows.Point Point5 = new System.Windows.Point(200, 150);
PointCollection polygonPoints = new PointCollection();
polygonPoints.Add(Point1);
polygonPoints.Add(Point2);
polygonPoints.Add(Point3);
polygonPoints.Add(Point4);
polygonPoints.Add(Point5);

// Set Polyline.Points properties

509 @ C# Corner
yellowPolyline.Points = polygonPoints;

// Add polyline to the page


LayoutRoot.Children.Add(yellowPolyline);
}
Listing 19

510 @ C# Corner
3D Graphics
The world is full of 3D objects; hence we should be able to have a 3D experience in development as well.
Every 3D object in the world is represented by 3 points: X, Y & Z. X & Y are the axis coordinates
specifying position of an object, where Z represents the depth of an object.

We can draw, transform, and animate 3D graphics in WPF.

Let's get started. Following are the things we need:

Viewport3D
It functions as a window. We need to place our 3D object inside this window.

Camera
Every 3D image is different from every angle. It depends on where the viewer is standing.

In order to specify that point of view. We can use CameraPerspective. CameraPerspective specifies
which X, Y & Z coordinate you are facing. Code snippets in listing 20 demonstrate how to use
Viewport3D with PerspectiveCamera to define position and the direction of an image.
<Viewport3D.Camera>
<PerspectiveCamera Position="5 5 4" LookDirection="-7 -4 -4"/>
</Viewport3D.Camera>

Listing 20

ModelVisual3D
It specifies the look & feel of a 3D object. You can add lights (filling up objects with a brush) to a
Model3DGroup. Code snippet in listing 21 demonstrate how to use ModelVisual3D for DirectionalLight.
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Direction="-1 -1 -1"/>
</ModelVisual3D.Content>
</ModelVisual3D>

Listing 21

GeometryModel3D
Model3D is an abstract base class. To build a 3D scene, you need some objects. We can achieve that
with GeometryModel3D.

MeshGeometry3D

511 @ C# Corner
You need to specify a list of triangle vertices inside a position property. These triangles define the clarity
of the object. Each group of 3 numbers represents the coordinates of each point in the 3D object. Code
snippets in listing 22 demonstrate how to use ModelVisual3D for GeometryModel3D.

<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-1 -1 0 1 -1 0 -1 1 0 1 1 0"
Normals="0 0 1 0 0 1 0 0 1 0 0 1"
TextureCoordinates="0 1 1 1 0 0 1 0 "
TriangleIndices="0 1 2 1 3 2" />
</GeometryModel3D.Geometry>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>

Listing 22

GeometryModel3D.Material
We have created a 3D object so far, but without texture it will not have that 3D feel. We have seen how
colors can be shiny or matte in real life and we can achieve such an effect in 3D modelling.

Some of them are as follows,

● DiffuseMaterial: Specifies the matte color.


● SpecularMaterial: Specifies the shiny color - colors which are reflective. By setting up the
SpecularPower property we can define the intensity of texture.
● EmissiveMaterial: The intensity of emitting light is equal to the color of the brush.

It has a different form of DiffuseMaterial or SpecularMaterial in look & feel. Code snippets in listing 23
demonstrate how to set DiffuseMaterial.

<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color = "DarkGoldenrod"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>

Listing 23

Now let’s see this in action, Shall we?

Figure 15 has three 3D objects, meaning it has three Viewport3D instances on a window.

512 @ C# Corner
Figure 15

In order to create output like figure 15 we need to combine everything we discuss above. Since we have
three objects, we need to have three instances. Listing 24 is showing the overall code.

<Window x:Class="_3D_Graphics.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_3D_Graphics"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">
<Grid>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="5 5 4" LookDirection="-7 -4 -4"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Direction="-1 -1 -1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>

513 @ C# Corner
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-1 -1 0 1 -1 0 -1 1 0 1 1 0"
Normals="0 0 1 0 0 1 0 0 1 0 0 1"
TextureCoordinates="0 1 1 1 0 0 1 0 "
TriangleIndices="0 1 2 1 3 2" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color = "DarkGoldenrod"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>

<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="3 3 3" LookDirection="-4 -5 -6"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Direction="-2 -2 -5"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-1 -1 0 1 -1 0 -1 1 0 1 1 0"
Normals="0 0 1 0 0 1 0 0 1 0 0 1"
TextureCoordinates="0 1 1 1 0 0 1 0 "
TriangleIndices="0 1 2 1 3 2" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color ="DarkOrange"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>

<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="3 3 1" LookDirection="-2 -2 -1"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Direction="-2 -2 -5"/>

514 @ C# Corner
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-1 -1 0 1 -1 0 -1 1 0 1 1 0"
Normals="0 0 1 0 0 1 0 0 1 0 0 1"
TextureCoordinates="0 1 1 1 0 0 1 0 "
TriangleIndices="0 1 2 1 3 2" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color = "Black"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</Window>

Listing 24

Brushes
Brushes are responsible for drawing and painting anything on a surface. In WPF, a surface is a panel such
as a Canvas or a Grid. WPF supports the following types of brushes.

● Solid Brush
● Linear Gradient Brush
● Radial Gradient Brush
● Image Brush
● Drawing Brush
● Visual Brush
● System Brushes

515 @ C# Corner
Solid Brush
A solid brush is the most basic brush and paints an area with one color. The SolidColorBrush object
represents a solid color brush. The Opacity property of the SolidColorBrush specifies the transparency of
the color that values between 0 and 1 where 0 is fully transparent and 1 is fully opaque. The Color
property specifies the solid color of the brush, which is a type of Colors class.

Creating a Solid Brush

The following code snippet creates a solid color brush with a blue color.

<SolidColorBrush Color="Blue" />

We can also set the Color property to the hexadecimal code of the color. The following code snippet sets
the color of the SolidColorBrush to blue using the hexadecimal value of the blue color.

<SolidColorBrush Color="#FF0000FF" />

Figure 16 is taken from MSDN shows the properties and hexadecimal values of the properties of the
Colors class.

516 @ C# Corner
Figure 16: Colors class properties

As we have seen in the previous sections, the Fill property of shape paints the internal areas of a shape.
We can directly specify a color in the Fill property and that brush will be used to fill a shape. The code
snippet in Listing 25 creates a rectangle shape sets the Fill property to Blue.

<Rectangle x:Name="TwoDRectangle"
Height="100"
Fill="LightBlue"
Stroke="Black"
StrokeThickness="4"
Width="200" />

Listing 25

The output looks like Figure 17.

Figure 17: A shape filled with a solid color

We can simply replace Listing 25 with the Listing 26 where we can set the Rectangle.Fill property to a
SolidColorBrush with a blue color.

<Rectangle
Width="200"
Height="100"
Stroke="Black"
StrokeThickness="4">
<Rectangle.Fill>
<SolidColorBrush Color="Blue" />
</Rectangle.Fill>
</Rectangle>
Listing 26

The CreateARectangleWithSolidBrush method listed in Listing 27 draws the same rectangle in Figure 17
dynamically.

/// <summary>
/// Creates a blue rectangle with black border

517 @ C# Corner
/// </summary>
public void CreateARectangleWithSolidBrush()
{
// Create a Rectangle
Rectangle blueRectangle = new Rectangle();
blueRectangle.Height = 100;
blueRectangle.Width = 200;

// Create a blue and a black Brush


SolidColorBrush blueBrush = new SolidColorBrush();
blueBrush.Color = Colors.Blue;
SolidColorBrush blackBrush = new SolidColorBrush();
blackBrush.Color = Colors.Black;

// Set Rectangle's width and color


blueRectangle.StrokeThickness = 4;
blueRectangle.Stroke = blackBrush;
// Fill rectangle with blue color
blueRectangle.Fill = blueBrush;

// Add Rectangle to the Grid.


LayoutRoot.Children.Add(blueRectangle);
}

Listing 27

GradientBrush
The LinearGradientBrush and the RadialGradientBrush classes represent linear and radial gradient
brushes. Both classes are inherited from the GradientBrush class. Before we discuss Linear Gradient and
Radial Gradient brushes, we need to understand the GradientBrush class.

The GradientBrush is an abstract class that describes the gradient, composed of gradient stops either
increasing or decreasing the intensity of the color. A gradient may be composed of multiple gradient
stops and each stop is a stopping point of the current gradient pattern before the next gradient pattern
starts. For example, you may build a gradient with a first stop where the first gradient starts with blue
and black, and second gradient starts with red and green colors. Initially, your gradient pattern will start
with blue and black color and then the next pattern will start with red and green colors.

ColorInterpolationMode Property

This property represents how the colors in a gradient are interpolated. It is of type
ColorInterpolationModel that has two values ScRgbLinearInterpolation and SRgbLinearInterpolation that
represent that colors are interpolated in the scRGB and sRGB color space.

GradientStops Property

This property represents the gradient stops of a gradient brush.

MappingMode Property

518 @ C# Corner
This property represents how the positioning coordinates of a gradient brush are interpreted. It is of
type BrushMappingMode enumeration that has two values – Absolute and RelativeToBoundingBox.
Absolute value means the coordinate system has nothing to do with the bounding box. In case of
RelativeToBoundingBox value, 0 indicates 0 percent of the bounding box, and 1 indicates 100 percent of
the bounding box. For example, (0.5, 0.5) describes a point in the middle of the bounding box, and (1, 1)
describes a point at the bottom right of the bounding box.

SpreadMethod Property

This property represents how to draw a gradient that starts and ends inside the bounds of the object to
be painted. It has three values – Pad, Reflect, and Repeat. Figure 19 shows examples of these values.

Figure 19: Gradient SpreadMethod

Linear Gradient Brush


A linear gradient brush paints an area with a linear gradient. The LinearGradientBrush object represents
a linear gradient brush. The default value linear gradient value is diagonal. The StartPoint and EndPoint
properties of the LinearGradientBrush represent the start and end points of a gradient. The default
values of these properties are (0,0) and (1,1), which is the upper-left corner to the lower-right corner of
an area.

Figure 20 and 21 shows a diagonal gradient (MSDN sample).

519 @ C# Corner
Figure 20: Linear Gradient

Figure 21: Linear Gradient with Stops

Creating a Linear Gradient Brush

The following code snippet creates a linear gradient brush with blue and red colors by setting
GradientStops. The StartPoint and EndPoint values are (0,0) and (1,1).

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >


<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>

We can fill a shape with a gradient brush by setting a shape’s Fill property to the gradient brush. The
code snippet in Listing 28 creates a rectangle shape and sets the Fill property to a LinearGradientBrush
with blue and red colors.

520 @ C# Corner
<Rectangle Width="200" Height="100">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>

Listing 28

The output looks like Figure 22.

Figure 22: A shape filled with a linear gradient brush

Now let’s apply multiple stops with multiple colors. The code snippet in Listing 29 creates a linear
gradient brush with five stops.

<Rectangle Width="200" Height="100">


<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Yellow" Offset="0.50" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
Listing 29

The new output generated by Listing 29 looks like Figure 23.

Figure 23: A linear gradient brush with 5 stops

521 @ C# Corner
The CreateARectangleWithLGBrush method listed in Listing 30 draws the same rectangle in Figure
23 dynamically.

public void CreateARectangleWithLGBrush()


{
// Create a Rectangle
Rectangle blueRectangle = new Rectangle();
blueRectangle.Height = 100;
blueRectangle.Width = 200;

// Create a linear gradient brush with five stops


LinearGradientBrush fiveColorLGB = new LinearGradientBrush();
fiveColorLGB.StartPoint = new Point(0, 0);
fiveColorLGB.EndPoint = new Point(1, 1);

// Create and add Gradient stops


GradientStop blueGS = new GradientStop();
blueGS.Color = Colors.Blue;
blueGS.Offset = 0.0;
fiveColorLGB.GradientStops.Add(blueGS);

GradientStop orangeGS = new GradientStop();


orangeGS.Color = Colors.Orange;
orangeGS.Offset = 0.25;
fiveColorLGB.GradientStops.Add(orangeGS);

GradientStop yellowGS = new GradientStop();


yellowGS.Color = Colors.Yellow;
yellowGS.Offset = 0.50;
fiveColorLGB.GradientStops.Add(yellowGS);

GradientStop greenGS = new GradientStop();


greenGS.Color = Colors.Green;
greenGS.Offset = 0.75;
fiveColorLGB.GradientStops.Add(greenGS);

GradientStop redGS = new GradientStop();


redGS.Color = Colors.Red;
redGS.Offset = 1.0;
fiveColorLGB.GradientStops.Add(redGS);

// Set Fill property of rectangle


blueRectangle.Fill = fiveColorLGB;

// Add Rectangle to the page


LayoutRoot.Children.Add(blueRectangle);
}

Listing 30

By simply changing the StartPoint and EndPoint values, we can generate vertical gradient shapes. By
changing a few lines in the above code snippet in Listing 30 will generate Figure 24.

522 @ C# Corner
// Create a linear gradient brush with five stops
LinearGradientBrush fiveColorLGB = new LinearGradientBrush();
fiveColorLGB.StartPoint = new Point(0, 0.5);
fiveColorLGB.EndPoint = new Point(1, 0.5);

Figure 24: Vertical gradient

Radial Gradient Brush

A radial gradient brush paints an area with a radial gradient that has a circle, along with a focal point.
The focal point defines the center of the gradient and has a default value as 0.0. The
RadialGradientBrush object represents a radial gradient brush.

Figure 25 shows a radial gradient.

Figure 25: Radial Gradient

523 @ C# Corner
Figure 26: Radial Gradient with Stops

Creating a Radial Gradient Brush

The RadialGradientBrush element in XAML creates a radial gradient brush.

The Center property of the RadialGradientBrush specifies the center of the outermost. The default
center point of the gradient circle is (0.5, 0.5).

The GradientOrigin property specifies the location of the focal point of the gradient. The default focal
point of the gradient circle is (0.5, 0.5).

The RadiusX and the RadiusY properties of the RadialGradientBrush specifies the X and Y radius of the
radial gradient.

The following code snippet creates a radial gradient brush with blue and red colors by setting
GradientStops. The GradientOrigin and Center properties are default properties. The code snippet also
sets the RadiusX and RadiusY properties.

<RadialGradientBrush
GradientOrigin="0.5,0.5"
Center="0.5,0.5"
RadiusX="0.5" RadiusY="0.5">
<RadialGradientBrush.GradientStops>
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>

Listing 31

We can fill a shape with a radial gradient brush by setting a shape’s Fill property to the gradient brush.
The code snippet in Listing 32 creates a rectangle shape that sets the Fill property to a

524 @ C# Corner
RadialGradientBrush with blue and red colors where the center of the radial gradient starts with the
blue color.

<Rectangle
Height="100"
Stroke="Black"
Width="200" >
<Rectangle.Fill>
<RadialGradientBrush
GradientOrigin="0.5,0.5"
Center="0.5,0.5" >
<RadialGradientBrush.GradientStops>
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

Listing 32

The output looks like Figure 27.

Figure 27: A shape filled with a radial gradient brush

Now let’s apply multiple stops with multiple colors. The code snippet in Listing 33 creates a radial
gradient brush with five stops.
<Rectangle
Height="100"
Stroke="Black"
Width="200" >
<Rectangle.Fill>
<RadialGradientBrush
GradientOrigin="0.5,0.5"
Center="0.5,0.5" >
<RadialGradientBrush.GradientStops>
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />

525 @ C# Corner
<GradientStop Color="Yellow" Offset="0.50" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
Listing 33

The new output generated by Listing 33 looks like Figure 28.

Figure 28: A radial gradient brush with 5 stops

The CreateARectangleWithRGBrush method listed in Listing 34 draws the same rectangle in Figure
28 dynamically.

public void CreateARectangleWithRGBrush()


{
// Create a Rectangle
Rectangle blueRectangle = new Rectangle();
blueRectangle.Height = 100;
blueRectangle.Width = 200;

// Create a radial gradient brush with five stops


RadialGradientBrush fiveColorRGB = new RadialGradientBrush();
fiveColorRGB.GradientOrigin = new Point(0.5, 0.5);
fiveColorRGB.Center = new Point(0.5, 0.5);

// Create and add Gradient stops


GradientStop blueGS = new GradientStop();
blueGS.Color = Colors.Blue;
blueGS.Offset = 0.0;
fiveColorRGB.GradientStops.Add(blueGS);

GradientStop orangeGS = new GradientStop();


orangeGS.Color = Colors.Orange;
orangeGS.Offset = 0.25;
fiveColorRGB.GradientStops.Add(orangeGS);

526 @ C# Corner
GradientStop yellowGS = new GradientStop();
yellowGS.Color = Colors.Yellow;
yellowGS.Offset = 0.50;
fiveColorRGB.GradientStops.Add(yellowGS);

GradientStop greenGS = new GradientStop();


greenGS.Color = Colors.Green;
greenGS.Offset = 0.75;
fiveColorRGB.GradientStops.Add(greenGS);

GradientStop redGS = new GradientStop();


redGS.Color = Colors.Red;
redGS.Offset = 1.0;
fiveColorRGB.GradientStops.Add(redGS);

// Set Fill property of rectangle


blueRectangle.Fill = fiveColorRGB;

// Add Rectangle to the page


LayoutRoot.Children.Add(blueRectangle);
}

Listing 34

The following code snippet changes the GradientOrigin and Center properties and now the new output
looks like Figure 29.

<RadialGradientBrush
GradientOrigin="0.2,0.5"
Center="0.1,0.5"
RadiusX="0.5" RadiusY="0.5">

Listing 35

Figure 29: Radial gradient

527 @ C# Corner
Image Brush
An image brush paints an area with an image. The ImageSource property specifies the image to be used
by an image brush. The ImageBrush object represents an image brush.

Creating an Image Brush

The ImageBrush element in XAML creates an image brush. The ImageSource property of the ImageBrush
represents the image used in the painting process.

The following code snippet creates an image brush and sets the ImageSource property to an image.

<ImageBrush ImageSource="dock.jpg" />

We can fill a shape with an image brush by setting a shape’s Fill property to the image brush. The code
snippet in Listing 36 creates a rectangle shape and sets the Fill property to an ImageBrush.

<Rectangle
Height="100"
Width="200"
Stroke="Black"
StrokeThickness="4">
<Rectangle.Fill>
<ImageBrush ImageSource="dock.jpg" />
</Rectangle.Fill>
</Rectangle>

Listing 36

The output looks like Figure 30.

Figure 30: A shape filled with an image brush

The CreateAnImageBrush method listed in Listing 37 draws the same rectangle with a dock image
shown in Figure 30.

/// <summary>
/// Fills a rectangle with an ImageBrush
/// </summary>
public void CreateAnImageBrush()
{
// Create a Rectangle
Rectangle blueRectangle = new Rectangle();
blueRectangle.Height = 100;

528 @ C# Corner
blueRectangle.Width = 200;

// Create an ImageBrush
ImageBrush imgBrush = new ImageBrush();

imgBrush.ImageSource =
new BitmapImage(new Uri(@"Dock.jpg", UriKind.Relative));

// Fill rectangle with an ImageBrush


blueRectangle.Fill = imgBrush;

// Add Rectangle to the Grid.


LayoutRoot.Children.Add(blueRectangle);
}

Listing 37

Drawing Brush
The Drawing object in WPF represents a 2-D drawing that includes shapes, text, video, image, and other
types of media. A DrawingBrush object paints a surface with a drawing. The DrawingGroup,
GeometryDrawing, GlyphRunDrawing, ImageDrawing, and VideoDrawing classes are inherited from the
Drawing class. That means we can create any of these objects to be painted by a DrawingBrush.

Creating a Drawing Brush

The DrawingBrush element in XAML creates a drawing brush.

The following code snippet creates a drawing brush and sets the Drawing property. The Drawing
property can be an element inherited from the Drawing such as a GeometryDrawing.
<DrawingBrush>
<DrawingBrush.Drawing />
</DrawingBrush>

We can fill a shape with a drawing brush by setting a shape’s Fill property to the image brush. The code
snippet in Listing 38 creates a rectangle shape sets the Fill property to a DrawingBrush.

<Grid Name="LayoutRoot">
<Rectangle Width="200" Height="200" Stroke="Black" StrokeThickness="0">
<Rectangle.Fill>
<DrawingBrush >
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Yellow">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="50,25,25,25" />
<RectangleGeometry Rect="25,50,25,25" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="5">

529 @ C# Corner
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="Blue" />
<GradientStop Offset="1.0" Color="Black" />
</LinearGradientBrush>
</Pen.Brush>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
Listing 38

The output looks like Figure 31.

Figure 31: A shape filled with a Drawing brush

The Viewport property determines the size and position of the base tile and the ViewportUnits property
determines whether the Viewport is specified using absolute or relative coordinates. If the coordinates
are relative, they are relative to the size of the output area. The point (0,0) represents the top left
corner of the output area, and (1,1) represents the bottom right corner of the output area. To specify
the Viewport property to absolute coordinates, set the ViewportUnits property to Absolute.

The TileMode property of DrawingBrush represents the tile mode that is a type of a TileMode
enumeration. The TileMode enumeration has values such as Tile, FlipX, FlipY, FlipXY, and None.

The following code snippet sets the Viewport and TileMode properties of a DrawingBrush.

530 @ C# Corner
<DrawingBrush Viewport="0,0,0.25, 0.25" TileMode="Tile">

Figure 32, 33, and 34 shows the tile modes values Tile, FilpXY, and FlipX respectively.

Figure 32: A shape filled with a Drawing brush in Tile mode

Figure 33: A shape filled with a Drawing brush with TileMode as FlipXY

531 @ C# Corner
Figure 34: A shape filled with a Drawing brush with TileMode as FlipX

One of the key examples of tile mode is to create a chess board like image that has a repeating rectangle
with black and white background colors. The CreateARectangleWithDrawingBrush method in following
Listing 39 draws a chess board like rectangle with a drawing brush dynamically.

private void CreateARectangleWithDrawingBrush()


{
// Create a background rectangle
Rectangle chessBoard = new Rectangle();
chessBoard.Width = 300;
chessBoard.Height = 300;

// Create a DrawingBrush
DrawingBrush blackBrush = new DrawingBrush();
// Create a Geometry with white background
GeometryDrawing backgroundSquare =
new GeometryDrawing(
Brushes.White,
null,
new RectangleGeometry(new Rect(0, 0, 400, 400)));
// Create a GeometryGroup that will be added to Geometry
GeometryGroup gGroup = new GeometryGroup();
gGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 200, 200)));
gGroup.Children.Add(new RectangleGeometry(new Rect(200, 200, 200, 200)));
// Create a GeometryDrawing
GeometryDrawing checkers = new GeometryDrawing(new SolidColorBrush(Colors.Black),
null, gGroup);

532 @ C# Corner
DrawingGroup checkersDrawingGroup = new DrawingGroup();
checkersDrawingGroup.Children.Add(backgroundSquare);
checkersDrawingGroup.Children.Add(checkers);
blackBrush.Drawing = checkersDrawingGroup;

// Set Viewport and TimeMode


blackBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
blackBrush.TileMode = TileMode.Tile;
// Fill rectangle with a DrawingBrush
chessBoard.Fill = blackBrush;
LayoutRoot.Children.Add(chessBoard);
}
Listing 39

The output of Listing 39 looks like Figure 35.

Figure 35. A chess board

Visual Brush
The Visual object in WPF represents a visual control. That said, you can pretty much create a visual that
can be a control or a combination of controls including a Window, Page, or even a MediaElement and
draw an element with this visual. A Visual object usually hosts one container panel such as a Grid or
StackPanel and on this container; you may place as many controls as possible you like.

533 @ C# Corner
Creating a Visual Brush

The VisualBrush element in XAML creates a visual brush.

The following code snippet creates a visual brush and sets the Visual property. The Visual property can
be an element inherited from the controls such as a Grid or StackPanel.
<VisualBrush>
<VisualBrush.Visual />
</VisualBrush>

We can fill a shape with a visual brush by setting a shape’s Fill property to the visual brush. The code
snippet in Listing 40 creates a rectangle shape and sets the Fill property to a VisualBrush. In this code,
Visual hosts a StackPanel that contains a Rectangle, TextBlock, and a Button control. Now keep in mind,
these controls on a VisualBrush can still have their own identity such as events, attributes, and methods.

<Grid Name="LayoutRoot">
<Rectangle Height="300" Margin="5,0,5,0" Stroke="Black" Width="300" >
<Rectangle.Fill>
<VisualBrush>
<VisualBrush.Visual>
<StackPanel Background="#DADDFC">
<Rectangle Height="20" Width="100">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,1" >
<GradientStop Color="#2E4C6D"
Offset="0" />
<GradientStop Color="#396EB0"
Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock FontFamily="Georgia"
Foreground="#0F2C67"
FontWeight="Bold"
TextAlignment="Center">
Visual Brush
</TextBlock>
<Button Background="#C2FFF9"
Foreground="#2E4C6D">
Button for Visual
</Button>
</StackPanel>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>

Listing 40

The output looks like Figure 36.

534 @ C# Corner
Figure 36: A shape filled with a Visual brush

Like a DrawingBrush, the VisualBrush supports both Viewport and TileMode properties.

The Viewport property determines the size and position of the base tile when the TileMode of a
DrawingBrush is set, and the ViewportUnits property determines whether the Viewport is specified
using absolute or relative coordinates. If the coordinates are relative, they are relative to the size of the
output area. The point (0,0) represents the top left corner of the output area, and (1,1) represents the
bottom right corner of the output area. To specify that the Viewport property uses absolute
coordinates, set the ViewportUnits property to Absolute.

The TileMode property of DrawingBrush represents the tile mode that is a type of a TileMode
enumeration. The TileMode enumeration has Tile, FlipX, FlipY, FlipXY, and None values.

The following code snippet sets the Viewport and TileMode properties of a DrawingBrush.
<VisualBrush Viewport="0,0,0.25,0.25" TileMode="Tile">

The output with TileMode set to Tile looks like Figure 37.

535 @ C# Corner
Figure 37: A shape filled with a Visual brush in Tile mode

The VisualBrush object in WPF is used to create a VisualBrush at run-time. The code listed in
CreateARectangleWithVisualBrush() method in Listing 41 creates a VisualBrush, sets its visual
property to a StackPanel that contains a Rectangle, TextBlock, and a Button control.
private void CreateARectangleWithVisualBrush()
{
// Create a background rectangle
Rectangle visualBoard = new Rectangle();
visualBoard.Width = 300;
visualBoard.Height = 300;
// Create a DrawingBrush
VisualBrush vBrush = new VisualBrush();
// Create a StackPanel and add a few controls to it
StackPanel stkPanel = new StackPanel();
// Create a Rectangle and add it to StackPanel
Rectangle yellowGreenRectangle = new Rectangle();
yellowGreenRectangle.Height = 100;
yellowGreenRectangle.Width = 20;
LinearGradientBrush yellowGreenLGBrush = new LinearGradientBrush();
yellowGreenLGBrush.StartPoint = new Point(0, 0);
yellowGreenLGBrush.EndPoint = new Point(1, 1);
GradientStop blueGS = new GradientStop();
blueGS.Color = Colors.Yellow;
blueGS.Offset = 0.0;
yellowGreenLGBrush.GradientStops.Add(blueGS);
GradientStop orangeGS = new GradientStop();
orangeGS.Color = Colors.Green;

536 @ C# Corner
orangeGS.Offset = 0.25;
yellowGreenLGBrush.GradientStops.Add(orangeGS);
yellowGreenRectangle.Fill = yellowGreenLGBrush;
stkPanel.Children.Add(yellowGreenRectangle);
// Create a TextBlock and add it to StackPanel
TextBlock redTextBlock = new TextBlock();
redTextBlock.Text = "Visual Brush";
redTextBlock.FontWeight = FontWeights.Bold;
redTextBlock.FontFamily = new FontFamily("Georgia");
redTextBlock.TextAlignment = TextAlignment.Center;
stkPanel.Children.Add(redTextBlock);
// Create a Button and add it to StackPanel
Button blueButton = new Button();
blueButton.Background = new SolidColorBrush(Colors.LightBlue);
blueButton.Foreground = new SolidColorBrush(Colors.Orange);
blueButton.Content = "Button for Visual";
stkPanel.Children.Add(blueButton);

// Set Viewport and TileMode


vBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
vBrush.TileMode = TileMode.Tile;
// Set Visual of VisualBrush
vBrush.Visual = stkPanel;
// Fill rectangle with a DrawingBrush
visualBoard.Fill = vBrush;
LayoutRoot.Children.Add(visualBoard);
}
Listing 41

Video Brush
A video brush is a brush like any other brush. Instead of painting an area with a color, a video brush
paints an area with a video. The video contents are provided by a MediaElement. We can use a
visualBrush to play a media by setting a MediaElement as its Visual attribute.

The following code snippet creates a MediaElement. The Source property of the MediaElement is the
name of the video file.

<MediaElement Source="Lake.wmv"
Name="McMediaElement" Width="450" Height="250" LoadedBehavior="Manual"
UnloadedBehavior="Stop" Stretch="Fill />

The code snippet in Listing 42 creates a VisualBrush and sets its Visual attribute to a MediaElement.

<VisualBrush>
<VisualBrush.Visual>

537 @ C# Corner
<MediaElement Source="Lake.wmv"
Name="McMediaElement" Width="450" Height="250"
LoadedBehavior="Manual" UnloadedBehavior="Stop" Stretch="Fill />
</VisualBrush.Visual>
</VisualBrush>
Listing 42

The code snippet in Listing 43 creates a MediaElement and sets it as the Visual property of a
VisualBrush.

MediaElement McMediaElement = new MediaElement();


McMediaElement.Source = new Uri("Lake.wmv", UriKind.Relative);
McMediaElement.IsMuted = false;

VisualBrush videoBrush = new VisualBrush();


videoBrush.Visual = McMediaElement;
Listing 43

Transparent Brushes
All elements in XAML including all brushes have an Opacity attribute that defines the transparency of an
element. The value of Opacity can be set between 0 and 1. The value 0 means an element is fully
transparent and value 1 means an element is fully opaque. The default value of Opacity is 1.

The following code snippet creates a SolidColorBrush with 50% transparency. You can set the Opacity
attribute of any brush using the same code.
<SolidColorBrush Color="Blue" Opacity="0.5"/>

Now if we set the Opacity of code in 25 as follows, the output that looks like Figure 37 will look like
Figure 38.

<VisualBrush Viewport="0,0,0.25, 0.25" TileMode="Tile" Opacity="0.5">

The following code snippet sets the Opacity property of a VisualBrush at run-time.
VisualBrush vBrush = new VisualBrush();
vBrush.Opacity = 0.50;

538 @ C# Corner
Figure 37: A rectangle with a transparent Visual brush in Tile mode

Predefined Brushes
Predefined brushes are brushes that are available in the Windows operating system. There are different
ways to apply predefined brushes in WPF.

Using Color Name

There is a brush associated with each color, you can refer to Figure 16. All these brushes are solid colors
by default. For example, if we need to fill a Rectangle with a green SolidColorBrush, we can simply set
the Fill attribute of the Rectangle to the color name. The following code snippet fills a Rectangle with
green color.

<Rectangle
Fill="Green"
Height="100"
Width="200"
Stroke="Black"
StrokeThickness="4" />
Listing 44

539 @ C# Corner
In code, we can use the Colors class to create a brush for the given color. The following code snippet
sets the Color property of a SolidColorBrush.

SolidColorBrush blueBrush = new SolidColorBrush();


blueBrush.Color = Colors.Blue;
Listing 45

Using Hexadecimal Values

We can also specify a color with its hex value. The following code snippet uses a hex value followed by a
hash (#) symbol to fill a rectangle.

<Rectangle
Fill="# FFAA1100"
Height="100"
Width="200"
Stroke="Black"
StrokeThickness="4" />
Listing 46

Using ARGB Values

A Color is represented by an ARGB value that is a combination of values for alpha, red, green, and blue
color components. By using these four values you can create any combination of colors. Alpha value in
the ARGB represents the transparency of a color. The following code snippet creates SolidColorBrush
from an ARGB value.
<Rectangle Height="100"
Width="200"
Stroke="Black"
StrokeThickness="4" >
<Rectangle.Fill>
<SolidColorBrush>
<SolidColorBrush.Color>
<Color A="150" R="0" G="0" B="255" />
</SolidColorBrush.Color>
</SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
Listing 47

The following code snippet creates a transparent blue brush using Colors.FromArgb method.

SolidColorBrush transparentBlueBrush = new SolidColorBrush();


transparentBlueBrush.Color = Colors.FromArgb(150, 0, 0, 255);

Listing 48

540 @ C# Corner
System Brushes

The SystemColors class provides support for system colors, system brushes, and system resource keys
that correspond to system display elements. The SystemBrushes class has a static property for each of
these elements. The system colors properties are represented by a Color structure. The color properties
are represented by a SolidColorBrush object. The resource properties are represented by a ResourceKey
object.

SystemBrushes are used as static resources. The following code snippet fills a Rectangle with a
MenuBrush.

<Rectangle Width="200" Height="100"


Fill="{x:Static SystemColors.MenuBrush}">
</Rectangle>
Listing 49

The following code snippet creates and fills a rectangle with a system brush dynamically.
private void CreateARectangleWithSystemBrushes()
{
Rectangle rect = new Rectangle();
rect.Width = 200;
rect.Height = 100;
rect.Fill = SystemColors.MenuBrush;
LayoutRoot.Children.Add(rect);
}
Listing 50

Brushes and Controls


In the previous discussions of this chapter, we have seen brushes being used with a shape such as a
rectangle. However, brushes are not limited to a shape. Most of the brushes can be applied to any
element in WPF including all controls. In other words, we can use a VisualBrush or an ImageBrush to set
the background of a DataGrid control or we can use a LinearGradientBrush to set the background of a
ListBox control.

How about creating a UI where a Button has an image as background, a TextBlock and ListBox controls
have a gradient background, and the Grid has a drawing brush background that looks like Figure 38?

541 @ C# Corner
Figure 38: Controls with different brush backgrounds

Code listed in Listing 51 creates this UI where you can see we set the Background attributes of controls
to a different color.

<Grid Name="LayoutRoot">
<!-- Set Grid Background to a DrawingBrush -->
<Grid.Background>
<DrawingBrush Opacity="0.25" TileMode="Tile" Viewport="0,0, 0.25, 0.25">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Yellow">
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="50,25,25,25" />
<RectangleGeometry Rect="25,50,25,25" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="5">
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="Blue" />
<GradientStop Offset="1.0" Color="Black" />
</LinearGradientBrush>
</Pen.Brush>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Grid.Background>

<!-- Create a ListBox -->


<ListBox Name="ListBoxColors"

542 @ C# Corner
BorderBrush="Red"
BorderThickness="4"
Height="210"
HorizontalAlignment="Left"
Margin="277,25,0,0"
VerticalAlignment="Top"
Width="156">
<!-- Set ListBox background to a LinearGradientBrush -->
<ListBox.Background>
<RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5"
Opacity="0.3" >
<RadialGradientBrush.GradientStops>
<GradientStop Color="Blue" Offset="0.1" />
<GradientStop Color="Orange" Offset="0.25" />
<GradientStop Color="Yellow" Offset="0.50" />
<GradientStop Color="Green" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</ListBox.Background>
</ListBox>

<!-- Create a Button -->


<Button Name="ButtonImageBackground"
BorderBrush="Blue"
BorderThickness="2"
Content="Button with Image"
Height="44"
HorizontalAlignment="Left"
FontSize="20"
FontFamily="Georgia"
FontWeight="Bold"
Margin="21,24,0,0"
VerticalAlignment="Top"
Width="230">
<!-- Set Button Background to an ImageBrush -->
<Button.Background>
<ImageBrush ImageSource="dock.jpg" Opacity="0.30" />
</Button.Background>
</Button>

<!-- Create a TextBlock -->


<TextBlock Name="TextBlockGradientBrushBackground"
FontSize="18"
Height="147"
HorizontalAlignment="Left"
Margin="21,87,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="230">

<!-- Set TextBlock background to a RadialGradientBrush -->


<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" Opacity="0.25" >
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</TextBlock.Background>

543 @ C# Corner
<TextBlock.Text>
I am a TextBlock with gradiant background colors.
How cool is that
</TextBlock.Text>
</TextBlock>
</Grid>
Listing 51

544 @ C# Corner
Pen

While a brush is used to fill shapes with colors, a pen is used to draw outlines of a shape.

The Pen element in XAML is used to create a pen at design-time. The Brush and Thickness are only two
required attributes you need to set to create a pen. The Brush property represents the brush that is
used to draw an outline and Thickness property represents the thickness of the outline.

A Pen can be created by any kind of brushes discussed above and once a Brush is set for a pen, that
brush is used to draw the outlines of a shape. The code listed in following Listing 52 creates two Pen
elements. First Pen is created using a SolidColorBrush and the second Pen is created using a
LinearGradientBrush.

<!-- SolidColorBrush Pen -->


<Pen x:Key="SolidYellowPen" Thickness="5" Brush="Yellow" />
<!-- GradientBrush Pen -->
<Pen x:Key="YellowGreenBrush" Thickness="5" >
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="Green" />
<GradientStop Offset="1.0" Color="Yellow" />
</LinearGradientBrush>
</Pen.Brush>
</Pen>
Listing 52

The code snippet in Listing 53 creates a GeometryDrawing with a Line, two Rectangle objects and uses
GeometryDrawing.Pen to draw the outline. As you can see from the Pen element, the thickness of the
Pen is 5.

<Rectangle
Height="200"
Stroke="Black"
StrokeThickness="0"
Width="200">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Yellow">
<GeometryDrawing.Geometry>
<GeometryGroup>
<LineGeometry StartPoint="25,25" EndPoint="75,75" />
<RectangleGeometry Rect="50,25,25,25" />
<RectangleGeometry Rect="25,50,25,25" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="5" >
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="Blue" />
<GradientStop Offset="1.0" Color="Black" />
</LinearGradientBrush>

545 @ C# Corner
</Pen.Brush>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
Listing 53

The output of Listing 53 looks like Figure 39. As you may notice, the outline of the rectangles and line is
just flat.

Figure 39

Now let’s add some creativity to the Pen. Pen supports several more properties including StartLineCap,
EndLineCap, DashCap, LineJoin, and MiterLimit.

StartLineCap and EndLineCap define the type of shape to use at the beginning and end of a stroke. The
value can be flat, square, triangle and round. LineJoin property defines the type of joint used at the
vertices of a shape's outline. The value of LineJoin is a type of PenLineJoin enumeration that has Miter,
Bevel, and Round values. The following code snippet sets StartLineCap, EndLineCap, and LineJoin
properties to Triangle, Round, and Bevel respectively.

<Pen
EndLineCap="Round"
LineJoin="Bevel"
StartLineCap="Triangle"
Thickness="5">
Listing 54

546 @ C# Corner
Output would look like figure 40 if you make changes specified in listing 54.

Figure 40

The DashCap attribute property defines how the ends of each dash are drawn. MiterLimit property
represents the limit on the ratio of the miter length to half this pen's Thickness.

The code snippet in Listing 55 sets some of these properties using attributes of the Pen element,
<Rectangle
Height="200"
Stroke="Black"
StrokeThickness="0"
Width="200">
<Rectangle.Fill>
<DrawingBrush >
<DrawingBrush.Drawing>
<GeometryDrawing Brush="Yellow">
<GeometryDrawing.Geometry>
<GeometryGroup>
<LineGeometry StartPoint="25,25" EndPoint="75,75" />
<RectangleGeometry Rect="50,25,25,25" />
<RectangleGeometry Rect="25,50,25,25" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen
DashCap="Triangle"
MiterLimit="0"

547 @ C# Corner
EndLineCap="Round"
LineJoin="Bevel"
StartLineCap="Triangle"
Thickness="5"
>
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="Blue" />
<GradientStop Offset="1.0" Color="Black" />
</LinearGradientBrush>
</Pen.Brush>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>

Listing 55

The output of Listing 55 looks like Figure 41.

Figure 41

The Pen object in WPF is used to create a pen at run-time. The code snippet in Listing 36 creates a Pen
object at run-time and sets some of these properties.

private void CreateADynamicPen()


{
// Create two Rectangle and one Line Geometry
LineGeometry line1 = new LineGeometry();
line1.StartPoint = new Point(25, 25);
line1.EndPoint = new Point(75, 75);

548 @ C# Corner
RectangleGeometry rect1 = new RectangleGeometry();
rect1.Rect = new Rect(50, 25, 25, 25);
RectangleGeometry rect2 = new RectangleGeometry();
rect2.Rect = new Rect(25, 50, 25, 25);
// Create a GeometryGroup and add the geometries to it.
GeometryGroup geoGroup = new GeometryGroup();
geoGroup.Children.Add(line1);
geoGroup.Children.Add(rect1);
geoGroup.Children.Add(rect2);
// Create a GeometryDrawing and add it to a DrawingGroup
GeometryDrawing geoDrawing = new GeometryDrawing();
geoDrawing.Geometry = geoGroup;
DrawingGroup drawingGrp = new DrawingGroup();
drawingGrp.Children.Add(geoDrawing);
// Create a linear gradient brush with five stops
LinearGradientBrush blueBlackLGB = new LinearGradientBrush();
blueBlackLGB.StartPoint = new Point(0, 0);
blueBlackLGB.EndPoint = new Point(1, 1);
// Create and add Gradient stops
GradientStop blueGS = new GradientStop();
blueGS.Color = Colors.Blue;
blueGS.Offset = 0.0;
blueBlackLGB.GradientStops.Add(blueGS);
GradientStop blackGS = new GradientStop();
blackGS.Color = Colors.Black;
blackGS.Offset = 1.0;
blueBlackLGB.GradientStops.Add(blackGS);
// Create a Pen to add to the GeometryDrawing
Pen blackBluePen = new Pen();
blackBluePen.Thickness = 5;
blackBluePen.LineJoin = PenLineJoin.Bevel;
blackBluePen.StartLineCap = PenLineCap.Triangle;
blackBluePen.EndLineCap = PenLineCap.Round;
blackBluePen.Brush = blueBlackLGB;
geoDrawing.Pen = blackBluePen;
// Create a DrawingBrush and fill a Rectangle with it
DrawingBrush drawingBrush = new DrawingBrush();
drawingBrush.Drawing = geoDrawing;
// Create a Rectangle and fill with DrawingBrush
Rectangle rect = new Rectangle();
rect.Width = 200;
rect.Height = 200;
rect.Stroke = new SolidColorBrush(Colors.Black);
rect.Fill = drawingBrush;
LayoutRoot.Children.Add(rect);
}
Listing 56

The output of Listing 56 generates Figure 42.

549 @ C# Corner
Figure 42

Imaging

WPF Imaging API deals with images in WPF. WPF Imaging has some improved functionality that was
missing from GDI and GDI+. This section focuses on imaging and how we can view, manipulate, and save
images.

Viewing Images
There are three different ways we can view images in WPF. We can use an Image control, an
ImageBrush, or an ImageDrawing.

Image Control
The Image control is used to load and view an image in WPF. This class displays .bmp, .gif, .ico, .jpg, .png,
.wdp, and .tiff files. If a file is a multiframe image, only the first frame will be displayed. The frame
animation is not supported by this class. The Source property of Image class specifies the image file
which needs to be loaded. We can simply specify the full path of an image file as the Source property of
the Image control.

The Image element in XAML represents an Image control at design-time. The following code that creates
an Image element and sets its Source attribute is the simplest way to view an image using the Image
control.

<Grid>
<Image Source="Background.jpg"/>
</Grid>

550 @ C# Corner
Listing 57

The output of above code snippet 57 generates a Figure 43 where image size is same as the size of the
Grid panel placed inside a Window.

Figure 43

The Width and Height properties of Image control represent the width and height of the image to be
displayed. If you do not specify the Width and Height properties for an Image, the original size of an
image will be displayed. If you set Width and Height properties of Image control, the size of the control
will change to the given size, but the aspect ratio of the image will remain the same.

The following code snippet sets the Width and Height property of an Image control.

<Grid>
<Image Source="Background.jpg" Height="300" Width="250" />
</Grid>
Listing 58

In Figure 44 you can see the Image control size is larger than the image because the aspect ratio of
image is different from 200 and 200.

551 @ C# Corner
Figure 44

The Stretch property of Image is used to stretch the image to the given size. The Stretch property is a
type of Stretch enumeration that has None, Fill, Uniform, and UniformToFill values.

The StretchDirection property of Image is used to set the stretch direction. The StretchDirection
property is a type of StretchDirection enumeration that has UpOnly, DownOnly, and Both values. This
property is applicable only when the Stretch property of an Image is set.

The following code snippet sets Stretch and StretchDirection properties to Fill and Both respectively.

<Grid>
<Image Height="300"
Source="Background.jpg"
Stretch="Fill"
StretchDirection="Both"
Width="250" />
</Grid>
Listing 59

The new output looks like Figure 45.

552 @ C# Corner
Figure 45

We can also set a BitmapImage as Source property of Image. The following code snippet uses a
BitmapImage to display an image.

<Image Width="200">
<Image.Source>
<BitmapImage UriSource="Background.jpg" />
</Image.Source>
</Image>
Listing 60

We will discuss BitmapImage class in more details later in this chapter.

The Image object in WPF is used to create an Image control at run-time. The code snippet in Listing 61
creates an Image control, creates a BitmapImage object and sets its UriSource property and then use
BitmapImage to set the Source property of Image that displays an image and sets its properties at run-
time.

private void ViewImageDynamically()


{
// Create Image Element
Image dynamicImageControl = new Image();
dynamicImageControl.Width = 250;
dynamicImageControl.Height = 300;
dynamicImageControl.Stretch = Stretch.Fill;
dynamicImageControl.StretchDirection = StretchDirection.Both;
// Create a BitmapImage and Set UriSource property

553 @ C# Corner
BitmapImage bitmapImage = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(@"Background.jpg", UriKind.RelativeOrAbsolute);
bitmapImage.EndInit();
// Set Source property of Image control
dynamicImageControl.Source = bitmapImage;
LayoutRoot.Children.Add(dynamicImageControl);

}
Listing 61

ImageBrush
We covered this topic under brushes earlier in this chapter.

ImageDrawing
ImageDrawing is another class we can use to display images in WPF. This class is a part of the drawing
family that is used by a DrawingBrush to paint surfaces as we discussed earlier in the DrawingBrush
section of this chapter.

Unlike the Image class, the ImageDrawing is a type of Freezable object. A Freezable object can be frozen
to improve performance. A freezable object has two states – frozen and unfrozen. When an object is
frozen, it cannot be modified plus all events are blocked. The case for an unfrozen state is exactly
opposite, it works the same as a normal object. When an object is in the frozen state, it avoids all the re-
rendering process and hence it gives the performance boost.

Creating an ImageDrawing

An ImageDrawing is used to draw an image within the given Rect. The ImageDrawing class has two
properties Rect and ImageSource. The Rect property defines the position and size of the image that is
being displayed by the ImageDrawing and the ImageSource property specifies the source of an image.
An ImageDrawing can be used in a DrawingBrush, DrawingImage, or a Visual.

The ImageDrawing element in XAML represents an ImageDrawing at design-time. The following code
snippet creates an ImageDrawign and sets its Rect and ImageSource attributes in XAML.
<ImageDrawing Rect="150,150,200,200" ImageSource="Background.jpg"/>

The code snippet in Listing 38 creates a border and sets the Content of border to an Image. Then the
Image.Source is set to a DrawingImage. The DrawingImage creates a Drawing and that has an
ImageDrawing inside the DrawingGroup.
<Border Name="LayoutRoot" BorderBrush="Gray" BorderThickness="1" >
<Image Stretch="None">
<Image.Source>

554 @ C# Corner
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<ImageDrawing Rect="150,150,200,200"
ImageSource=" Background.jpg"/>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Border>
Listing 62

The output looks like Figure 46.

Figure 46

The ImageDrawing object in WPF represents ImageDrawing. The CreateAnImageDrawing method


listed in Listing 63 creates an ImageDrawing and sets its properties at run-time.

public void CreateAnImageDrawing()


{
DrawingGroup drawingGrp = new DrawingGroup();
ImageDrawing dynamicImageDrawing = new ImageDrawing();
dynamicImageDrawing.Rect = new Rect(150, 150, 200, 200);
dynamicImageDrawing.ImageSource = new BitmapImage(new Uri(@"Background.jpg",
UriKind.Relative));
drawingGrp.Children.Add(dynamicImageDrawing);
DrawingImage drawingImageSource = new DrawingImage(drawingGrp);
drawingImageSource.Freeze();
Image imageControl = new Image();
imageControl.Stretch = Stretch.None;
imageControl.Source = drawingImageSource;

555 @ C# Corner
}
Listing 63
Create a Thumbnail
The BitmapImage class is used to create a thumbnail in WPF. The DecodePixelWidth and
DecodePixelHeight properties are used to set the size of the bitmap from an image and this bitmap can
be displayed in an Image control.

The BitmapImage element in XAML represents a Bitmap Image control at design-time. The following
code snippet creates a BitmapImage element and sets its DecodePixelWidth and DecodePixelHeight
attributes.

<Image
Height="120"
HorizontalAlignment="Center"
Width="120" >
<Image.Source>
<BitmapImage DecodePixelWidth="100"
DecodePixelHeight="100"
UriSource="Backgtound.jpg" />
</Image.Source>
</Image>
Listing 64

Listing 65 shows a Window with two Image controls. First Image control displays an image in its original
size and second control displays its thumbnail size.

<Border BorderBrush="Gray"
BorderThickness="2"
HorizontalAlignment="Right"
Height="130"
Margin="5"
Width="130">
<Image
Height="120"
HorizontalAlignment="Center"
Width="120">
<Image.Source>
<BitmapImage
DecodePixelWidth="100"
DecodePixelHeight="100"
UriSource="Backgtound.jpg"/>
</Image.Source>
</Image>
</Border>

Listing 65

The output of Listing 65 generates Figure 47 where the left side image is the original image and the right
side image is the thumbnail preview of the image.

556 @ C# Corner
Figure 47

The code listed in Listing 66 creates a thumbnail at run-time by creating a BitmapImage object and
setting its DecodePixelWidth and DecodePixelHeight properties.

private void CreateThumbnail()


{
// Create an Image control
Image thumbnailImage = new Image();
thumbnailImage.Width = 130;
// Create a BitmapImage and sets its DecodePixelWidth and DecodePixelHeight
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.UriSource = new Uri(@"Background.jpg", UriKind.RelativeOrAbsolute);
bmpImage.DecodePixelWidth = 120;
bmpImage.DecodePixelHeight = 120;
bmpImage.EndInit();
// Set Source property of Image
thumbnailImage.Source = bmpImage;
LayoutRoot.Children.Add(thumbnailImage);
}

Listing 66

Image Transformation

557 @ C# Corner
Image transformation is a process of rotating and scaling images.

Rotating Images
There are two ways to rotate an image. First option is to use the Rotation property of BitmapImage and
the second option is to use a TransformBitmap image. The TransformBitmap class is used for both
scaling and rotating images.

The Rotation property of BitmapImage is a type of Rotation enumeration that has four values Rotate0,
Rotate90, Rotate180, and Rotate270. The following code snippet creates a BitmapImage element and
sets its Rotation attribute to Rotate270.

<Image HorizontalAlignment="Center">
<Image.Source>
<BitmapImage UriSource="Background.jpg" Rotation="Rotate270" />
</Image.Source>
</Image>
Listing 67

Figure 44 shows the regular image and Figure 45 is the image rotates at 270 degrees.

Figure 48

558 @ C# Corner
Figure 49

Alternatively, we can use TransformBitmap and its Transform property to transform an image. The
Source attribute of TransformedBitmap is the image name. To rotate an image, we simply need to set
the Transform property to RotateTransform and set Angle attribute to the angle of rotation as shown in
below code.

<Image>
<Image.Source>
<TransformedBitmap Source="Dock.jpg" >
<TransformedBitmap.Transform>
<RotateTransform Angle="270"/>
</TransformedBitmap.Transform>
</TransformedBitmap>
</Image.Source>
</Image>
Listing 68

The code listed in Listing 69 rotates an image at run-time.

private void RotateImageDynamically()


{
// Create an Image
Image imgControl = new Image();

559 @ C# Corner
// Create the TransformedBitmap
TransformedBitmap transformBmp = new TransformedBitmap();

// Create a BitmapImage
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.UriSource = new Uri(@"Background.jpg", UriKind.RelativeOrAbsolute);
bmpImage.EndInit();
// Properties must be set between BeginInit and EndInit
transformBmp.BeginInit();
transformBmp.Source = bmpImage;
RotateTransform transform = new RotateTransform(90);
transformBmp.Transform = transform;
transformBmp.EndInit();
// Set Image.Source to TransformedBitmap
imgControl.Source = transformBmp;
LayoutRoot.Children.Add(imgControl);
}
Listing 69

Scaling Images
The ScaleTransform is used to scale an image. The ScaleX and ScaleY properties are used to resize the
image by the given factor. For example, value 0.5 reduces the image size by 50% and value 1.50
stretches the image by 150%. The CenterX and CenterY properties are used to set the point that is the
center of the scaling. By default, CenterX and CenterY values are 0 and 0 that represents the top-left
corner.

The following code snippet creates a BitmapImage element and sets its ScaleTransform property and its
attributes CenterX, CenterY, ScaleX, and ScaleY.

<Image Name="ImageControl" >


<Image.Source>
<TransformedBitmap Source="Background.jpg" >
<TransformedBitmap.Transform>
<ScaleTransform CenterX="25" CenterY="25" ScaleX="2" ScaleY="2" />
</TransformedBitmap.Transform>
</TransformedBitmap>
</Image.Source>
</Image>
Listing 70

GrayScale Image
The PixelFormats class is used to represent image pixel formats. The class has about 2 dozen static
properties representing various pixel formats such as BlackWhite, Gray16, Gray32Float, Gray8, Rgba64
and so on.

560 @ C# Corner
To apply pixel formatting on an image, we use the DestinationFormat property of
FormatConvertedBitmap. The Source property of FormatConvertedBitmap is the original
BitmapImage that you would like to convert to grayscale.

Listing 71 creates a FormatConvertedBitmap from a BitmapImage and sets its DestinationFormat to


Gray8.

private void ConvertImageToGrayScaleImage()


{
// Create an Image control
Image grayImage = new Image();
// Create a BitmapImage and sets its DecodePixelWidth and DecodePixelHeight
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.UriSource = new Uri(@"Background.jpg", UriKind.RelativeOrAbsolute);
bmpImage.EndInit();
// Create a new image using FormatConvertedBitmap and set DestinationFormat to
GrayScale
FormatConvertedBitmap grayBitmap = new FormatConvertedBitmap();
grayBitmap.BeginInit();
grayBitmap.Source = bmpImage;
grayBitmap.DestinationFormat = PixelFormats.Gray8;
grayBitmap.EndInit();
// Set Source property of Image
grayImage.Source = grayBitmap;
LayoutRoot.Children.Add(grayImage);
}

Listing 71

The output of Listing 71 generates Figure 50 which is a gray image.

561 @ C# Corner
Figure 50

Clipping or Cropping Images


Clipping a region is a process of displaying a partial area of a region by setting the outline of a region. In
WPF, the clipping has been extended to all elements that are inherited from UIElement that includes
controls, images, panels, Windows, and Pages. The UIElement class has a Clip property that is a
Geometry type and based on the given Geometry, an element can be clipped. For example, the code
snippet below clips a Window by defining an EllipseGeometry.

<Window.Clip>
<EllipseGeometry Center="150,160" RadiusX="120" RadiusY="120" />
</Window.Clip>

The following code snippet clips or crops an image to an ellipse.

<Image Source="Background.jpg">
<Image.Clip>
<EllipseGeometry Center="250,160" RadiusX="120" RadiusY="120" />
</Image.Clip>
</Image>
Listing 72

The clipped image looks like Figure 51.

562 @ C# Corner
Figure 51

Listing 73 creates a BitmapImage and then creates an Image and sets its Source property to
BitmapImage. After that, the Clip property is set to Image property to an EllipseGeometry. Listing 73
generates output the same as Figure 51.

private void ClipImage()


{
// Create a BitmapImage
BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.UriSource = new Uri(@"Background.jpg", UriKind.RelativeOrAbsolute);
bmpImage.EndInit();

// Clipped Image
Image clippedImage = new Image();
clippedImage.Source = bmpImage;
EllipseGeometry clipGeometry = new EllipseGeometry(new Point(250, 160), 120, 120);
clippedImage.Clip = clipGeometry;
LayoutRoot.Children.Add(clippedImage);
}
Listing 73

563 @ C# Corner
Summary
This chapter discussed graphics programming in WPF. The chapter started with the introduction of
graphics related classes and namespaces in .NET. After that, the chapter covered shapes and how to
draw and fill line, rectangle, ellipse, polyline, and path shapes and 3D objects. After that we discussed
how to represent various kinds of brushes in WPF and how to use them to fill different shapes. In the
last part of this chapter, we discussed how to work with images in WPF.

564 @ C# Corner
Chapter 8: Printing in WPF
Printing in WPF changes the way we used to build printing enabled applications prior to WPF. WPF
printing revolves around XML Paper Specification (XPS) file format and the XPS print path.

Basic vs. Advanced Printing


WPF breaks down XPS printing functionality into the following two categories.

● Basic printing
● Advanced printing

Basic printing involves use of the PrintDialog control and advanced printing functionality is defined in
the System.Windows.XPS and System.Printing namespaces. In most of the cases, we would only need
basic printing.

Basic Printing
The PrintDialog control in WPF is the key component in printing. PrintDialog opens Windows print dialog
box as you can see in Figure 1 and prints a document or given input.

565 @ C# Corner
Figure 1

Windows Print dialog allows users to select a printer from the available installed printers on a system. It
also lets users set printer properties and it also allows users to add a new printer using the “Find Printer”
button.

On the Print dialog, users can also specify the number of pages they would like to print if a document is
a multi-page document and print selected portions of a document. Users can also select the number of
copies, paper per sheet and paper size.

To understand the full functionality defined in PrintDialog, let’s take a look at PrintDialog properties and
methods.

PrintDialog Properties
Here is a list of PrintDialog class properties defined briefly.

● MaxPage – Highest page number that is allowed in page ranges.


● MinPage - Lowest page number that is allowed in page ranges.

566 @ C# Corner
● PageRange - Range of pages to print when PageRangeSelection is set to UserPages.
● PageRangeSelection - PageRangeSelection for this instance of PrintDialog.
● PrintableAreaHeight – Gets the Height of the printable area of the page.
● PrintableAreaWidth – Gets the Width of the printable area of the page.
● PrintQueue - Represents the printer that is selected.
● PrintTicket - It is used by the PrintDialog when the user clicks Print for the current print job.
● UserPageRangeEnabled – Enables users to have page range option.

The code snippet in Listing 1 creates a PrintDialog object and sets its properties.

private void PrintDocument()


{
PrintDialog printDlg = new()
{
MaxPage = 10,
MinPage = 2,
PageRangeSelection = PageRangeSelection.AllPages,
UserPageRangeEnabled = true
};
printDlg.ShowDialog();
}
Listing 1

PrintDialog Methods
The PrintDialog class has three methods – PrintDocument, PrintVisual, and ShowDialog.

The ShowDialog method invokes the Windows standard print dialog as a modal dialog box that lets you
select a printer and printer settings. The code snippet in Listing 2 creates a PrintDialog object and calls
its ShowDialog method that invokes the PrintDialog.
PrintDialog printDlg = new PrintDialog();
printDlg.PageRangeSelection = PageRangeSelection.AllPages;
printDlg.UserPageRangeEnabled = true;
// Display the dialog. This returns true if the user presses the Print button.
Nullable<Boolean> print = printDlg.ShowDialog();
if (print == true)
{
XpsDocument xpsDoc = new XpsDocument("SomeXPSDocument.xps",
System.IO.FileAccess.ReadWrite);
FixedDocumentSequence fixedDocSeq = xpsDoc.GetFixedDocumentSequence();
printDlg.PrintDocument(fixedDocSeq.DocumentPaginator, "XPS Doc Printing.");
}
Listing 2

The PrintDocument method prints a DocumentPaginator object to the PrintQueue that is currently
selected. To print a FlowDocument, what we need to do is, create a DocumentPaginator from a
FlowDocument. The code snippet in Listing 3 creates a PrintDialog object and calls its PrintDocument
that prints a FlowDocument.

567 @ C# Corner
private void PrintSimpleTextButton_Click(object sender, RoutedEventArgs e)
{
// Create a PrintDialog
PrintDialog printDlg = new PrintDialog();

// Create a FlowDocument dynamically


FlowDocument doc = new(new Paragraph(new Run("Some text goes here.")))
{
PagePadding = new Thickness(4),
Name = "FlowDoc"
};
// Create IDocumentPaginatorSource from FlowDocument
IDocumentPaginatorSource dps = doc;
// Call PrintDialog.PrintDocument method
printDlg.PrintDocument(dps.DocumentPaginator, "Hello WPF Printing.");
}
Listing 3

In WPF, a Visual is an object that is the parent class of all user interfaces including UIElement,
Containers, Controls, UserControls, and even Viewport3DVisual. The PrintVisual prints a Visual object.
That means, by using the PrintVisual method, we can print any control, container, Window or user
control.

The code snippet in Listing 4 creates a PrintDialog object and calls its PrintVisual method by passing a
UserControl to print the UserControl. Using this method, we can print any controls in WPF including a
Window, page, or a ListBox.
PrintDialog printDlg = new PrintDialog();
UserControl1 uc = new UserControl1();
printDlg.PrintVisual(uc, "User Control Printing.");

Listing 4
Printing a FlowDocument
Printing in WPF has changed drastically in WPF. We are used to writing a printing application using GDI
or GDI+, you will have to start thinking in a different way. Now, you have to think of a FlowDocument. If
you want to print in WPF, what you actually need to do is, create a FlowDocument object, add your
contents that you would like to print to this FlowDocument and send this FlowDocument object to the
printer.

Before you write your printing code, you must make sure you import these two namespaces in your
project.

using System.Printing;
using System.Windows.Documents;

568 @ C# Corner
The System.Windows.Documents namespace is already added to your project when you create a new
WPF project. The System.Printing namespace is required for the printing functionality.

Printing Process
OK, here are the steps required to print a FlowDocument in WPF.

1. Create a PrintDialog
The following code creates a PrintDialog in WPF.

// Create a PrintDialog
PrintDialog printDlg = new PrintDialog();

2. Create a FlowDocument

The FlowDocument object is used to create a FlowDocument. It has items such as a paragraph, run, line,
image and so on. The following code snippet creates a FlowDocument and adds a line of text to the
document.

// Create a FlowDocument dynamically.


FlowDocument doc = new FlowDocument(new Paragraph(new Run("Some text goes here")));
doc.Name = "FlowDoc";

3. Create an IDocumentPaginatorSource

The third step is to create an IDocumentPaginatorSource object from a FlowDocument which is pretty
simple.

// Create IDocumentPaginatorSource from FlowDocument


IDocumentPaginatorSource idpSource = doc;

4. Call PrintDialog.PrintDocument method

The last step is to call the PrintDialog.PrintDocument method to call the print dialog that will allow you
to select a printer and send a document to the printer to print it. The PrintDocument method of
PrintDialog takes a DocumentPaginator object that you can get from
IDocumentPaginatorSource.DocumentPaginator property as listed in the following code:

// Call PrintDocument method to send document to printer


printDlg.PrintDocument(idpSource.DocumentPaginator, "Hello WPF Printing.");

The Application
Ok now you know what is required to print FlowDocuments in WPF, let’s create a working application.
Create a WPF Application and add a Button control to the Window.

569 @ C# Corner
After that, change the Name attribute of the button to PrintSimpleTextButton and double click on it to
write a button click event handler. My XAML code of MainWindow looks like Listing 4.
<Window x:Class="PrintingTextSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Print Simple Text" Height="37" HorizontalAlignment="Left"
Margin="22,21,0,0"
Name="PrintSimpleTextButton" VerticalAlignment="Top" Width="134"
Click="PrintSimpleTextButton_Click" />
</Grid>
</Window>

Listing 4

Now we are going to create a FlowDocument in WPF. The CreateFlowDocument method in Listing 5
creates and returns a FlowDocument object. The Paragraph, Section, Underline objects represent a
paragraph, section, and underline of a document respectively. You can add as many contents to your
FlowDocument here. I am writing a tutorial on working with FlowDocuments in WPF. Stay tuned for it.

/// <summary>
/// This method creates a dynamic FlowDocument. You can add anything to this
/// FlowDocument that you would like to send to the printer
/// </summary>
/// <returns></returns>
private FlowDocument CreateFlowDocument()
{
// Create a FlowDocument
FlowDocument doc = new();
// Create a Section
Section sec = new();
// Create first Paragraph
Paragraph paragraphFirst = new();
// Create and add a new Bold, Italic and Underline
Bold bld = new();
bld.Inlines.Add(new Run("First Paragraph"));
Italic italicBld = new();
italicBld.Inlines.Add(bld);
Underline underlineItalicBld = new();
underlineItalicBld.Inlines.Add(italicBld);
// Add Bold, Italic, Underline to Paragraph
paragraphFirst.Inlines.Add(underlineItalicBld);
// Add Paragraph to Section
sec.Blocks.Add(paragraphFirst);
// Add Section to FlowDocument
doc.Blocks.Add(sec);

return doc;

570 @ C# Corner
}
Listing 5

Now, we are going to write code on the button click event handler that will create a FlowDocument and
print it.

As you can see from the code listed in Listing 6, we follow the steps discussed in the previous section.
We have first created a PrintDialog, then created a FlowDocument, converted it to an
IDocumentPaginatorSource and in the end, called PrintDialog.PrintDocument method.
private void PrintSimpleText(object sender, RoutedEventArgs e)
{
// Create a PrintDialog
PrintDialog printDlg = new();

// Create a FlowDocument dynamically


FlowDocument doc = new(new Paragraph(new Run("Some text goes here.")))
{
PagePadding = new Thickness(4),
Name = "FlowDoc"
};
// Create IDocumentPaginatorSource from FlowDocument
IDocumentPaginatorSource dps = doc;
// Call PrintDialog.PrintDocument method
printDlg.PrintDocument(dps.DocumentPaginator, "Hello WPF Printing.");
}
Listing 6

Advanced Printing
Advanced printing in WPF goes beyond the PrintDialog control and gives you more control over custom
print features. Advanced printing is supported by using XPS documents and is defined in the
System.Printing and System.Windows.Xps namespaces.

The following five key classes play a major role in printing.

● PrintSystemObject
● PrintServer
● PrintQueue
● PrintSystemJobInfo
● PrintTicket

PrintSystemObject
The PrintSystemObject class is the base class for printing classes and provides two methods –
Commit and Refresh. The Commit method saves all the changes that have been made to a

571 @ C# Corner
derived class’s object to the related hardware or software component. The Refresh method
refreshes all the properties of a derived class’s object.

PrintFilter, PrintPort, PrintQueue, PrintServer, and PrintSystemJobInfo classes are derived from
the PrintSystemObject class. We will discuss these classes and their functionality as we move
forward through this chapter.

PrintServer
The PrintServer object represents a print server that is usually a machine (a computer or a
dedicated print server) and manages print queues.

Create a PrintServer
Creating a PrintServer object is simple. You just pass the print server name in the constructor. If
you do not pass anything in the constructor, the current machine is the default print server. The
following code snippet creates a PrintServer object.
PrintServer printSvr = new PrintServer(@"\\ServerName");

PrintServer Properties
Table lists PrintServer properties described briefly.

● BeepEnabled – If set true, the Print Server beeps if an error occurs on the printer.

● DefaultSpoolDirectory – Represents the path where the print server's spool files are
located.

Name Description

Gets or sets a value that indicates whether the print server beeps in
BeepEnabled
response to an error condition in the printer.

DefaultPortThreadPriority Do not use.

DefaultSchedulerPriority Do not use.

DefaultSpoolDirectory Gets or sets the path where the print server's spool files are located.

EventLog Gets or sets the type of events that the print server logs.

Gets or sets a value that indicates whether initialization of the PrintServer


IsDelayInitialized
properties has been postponed.

572 @ C# Corner
Gets or sets a value that indicates whether the object has been disposed.
IsDisposed
(Inherited from PrintSystemObject.)

MajorVersion Gets the major version of the operating system.

MinorVersion Gets the minor version within the major version of the operating system.

Gets the name of the print server. (Overrides


Name
PrintSystemObject..::.Name.)

Gets or sets a value that indicates whether notifications that a print job
NetPopup
has finished are sent to either the print server or the client computer.

Parent Gets the parent of the object. (Inherited from PrintSystemObject.)

Gets or sets the thread priority for the process that manages I/O through
PortThreadPriority
the printer ports.

Gets a collection of attribute and value pairs. (Inherited from


PropertiesCollection
PrintSystemObject.)

Gets or sets a value that indicates whether users can restart jobs after an
RestartJobOnPoolEnabled
error occurs if printer pooling is enabled.

Gets or sets a value that indicates the wait time before a job can be
RestartJobOnPoolTimeout
restarted, if an error occurs when printer pooling is also enabled.

Gets or sets the thread priority for the process that routes print jobs from
SchedulerPriority
applications to print queues.

SubSystemVersion Gets the version of the print spooler system.

Top

See Also

PrintServer Methods
The PrintServer object represents a print server that is usually a machine (a computer or a
dedicated print server) and manages print queues.

Print Interoperability

573 @ C# Corner
Before we dig into printing functionality, let’s spend some time understanding XPS file format and XPS
print path.

574 @ C# Corner
Chapter 9: Programming Ink in WPF
This chapter discusses Ink functionality in WPF.

Ink functionality is defined in the System.Windows.Ink namespace. Before you use Ink functionality in a
WPF application, you must import this namespace System.Windows.Ink.
using System.Windows.Ink;

InkCanvas
The InkCanvas is the primary control used in drawing. An InkCanvas control defines an area that is used
as a drawing board for Ink. Usually, a pen or mouse is used to draw on an InkCanvas which then
interacts with a digitizer to produce ink strokes. An InkCanvas control works pretty much similar to a
Canvas control. The only difference is that InkCanvas supports Ink.

The InkCanvas element in XAML represents an InkCanvas.


<InkCanvas />

Like other WPF classes, the InkCanvas class is inherited from UIElement and FrameworkElement classes,
which means it has all properties such as Name, Width, Height, Background, Foreground and so on.

The code snippet in Listing 1 creates an InkCanvas control and sets some of the properties of InkCanvas
in XAML at design-time.

Let’s create a simple WPF application with an InkCanvas control.


<InkCanvas x:Name="InkBoard"
Background="LightBlue"
Height="200"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="300" />
Listing 1

Now simply build and run the application. The output of Listing 1 generates Figure 1. You can simply use
your mouse to write anything on this Window.

575 @ C# Corner
Figure 1

We can also set an image as the background of an InkCanvas. In Listing 2, we have removed the
Background property of InkCanvas and set an Image as Background using an ImageBrush.

<InkCanvas x:Name="InkBoard"
Height="300"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="500" >
<InkCanvas.Background>
<ImageBrush Opacity="0.5" ImageSource="Background.jpg" />
</InkCanvas.Background>
</InkCanvas>
Listing 2

The new output looks like Figure 2 where you will notice a picture in the background.

576 @ C# Corner
Figure 2

Creating InkCanvas Dynamically


The InkCanvas object represents an InkCanvas in WPF. The code snippet in Listing 3 creates an InkCanvas
at run-time and sets its Name, Width, Height, Background, and other properties. The LayoutRoot is the
name of the Parent Grid that is used as a container for InkCanvas.

private void CreateInkCanvasDynamically()


{
InkCanvas inkboard = new InkCanvas();
inkboard.Name = "InkBoard";
inkboard.Width = 300;
inkboard.Height = 200;
inkboard.Background = new SolidColorBrush(Colors.LightGray);
inkboard.VerticalAlignment = VerticalAlignment.Top;
inkboard.HorizontalAlignment = HorizontalAlignment.Left;
inkboard.EditingMode = InkCanvasEditingMode.Ink;
inkboard.EditingModeInverted = InkCanvasEditingMode.GestureOnly;
LayoutRoot.Children.Add(inkboard);
}

Listing 3
InkCanvas Properties
Here is a quick list of the InkCanvas properties. We are going to discuss these properties in more detail
in the following sections.

577 @ C# Corner
● ActiveEditingMode property returns the current active editing mode of an InkCanvas.
Background property represents the background brush of an InkCanvas. Children property
represents all child elements of an InkCanvas.
● DefaultDrawingAttributes property that is a type of DrawingAttributes class represents the
drawing attributes of the stroke that is used to draw the ink.
● EditingMode property represents the editing mode of InkCanvas and controls the tip of the
stylus. The EditingModeInverted property represents when the stylus is inverted, meaning when
usually editing mode is erased. Both of these properties are a type of InkCanvasEditingMode
enumeration.
● DefaultStylusPointDescription Property represents the stylus point description of an InkCanvas.
● DynamicRenderer Property represents the renderer that dynamically draws ink on an InkCanvas.
● EraserShape property represents the shape of the stylus that is used to point-erase ink from an
InkCanvas.
● InkPresenter property represents the ink presenter that displays ink on an InkCanvas.
● IsGestureRecognizerAvailable property returns true if the gesture recognizer is available on the
system.
● MoveEnabled property represents whether the user can move the selected ink strokes.
● ResizeEnabled property represents whether the user can resize the selected ink strokes.
● PreferredPasteFormats Property represents formats that can be pasted onto the InkCanvas.
● Strokes Property represents the collection of ink strokes collected by an InkCanvas.
● UseCustomCursor Property represents whether a custom cursor can be used or not.

EditingMode and EditingModeInverted


EditingMode property represents the editing mode of InkCanvas and controls the tip of the stylus. The
EditingModeInverted property represents if the stylus is inverted, meaning when usually editing mode is
eraser. Both of these properties are a type of InkCanvasEditingMode enumeration.

Figure 3 shows the InkCanvasEditingMode values that are None, Ink, GestureOnly, InkAndGesture,
Select, EraseByPoint, and EraseByStroke.

Figure 3

578 @ C# Corner
When value None is selected, no action is taken when a pen or mouse is used to draw on an InkCanvas.
When Ink is selected, the ink will be drawn on the canvas. GestureOnly will let you see the drawing, but
it will not be saved once done. InkAndGesture activates both Ink and gesture. Select indicates that the
pen selects strokes and elements on the InkCanvas. EraseByPoint indicates that the pen erases the
selected part of a stroke. EraseByStroke indicates that the pen erases an entire stroke when the pen
intersects the stroke.

The code in Listing 4 sets EditingMode and EditingModeInverted properties to Ink and GestureOnly
respectively.

InkBoard.EditingMode = InkCanvasEditingMode.Ink;
InkBoard.EditingModeInverted = InkCanvasEditingMode.GestureOnly;

Listing 4

Let’s make our Ink application more interactive. We are going to place a Label and a ComboBox control
at the right side of the InkCanvas control. The final output will look like Figure 4. The ComboBox will list
all InkEditingMode options and the mode you select from this ComboBox will be set for the InkCanvas.

Figure 4

To create a UI like figure 4, we need a Grid and then we can place items. Code snippet 5 will create an UI
for our application.
<Grid x:Name="LayoutRoot">

579 @ C# Corner
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="8*"/>
</Grid.RowDefinitions>
<InkCanvas x:Name="InkBoard"
Background="LightBlue"
Height="300"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="500"
Grid.RowSpan="2"/>
<Label x:Name="LabelInkEditingModes"
Content="Ink Editing Modes"
Margin="0 5 0 0"
VerticalAlignment="Top"
Grid.Column="1"/>
<ComboBox x:Name="ComboBoxInkEditingModes"
Height="20"
Margin="5 -15 10 0"
SelectionChanged="InkEditingModeList_SelectionChanged"
VerticalAlignment="Top"
Grid.Column="1"
Grid.Row="1" />
</Grid>

Listing 5

The GetValues method of Enum returns an array of objects. We can use this method to convert an enum
to an array and bind to a ComboBox in WPF using ItemsSource property.

The following code snippet binds InkCanvasEditingMode enum to a ComboBox. We can use Windows’
loaded Window_Loaded event handler to initialize combobox with items.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
ComboBoxInkEditingModes.ItemsSource =
System.Enum.GetValues(typeof(InkCanvasEditingMode));
}
Listing 6

Now, once we have an enum bound to a ComboBox, it will be filled up with items and the user can
select one. we can use selected items from ComboBox and convert back to the enum. Unfortunately,
the ComboBox selected item gives us a string. So, we will have to convert back the string value to an
enum value.

For that, we can use the Enum.Parse method and cast it to the enumeration. The code snippet in Listing
67takes the selected value in a ComboBox and converts it back to the enum value.

580 @ C# Corner
private void InkEditingModeList_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
InkBoard.EditingMode =
(InkCanvasEditingMode)Enum.Parse(typeof(InkCanvasEditingMode),

ComboBoxInkEditingModes.Items[ComboBoxInkEditingModes.SelectedIndex].ToString());
}
Listing 7

DrawingAttributes
DefaultDrawingAttributes property represents the drawing attributes of the stroke that is used to draw
the ink.

The DrawingAttributes class is used to set DefaultDrawingAttributes and has its own properties to define
the stroke. The Color property represents the color of a stroke. The Width and Height properties
represent the width and height of the stylus. The StylusTip property represents the shape of the stylus
used to draw the Stroke. The FitToCurve property represents a value that indicates if Bezier smoothing is
used to render the Stroke. IgnorePressure property represents a value that indicates whether the
thickness of a rendered Stroke changes according to the amount of pressure applied. The IsHighligher
property represents if the stroke looks like a highlighter.

Listing 8 creates a DrawingAttributes object and sets its properties and in the end sets
DefaultDrawingAttributes of InkCanvas.

private void SetDrawingAttributesOfInkCanvas()


{
// Create a DrawingAttributes
DrawingAttributes inkDA = new DrawingAttributes();
inkDA.Color = Colors.DeepPink;
inkDA.Height = 4;
inkDA.Width = 4;
inkDA.FitToCurve = false;
inkDA.StylusTip = StylusTip.Ellipse;
// Set DefaultDrawingAttributes of InkCanvas to this new DrawingAttributes
InkBoard.DefaultDrawingAttributes = inkDA;
}

Listing 8

Now if you draw ink on Canvas, you will see a different stylus or tip that looks like Figure 5.

581 @ C# Corner
Figure 5

We can use DefaultDrawingAttributes to implement a highlighter. You need to set the IsHighlighter
property of DrawingAttributes to true and have the color set to yellow. The code snippet in Listing 9 sets
Ink mode as a highlighter.
InkBoard.DefaultDrawingAttributes.Color = Colors.Yellow;
InkBoard.DefaultDrawingAttributes.IsHighlighter = true;
InkBoard.DefaultDrawingAttributes.Height = 30;

Listing 9

Now if you draw ink on Canvas, you will see a yellow highlighter as shown in Figure 6.

582 @ C# Corner
Figure 6

EraserShape
EraserShape property, which is a type of StylusShape class, represents the shape of the stylus which is
used to point-erase ink from an InkCanvas.

The StylusShape class represents the tip of the stylus. This is an abstract base class and used through its
two derived classes EllipseStylusShape and RectangleStylusShape. The EllipseStylusShape represents a
stylus tip shaped like an ellipse and RectangleStylusShape represents a stylus tip shaped like a rectangle.

StylusShape has three properties – Height, Width, and Rotation.

The code snippet in Listing 10 creates an EllipseStylusShape and sets EraserShape property of InkCanvas.
Note: Keep in mind, to see the stylus in this shape; you must set the EditingMode of EraseByPoint.

// Create StylusShape
EllipseStylusShape ellipseStylus = new EllipseStylusShape(25, 25, 0);
MCInkCanvas.EraserShape = ellipseStylus;

Listing 10

Strokes
The Strokes property of InkCanvas represents a collection of Stoke objects. A Stroke is the data object
that is collected from a pointing device, such as a tablet pen or a mouse in one action. A Stroke contains
information about both its position and appearance including color, size, and shape. The Stroke class in
WPF represents a Stroke that has two properties – DrawingAttributes and StylusPoints. The StylusPoints
property is a collection of StylusPoint objects that specifies the position of the Stroke. The
DrawingAttributes property specifies a stroke's appearance.

Reading Strokes
The Strokes property of InkCanvas represents all strokes of an InkCanvas. The GetSelectedStrokes
method of InkCanvas returns a StrokeCollection of selected strokes. The code snippet in Listing 11 gets
all strokes and selected strokes of an InkCanvas.

// Get Strokes
StrokeCollection strokes = InkBoard.Strokes;
foreach (Stroke stroke in InkBoard.GetSelectedStrokes())
{
// Get Stroke data here
}
Listing 11

583 @ C# Corner
Saving Strokes
The Save method of StrokeCollection can be used to save Ink strokes to a file. The code snippet in Listing
12 saves an InkCanvas stroke to a file.
// Create a FileStream
System.IO.FileStream fs = new System.IO.FileStream("InkData.isf",
System.IO.FileMode.Create);
InkBoard.Strokes.Save(fs);
fs.Close();
Listing 12
Deleting Strokes
The Clear method of StrokeCollection can be used to remove Ink from an InkCanvas.
InkBoard.Strokes.Clear();

Summary
In this chapter, we learned how to create and use Ink in WPF using InkCanvas control.

Chapter 10: Programming Speech in WPF


This speech functionality is defined in the System.Speech and its five sub namespaces. Physically, the
speech API resides in the System.Speech.Dll assembly.

Here is a list of five namespaces that define Speech related functionality.

● System.Speech.Audioformat
● System.Speech.Recognition
● Systen.Speech.Recognition.SrgsGrammar
● System.Speech.Synthesis
● Systen.Speech.Synthesis.TtsEngine

584 @ C# Corner
To access Speech API in WPF, you must add System.Speech.Dll assembly reference to a project. You can
use Nuget manager as shown in Figure 1.

Figure 1

This action will add System.Speech assembly reference and copy System.Speech.dll to the bin folder of
your project. Now you can import System.Speech related namespaces in your application.

The following code snippet imports three speech related namespaces to an application.

using System.Speech;
using System.Speech.Synthesis;
using System.Speech.Recognition;

Speech Synthesis
Speech Synthesis, known as text-to-speech in previous versions of SAPI, is a process of converting text to
speech.

Windows OS comes with a default voice called Microsoft David. You will see Voice Selection dropdown
showing Microsoft David. On this selection, you may also test the voice and audio output.

585 @ C# Corner
Figure 2

Let’s look at it. Go to the Control Panel and click on Speech. You will see Speech Properties as you can
see in Figure 2 and Figure 3.

586 @ C# Corner
Figure 3

587 @ C# Corner
You can use online speech recognition to use Cortana.

Figure 4

Speech Synthesis API


The System.Speech.Synthesis namespace defines the functionality related to speech synthesis. You must
import the following namespaces in your application before use any speech synthesis related
functionality.

using System.Speech;
using System.Speech.Synthesis;

Table 1 describes the classes available in System.Speech.Synthesis namespace.

Class Description

FilePrompt Represents a prompt spoken from a file.

InstalledVoice Represents an installed Voice object.

Prompt Plays a prompt from text or from a PromptBuilder.

PromptBuilder Creates an empty Prompt object and provides methods for adding content.

PromptStyle Defines a style of prompting that consists of settings for emphasis, rate, and
volume.

SpeechSynthesizer Supports the production of speech and DTMF output.

588 @ C# Corner
VoiceInfo Represents a text-to-speech (TTS) voice.

SpeechSynthesizer
The SpeechSynthesizer generates text to speech.

The Speak method speaks the text synchronously. The following code creates a SpeechSynthesizer
object and calls the Speak method that says “Hello WPF.”. By default, the SpeechSynthesizer uses
Microsoft Mary voice. Listing 1 calls the Speak method.

SpeechSynthesizer talker = new SpeechSynthesizer();


talker.Speak("Hello WPF.");

Listing 1

Asynchronous Speech
The SpeakAsync method speaks asynchronously and takes a Prompt, PromptBuilder or string as input
text. Listing 2 shows how to use the SpeakAsync method.

SpeechSynthesizer talker= new SpeechSynthesizer();


talker.SpeakAsync("Hello WPF");

Listing 2

SpeechSynthesizer Properties
The SpeechSynthesizer has four properties - Rate, State, Voice, and Volume that are used to get and set
rate, state, voice, and volume of the speech. The value of rate is between -10 to 10 and value of Volume
is between 0 and 100. The Voice is the VoiceInfo object and the State is the SynthesizerState object.

Let’s create the following application where users can select a voice, volume, and rate.

589 @ C# Corner
Figure 5

Code snippet in listing 3 shows how xaml would look like for our application.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>

<Label Content="Voice"/>
<ComboBox x:Name="VoicesComboBox"
Height="20"
SelectionChanged="VoicesComboBox_SelectionChanged"
Width="200"/>

<Label Content="Volume"
Grid.Row="1"/>
<ComboBox x:Name="VolumeComboBox"
Height="20"
Width="200"
Grid.Row="1"/>

<Label Content="Rate"
Grid.Row="2"/>
<ComboBox x:Name="RateComboBox"
Height="20"
Width="200"
Grid.Row="2"/>
<Button x:Name="ButtonTalk"
Content="Talk"
Click="ButtonTalk_Click"
Height="20"
Width="200"
Grid.Row="3"/>
</Grid>

Listing 3

Let’s get the data we need. We can write all presentation logic in code-behind. We need to fill all these 3
comboboxes. We can do that in the constructor as shown in listing 4.

public MainWindow()
{
InitializeComponent();
GetInstalledVoices();
List<int> rates = new List<int>();
rates.AddRange(Enumerable.Range(-10, 10));
RateComboBox.ItemsSource = rates;

590 @ C# Corner
List<int> volume = new List<int>();
volume.AddRange(Enumerable.Range(0, 100));
VolumeComboBox.ItemsSource = volume;
}

Listing 4

InstalledVoice and VoiceInfo


In code snippet 5, The GetInstalledVoices method of SpeechSynthesizer returns all installed voices on a
system. The GetInstalledVoices method returns a collection of InstalledVoice objects. The VoiceInfo
object stores the information about a voice including the voice name.

The code snippet listed in Listing 5 gets all the installed voices and adds them to a ComboBox control.

private void GetInstalledVoices()


{
SpeechSynthesizer talker = new SpeechSynthesizer();
// Load all installed voices
System.Collections.ObjectModel.ReadOnlyCollection<InstalledVoice> voices =
talker.GetInstalledVoices();
foreach (InstalledVoice voice in voices)
{
VoicesComboBox.Items.Add(voice.VoiceInfo.Name);
}
}

Listing 5

Now last, Let’s make our Button work. Listing 6 is the logic for the button.

private void ButtonTalk_Click(object sender, RoutedEventArgs e)


{
ComboBoxItem volumeItem =
(ComboBoxItem)VolumeComboBox.Items[VolumeComboBox.SelectedIndex];
int vol = Convert.ToInt32(volumeItem.Content.ToString());
ComboBoxItem rateItem =
(ComboBoxItem)RateComboBox.Items[RateComboBox.SelectedIndex];
int rate = Convert.ToInt32(rateItem.Content.ToString());
SpeechSynthesizer talker = new SpeechSynthesizer();
talker.Volume = vol;
talker.Rate = rate;
talker.SelectVoice(VoicesComboBox.Text);
//talker.Speak(ConvertRichTextBoxContentsToString());
talker.Speak("Hello WPF.");
}

Listing 6

Selecting Voice

591 @ C# Corner
In code snippet 6, The SelectVoice method of SpeechSynthesizer is used to specify the current voice that
is used to speak. The following code snippet selects a voice from a ComboBox sets the current voice.
Listing 7 calls the SelectVoice method and sets a voice.

SpeechSynthesizer talker= new SpeechSynthesizer();


talker.SelectVoice(VoicesComboBox.Text);

Listing 7

Prompt and PromptBuilder


The Prompt plays a prompt from text or a PromptBuilder.

The PromptBuilder creates an empty Prompt object and provides methods for adding content. The
PromptBuilder has 10 Append methods to append various sources. These methods are AppendAudio,
AppendBookmark, AppendBreak, AppendPromptBuilder, AppendSsml, AppendSsmlMarkup,
AppendText, AppendTextWithAlias, AppendTextWithHint, and AppendTextWithPronunciation. The
PromptBuilder class also has methods to add a Paragraph, Sentence, and Style. The ClearContent
method clears a PromptBuilder.

Within a PromptBuilder, we can also switch voices by using StartVoice and EndVoice methods. The code
listed in Listing 8 creates a PromptBuilder and uses various methods to add text, change voice, and style.

private PromptBuilder BuildPromptBuilder()


{
PromptBuilder builder = new PromptBuilder();
builder.AppendText("WPF Speech API");
builder.AppendTextWithHint("Hello! This is WPF. How may I help you?"
, SayAs.Telephone);
builder.AppendTextWithHint("A B C D E F G", SayAs.SpellOut);
// Take a 5 sec break.
builder.AppendText("Let's take a quick break.");
builder.AppendBreak(new TimeSpan(0, 0, 5));
builder.AppendText("We are back. Now we are joined with Sam.");
builder.AppendBreak(new TimeSpan(0, 0, 2));
builder.AppendText("Sam. How are you? ");

// Add Sam's voice


builder.StartVoice("Microsoft Sam");
builder.AppendText("I am fine Mary. Thank you");
builder.EndVoice();

builder.AppendText("Can we speed it up?");


// Change Speed
builder.StartStyle(new PromptStyle(PromptRate.ExtraSlow));
builder.AppendText("This is slow reading.");
builder.EndStyle();

// Play Audio
builder.AppendAudio("sound.wav");

592 @ C# Corner
// Back to normal
builder.AppendText("We are done");

return builder;
}

Listing 8

The code listed in Listing 9 uses a PromptBuilder to speak.

SpeechSynthesizer talker= new SpeechSynthesizer();


talker.SpeakAsync(BuildPromptBuilder());

Listing 9

Reading and Writing SSML


Speech Synthesis Markup Language (SSML) is a rich, XML-based markup language for assisting the
generation of synthetic speech in Web and other applications. The essential role of the markup language
is to provide authors of synthesizable content a standard way to control aspects of speech such as
pronunciation, volume, pitch, rate, etc. across different synthesis-capable platforms. You can find more
details of SSML here: http://www.w3.org/TR/speech-synthesis/

The PromptBuilder allows us to read and write SSML. The AppendSSML method allows us to append
SSML to PromptBuilder contents. The ToXml method of PromptBuilder generates SSML from
PromptBuilder contents.

The code listed in Listing 8 generates SSML from a PromptBuilder.

string str = BuildPromptBuilder().ToXml();


XmlDocument doc = new XmlDocument();
doc.LoadXml(str);
doc.Save("SSML.xml");

Listing 10

The SSML file generated using Listing 10 looks like Figure 6.

593 @ C# Corner
Figure 6

594 @ C# Corner
Speech Recognition
Speech Recognition is a reverse process of Speech Synthesis that converts speech to text. There are two
major applications for speech recognition. The first application would be for people who are unable to
type but can speak to the system and the system will type text for them. For example, in endoscopic
applications a surgeon can evaluate the patient and speak to the system. While the surgeon is doing the
evaluation, his hands are busy but he can speak. The second application is speech command enabled
applications where instead of using a mouse, we can use voice to run and execute an application
commands, just like Siri and Google assistant.

Windows OS comes with built-in Speech Recognition controls that allow you to set up speech related
options such as voice settings, microphone, and other voice recognition settings. Let’s take a quick look
at what the Control Panel has to offer related to Speech Recognition.

Go to the Control Panel and open Speech Recognition Options. You will see a dialog that looks like
Figure 7.

Figure 7

As you can see from Figure 7, there are options to start speech recognition, set up your microphone,
take a speech tutorial, train your computer, and open a reference card. You may want to click on these
options one by one to understand Speech Recognition better.

If you click on the first link Start Speech Recognition, it will activate speech recognition on the system
and the system will start listening to sounds around your computer.

595 @ C# Corner
Next option is Set up Microphone. This option allows you to tell the system what microphone to use if
you have more than one. Otherwise the system will use the default microphone.

Next option Take Speech Tutorial is a step by step tutorial that teaches you how to use various system
controls.

Next option, training your computer to better understand is very important. Before you want to build
and test your application, I recommend you use this option and follow step by steps of the wizard. This
wizard will understand your voice and ensure the accuracy of commands you send to the system. If you
do not train your computer for your voice, the computer may not understand your command properly.

The component that is responsible for controlling and managing speech recognition is called Windows
Desktop Speech Technology Recognition Engine (SR Engine).

When you build a Speech Recognition application and you do not set up microphone and voice settings,
the system will launch wizards and it will ask you to set up these settings. On a Windows machine,
the first time you will use its and some Speech Recognition controls, you will notice a Windows
application like figure 7 and 8.

Figure 8

Figure 9

That tells me that the SR Engine is ready. We just need to enable this by saying first command start
listening.

If you right click on Speech Recognition control, you will see various options that allow you to turn
speech recognition on, off and put it in sleep mode as you see in Figure 10.

596 @ C# Corner
Figure 10

Speech Recognition API


Speech Recognition functionality is defined in the System.Speech.Recognition namespace. Before you
start using Speech Recognition related functionality, you must import these two namespaces in your
application:

using System.Speech;
using System.Speech.Recognition;

SpeechRecognizer
The SpeechRecognizer is the main component of the Speech Recognition API. The SpeechRecognition
class listens and catches the spoken text from the system and converts it to text or text commands.

protected SpeechRecognizer spRecognizer = new SpeechRecognizer();

Enabling SpeechRecognizer
The State property returns the current state of SpeechRecognizer that can either be in Stopped or
Listening. The Enabled property controls if the SpeechRecognizer is enabled and ready to listen or not.
Listing 11 enables SpeechRecognizer by setting Enabled property to true.

SpeechRecognizer spRecognizer = new SpeechRecognizer();

597 @ C# Corner
spRecognizer.Enabled = true;

Listing 11

Reading Text
The SpeechRecognized event of SpeechRecognizer is raised when the recognition engine detects speech,
and has found one or more phrases with sufficient confidence levels. This event is used to get the
speech that is detected by the speech engine.

The code snippet in Listing 12 sets the SpeechRecognized event handler and gets the text recognized by
the speech engine and copies it in a string.

SpeechRecognizer spRecognizer = new SpeechRecognizer();


spRecognizer.Enabled = true;
spRecognizer.SpeechRecognized += new
EventHandler<SpeechRecognizedEventArgs>(spRecognizer_SpeechRecognized);

void spRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs


e)
{
string str = e.Result.Text;
}

Listing 12

Grammar and GrammarBuilder


One of the key usages of speech-enabled applications is to build a software product that listens to your
commands and executes functionality based on the given commands. For example, instead of using
menu items to open and close files, we can build a system that will open and close a file when speech
commands Open File and Close File are sent to the speech system. The Grammar object of
SpeechRecognizer handles these commands and the Grammar class is used to create a Grammar
component.

The Grammar object in WPF represents a grammar document. The Grammar object fully supports the
W3C Speech Recognition Grammar Specification (SRGS) and Context Free Grammar (CFG) specifications.
You create a Grammar object by passing a GrammarBuilder object as a parameter in its constructor.
Listing 13 creates a Grammar object by passing a Grammar Builder object as the default parameter of its
constructor.

GrammarBuilder gBuilder = new GrammarBuilder();


// Construct GrammarBuilder here

// Create a Grammar from a GrammarBuilder


Grammar speechGrammar = new Grammar(gBuilder);

Listing 13

598 @ C# Corner
A GrammarBuilder object is used to provide a simple mechanism to build speech grammar. Add and
Append methods of GrammarBuilder are used to add and append speech text, phrases and other
GrammarBuilder objects to a grammar.

The methods of GrammarBuilder take parameters of either string or Choices object. The Choices object
represents a list of alternative items to make up an element in a speech grammar.

The code snippet in Listing 14 creates a Grammar Builder using some Choices objects and then builds a
Grammar object that can be loaded into a SpeechRecognizer.

private Grammar CreateGrammarDocument()


{
GrammarBuilder gBuilder = new GrammarBuilder();
// Construct GrammarBuilder here
gBuilder.Append(new Choices("Phone", "Email", "Text"));
gBuilder.Append("my");
gBuilder.Append(new Choices("Mom", "Dad", "Brother", "Sister"));

// Create a Grammar from a GrammarBuilder


Grammar speechGrammar = new Grammar(gBuilder);
return speechGrammar;
}

Listing 14

Here is a list of a few sentences that can be constructed using Listing 14.

● Phone my Mom
● Text my Brother
● Email my Mom
● Phone my Brother
● Email my Dad

Loading and Unloading Grammar


The LoadGrammar method of SpeechRecognizer synchronously loads a specific grammar into a
SpeechRecognizer. The code snippet in Listing 15 calls the LoadGrammar method and loads a grammar.

SpeechRecognizer spRecognizer = new SpeechRecognizer();


spRecognizer.LoadGrammar(CreateGrammarDocument());

Listing 15

The LoadGrammarSync method of SpeechRecognizer asynchronously loads a specific grammar into a


SpeechRecognizer. The code snippet in Listing 16 calls LoadGrammarAsync method and loads a
grammar.

SpeechRecognizer spRecognizer = new SpeechRecognizer();


spRecognizer.LoadGrammarAsync(CreateGrammarDocument());

599 @ C# Corner
Listing 16

The UnloadGrammar method unloads a given Grammar and UnloadAllGrammars method unloads all
grammars in a SpeechRecognizer object. The code snippet in Listing 17 shows how to upload grammars
using UnloadGrammar and UnloadAllGrammars methods.

spRecognizer.UnloadGrammar(g);
spRecognizer.UnloadAllGrammars();

Listing 17

SRGS
Speech Recognition Grammar Specification (SRGS) is a W3C recommendation to build grammar that is
used in speech enabled applications. More details about SRGS can be found at
http://www.w3.org/TR/speech-grammar/.

The System.Speech.Recognition.SrgsGrammar namespace defines all functionality related to SRGS. The


SrgsDocument class represents a SRGS document. The namespace also has classes for grammar objects
such as SrgsElement, SgrsItem, SrgsOneOf, SrgsRule, SrgsText, SrgsToken and so on. In WPF, each object
has its own class. Discussion of these classes in detail is out of scope of this chapter.

The following code snippet creates a Rule and sets its scope.

SrgsRule rootRule = new SrgsRule("Months and Days");


rootRule.Scope = SrgsRuleScope.Public;

The following code snippet adds an element to a Rule.

rootRule.Elements.Add(new SrgsItem("Months and Days Grammar "));

And the following code snippet adds a rule to a document.

SrgsText textItem = new SrgsText("Start of the Document.");


SrgsRule textRule = new SrgsRule("TextItem");
textRule.Elements.Add(textItem);
document.Rules.Add(textRule);
Listing 18

Listing 19 creates a complete SRGS document dynamically and saves this document in an XML file. As
you can see from the following code snippet, the code adds rules for months and days of week and
some extra items as rules.

private SrgsDocument BuildDynamicSRGSDocument()


{
// Create SrgsDocume=
SrgsDocument document = new SrgsDocument();

600 @ C# Corner
// Create Root Rule
SrgsRule rootRule = new SrgsRule("MonthsandDays");
rootRule.Scope = SrgsRuleScope.Public;

rootRule.Elements.Add(new SrgsItem("Months and Days Grammar "));

// Create months
SrgsOneOf oneOfMonths = new SrgsOneOf(
new SrgsItem("January"),
new SrgsItem("February"),
new SrgsItem("March"),
new SrgsItem("April"),
new SrgsItem("May"),
new SrgsItem("June"),
new SrgsItem("July"),
new SrgsItem("August"),
new SrgsItem("September"),
new SrgsItem("October"),
new SrgsItem("November"),
new SrgsItem("December")
);
SrgsRule ruleMonths = new SrgsRule("Months", oneOfMonths);
SrgsItem of = new SrgsItem("of");
SrgsItem year = new SrgsItem("year");
SrgsItem ruleMonthsItem = new SrgsItem(new SrgsRuleRef(ruleMonths), of,
year);

// Create Days
SrgsOneOf oneOfDays = new SrgsOneOf(
new SrgsItem("Monday"),
new SrgsItem("Tuesday"),
new SrgsItem("Wednesday"),
new SrgsItem("Thursday"),
new SrgsItem("Friday"),
new SrgsItem("Saturday"),
new SrgsItem("Sunday")
);
SrgsRule ruleDays = new SrgsRule("Days", oneOfDays);
SrgsItem week = new SrgsItem("week");
SrgsItem ruleDaysItem = new SrgsItem(new SrgsRuleRef(ruleDays), of,
week);

// Add items to root Rule


rootRule.Elements.Add(ruleMonthsItem);
rootRule.Elements.Add(ruleDaysItem);

// Add all Rules to Document


document.Rules.Add(rootRule, ruleMonths, ruleDays);
// Add some extra sperate Rules
SrgsText textItem = new SrgsText("Start of the Document.");
SrgsRule textRule = new SrgsRule("TextItem");
textRule.Elements.Add(textItem);
document.Rules.Add(textRule);

SrgsItem stringItem = new SrgsItem("Item as String.");

601 @ C# Corner
SrgsRule itemRule = new SrgsRule("ItemRule");
itemRule.Elements.Add(stringItem);
document.Rules.Add(itemRule);

SrgsItem elementItem = new SrgsItem();


SrgsRule elementRule = new SrgsRule("ElementRule");
elementRule.Elements.Add(elementItem);
document.Rules.Add(elementRule);

// Set Document Root


document.Root = rootRule;

// Save Created SRGS Document to XML file


XmlWriter writer = XmlWriter.Create("DynamicSRGSDocument.Xml");
document.WriteSrgs(writer);
writer.Close();

return document;
}

Listing 19

The document generated by code Listing 16 looks like Figure 8.

Figure 11

We can load a SRGS document as a parameter in the Grammar constructor to create a grammar from a
SrgsDocument. The code snippet in Listing 20 loads a SRGS Grammar document by calling
SpeechRecognizer’s LoadGrammar.

602 @ C# Corner
SpeechRecognizer spRecognizer = new SpeechRecognizer();
spRecognizer.LoadGrammar(new Grammar(BuildDynamicSRGSDocument()));

Listing 20

Summary
Speech API (SAPI) is a managed API that comes with Windows OS. This chapter demonstrated how we
can use SAPI in a WPF application to build speech-enabled applications. First part of this chapter we
covered the text-to-speech (TTS) or Speech Synthesis where we built an application that converts
text to speech. The second part of the chapter we discussed speech recognition where we built an
application that captures the speech from a voice device and converts it to text. We also saw how to
build speech grammars and use these grammars in speech-enabled applications.

603 @ C# Corner
Chapter 11: Documents and Typography in WPF
WPF divides documents in two categories – Fixed documents and flow documents. A fixed document is
used to represent static contents where we already know the layout and format of the contents and it
will never change. Desktop publishing, word processing, and form layouts are some of the examples of
fixed documents where layout and positions of documents never changes. Fixed documents retain the
same position and size no matter what device you used to view or print them.

On the other hand, a flow document is used to represent content where there is no predefined layout or
format, and it changes dynamically depending on the size of the window or monitor resolution. Flow
documents contents are optimized for the device that is being used to view or print them.

WPF Documents functionality is defined in the System.Windows.Documents namespace. Figure 1 shows


the classes defined in this namespace.

604 @ C# Corner
Figure 1

TextElement and TextElementCollection


TextElement and TextElementCollection are the most important elements when working with Flow
Documents in WPF. These elements and their relative classes are the base classes for flow document
elements and flow document element collections.

In this section, we will look at TextElement and TextElementCollection classes, their purpose, and their
members.

TextElement
TextElement is an abstract class and most of the flow contents classes are derived from it. As you can
see from Figure 1, all Block, Table, and Inline related classes are inherited from TextElement.

Table 1 summarizes TextElement class properties.

Property Name Description


ContentStart Gets a TextPointer that represents the start of content in a FlowDocument.
ContentEnd Gets a TextPointer that represents the end of content in a FlowDocument.
FontFamily, FontSize, FontStretch, Font family name, size, stretch, style, and weight of a FlowDocument
FontStyle, FontWeight contents.
Foreground, Background Foreground and background of a FlowDocument.
TextEffects Gets or sets the effects to apply to the text of a FlowDocument.
Gets the currently effective typography variations for the text contents of the
Typography
FlowDocument.

605 @ C# Corner
Table 1

TextElementCollection
BlockCollection, InlineCollection, and ListItemCollection classes are derived from TextElementCollection.

Table 2 summarizes TextElementCollection class methods.

Method Name Description


Add Appends an item to the collection.
AddRange Appends a range of items to the collection.
Aggregate
All
Any
AsQueryable
Average
Clear Clears all items from the collection.
Contains Queries collection for an intem.
Copies the contents of a collection and inserts them into a specified array at a
CopyTo
specified index position of the array.
Count Number of elements in a collection.
DefaultIfEmpty
Distinct
Except
First
FirstOrDefault
GetEnumerator Returns an enumerator for the contents of the collection.
InsertAfter Inserts an item to the collection after a specified item.
InsertBefore Inserts an item to the collection before a specified item.
Intersect
Last
LastOrDefault
LongCount
Max
Min
Remove Removes a specified item from the collection.
SkipWhile
Sum
TakeWhile
Union
Where
Table 2

606 @ C# Corner
Block and BlockCollection
Block is an abstract class for all block-level flow content elements. Figure 1 shows BlockUIContainer, List,
Paragraph, Section, and Table are inherited from the Block class.

Table 3 summarizes Block class properties.

Property Name Description


BorderBrush Border brush
BorderThickness Border thickness
BreakColumnBefore Insert column break before contents
BreakPageBefore Insert page break before contents
ClearFloaters Direction in which floater elements contained
FlowDirection Direction of contents
IsHypernationEnabled Automatic hypernation of words is enabled or not.
LineHeight Height of line
LineStackingStrategy How a line box is determined for each line of text within the block-level flow
content element.
Margin Margin thickness
NextBlock Next sibling block
Padding Padding thickness
PreviousBlock Previous block
SiblingBlocks All sibling blocks
TextAlignment
Table 3

The code listed in Listing 1 creates a Paragraph and sets its properties.

<Grid>
<FlowDocumentReader>
<FlowDocument Name="FlowDocumentExample" FontFamily="Georgia">
<Paragraph
Background="#041C32"
BorderBrush="#516BEB"
BorderThickness ="2"
FlowDirection="LeftToRight"
FontSize="20"
Foreground="#95D1CC"
IsHyphenationEnabled="True"
LineHeight="30"
Margin="22"
Padding="5"
TextAlignment="Center"
TextIndent="10">
Block and BlockCollection Sample
</Paragraph>
<Paragraph>
This example shows how to use Block and BlockCollection methods and
properties.First we discuss how to set properties in XAML at design time and then later
we will see how to use some of these at run-time in code behind.
</Paragraph>
</FlowDocument>
</FlowDocumentReader>

607 @ C# Corner
</Grid>

Listing 1

The output of Listing looks like Figure 2.

Figure 2

Inline and InlineCollection


A flow document is used to represent contents that are not fixed in size such as window size and device
resolution.

Flow Document
A flow document is used to represent contents that are not fixed in size such as window size and device
resolution.

The FlowDocument class in WPF represents a flow document.

The FlowDocument element in XAML is used to create a flow document. The following code snippet
creates a flow document in XAML.

608 @ C# Corner
<FlowDocument/>

FlowDocument Properties
Table summarizes FlowDocument properties.

Property Name Description


Blocks Gets the top-level Blocks of the contents of FlowDocument.
ColumnGap Gets or sets the spacing between columns in a FlowDocument.
ColumnRuleBrush Gets or sets the Brush that s used to draw the rule between columns.
ColumnRuleWidth Gets or sets the column rule width.
ColumnWidth Gets or sets the minimum column width.
ContentStart Gets a TextPointer that represents the start of content in a FlowDocument.
ContentEnd Gets a TextPointer that represents the end of content in a FlowDocument.
FlowDirection Gets or sets the direction of flow of content.
FontFamily, FontSize, FontStretch, Font family name, size, stretch, style, and weight of a FlowDocument
FontStyle, FontWeight contents.
Foreground, Background Foreground and background of a FlowDocument.
IsColumnWidthFlexible Gets or sets if column width is fixed or flexible.
IsHypernationEnabled Gets or sets a value that indicates whether automatic hyphenation of words is
enabled.
IsOptimalParagraphEnabled Gets or sets a value that indicates whether optimal paragraph layout is enabled.
LineHeight Gets or sets the height of each line of content.
Gets or sets the mechanism by which a line box is determined for each line of text
LineStackingStrategy
within the FlowDocument.
MaxPageHeight Gets or sets the maximum height for pages in a FlowDocument.
MaxPageWidth Gets or sets the maximum width for pages in a FlowDocument.
MinPageHeight Gets or sets the minimum height for pages in a FlowDocument.
MinPageWidth Gets or sets the minimum width for pages in a FlowDocument.
PageHeight Gets or sets the preferred height for pages in a FlowDocument.
Gets or sets a value that indicates the thickness of padding space between the
PagePadding
boundaries of a page and the page's content.
PageWidth Gets or sets the preferred width for pages in a FlowDocument.
TextAlignment Gets or sets a value that indicates the horizontal alignment of text content.
TextEffects Gets or sets the effects to apply to the text of a FlowDocument.
Gets the currently effective typography variations for the text contents of the
Typography
FlowDocument.
Table 4

Blocks property represents a BlockCollection that is the top-level child elements of a FlowDocument.
These child elements can be one or more of the following:

● BlockUIContainer
● List
● Paragraph
● Section
● Table

A BlockCollection is a collection of Block elements.

609 @ C# Corner
Block class, which is an abstract base class, represents a Block element. All top-level Block elements are
derived from the Block class.

Block class has three properties – NextBlock, PreviousBlock, and SiblingBlock that represent next,
previous, and sibling blocks of respectively. These properties are useful when navigating through the
blocks in a FlowDocument.

BlockUIContainer
You cannot place a UIElement control (for example a Button control) in a FlowDocument directly.
BlockUIContainer element is used to place a UIElement in a FlowDocument.

Following code snippet places a Button control as contents of a FlowDocument.

<FlowDocument Name="FlowDocumentExampleTwo" FontFamily="Georgia" >


<BlockUIContainer>
<Button
Background="#8E806A"
BorderBrush="#064663"
Content="Block UI Container"
Foreground="#22577E"
Height="30"
Width="200" />
</BlockUIContainer>
</FlowDocument>

Listing 2

If you run the app with listing 2 you’d get an output as shown in figure 3.

Figure 3

Now, the Button control placed within a FlowDocument content acts like any other WPF button. That
means, you can place a button click event handler and can execute desired code on the click event.

Listing 3 is a complete example where a Button is placed within a FlowDocument contents.

<FlowDocument Name="FlowDocumentExampleTwo" FontFamily="Georgia" >


<Paragraph
Background="#FBFBFB"
FontSize="20"
Foreground="#064663"

610 @ C# Corner
TextAlignment="Center"
TextIndent="10">
<Underline>
C# Corner
</Underline>
</Paragraph>

<BlockUIContainer>
<Button
Background="#95D1CC"
BorderBrush="#064663"
Content="About us!"
Foreground="#041C32"
Height="30"
Width="200" />
</BlockUIContainer>
<Paragraph>
C# Corner, headquartered in Philadelphia, PA, is an online global community
of 3 million software developers. C# Corner serves 5+ million visitors with 9 million
page views each month.
<Bold>We publish the latest news and articles on cutting-edge software
development topics.</Bold>
<LineBreak />
<LineBreak />
Developers share their knowledge and connect via content, forums, and
chapters. Thousands of members benefit from our monthly events, webinars, and
conferences.
<LineBreak />
<LineBreak/>
We also provide tools for career growth such as career advice, resume
writing, training, certifications, books and whitepapers, and videos.
<Bold>We also connect developers with their potential employers via our Job
board.</Bold>
<LineBreak/>
</Paragraph>
</FlowDocument>

Listing 3

The output looks like Figure 4.

611 @ C# Corner
Figure 4

Dynamic BlockUIContainer
ListItems property represents a collection of list items.

List
List is used to add bulleted or numbered items in a FlowDocument. The List with its two supporting
classes - ListItem and ListItemCollection, are used to add lists to a FlowDocument.

Following code snippet creates a List and adds a list item to it.
<List Name="FlowList" Foreground="Orange">
<ListItem>
<Paragraph>C# Corner</Paragraph>
</ListItem>
</List>

Now, both List and ListItem elements work as any other XAML and WPF control and you have control
over their formatting, events, and other functionality.

Listing 4 shows a List added to a FlowDocument with a few list items formatted in different ways.
<FlowDocument x:Name="FlowDocumentListExample"

612 @ C# Corner
Background="GhostWhite">
<List Name="FlowList" Foreground="Orange">
<ListItem Margin="5">
<Paragraph Background="#FAEDF0"
Foreground="#064663">
Colosseum, Italy
</Paragraph>
</ListItem>
<ListItem Background="#B8E4F0"
Foreground="#161853"
Margin="5">
<Paragraph>
Taj Mahal, India
</Paragraph>
</ListItem>
<ListItem Background="#FAEDF0"
Foreground="Red"
Margin="5">
<Paragraph>
Petra, Jordan
</Paragraph>
</ListItem>

<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="Green">
Christ The Redeemer, Brazil
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#FAEDF0"
Foreground="Brown">
Chichén Itza, Mexico
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="Purple">
The Great Wall of China, China
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#FAEDF0"
Foreground="#160040">
Machu Picchu
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="#113CFC">
The Great Pyramid of Giza, Egypt
</Paragraph>
</ListItem>

613 @ C# Corner
</List>
</FlowDocument>

Listing 4

The output of Listing 4 looks like Figure 5.

Figure 5

List Properties
ListItems property represents a collection of list items.

MarkerOffset property gets or sets the distance between the continents of each ListItem element and
the near edge of the list market. Value of MarkerOffset is double.

MarkerStyle property gets or sets the style of the market which is a type of TextMarkerStyle. The value
of MarkerStyle can be one of the following:

● None
● Disc
● Circle
● Square
● Box
● LowerRoman
● UpperRoman

614 @ C# Corner
● LowerLatin
● UpperLatin
● Decimal

StartIndex gets or sets the starting index for labeling the items in an ordered list. The default value is 1.

Here is an example of nested lists that use these properties.


<FlowDocument x:Name="FlowDocumentListExample"
Background="GhostWhite">
<List Name="FlowList" Foreground="Orange">
<ListItem Margin="5">
<Paragraph >Wonders of the world</Paragraph>
<List Margin="20"
Padding="0"
FontSize="12"
MarkerOffset="10"
MarkerStyle="Square"
FontFamily="Georgia">
<ListItem Margin="5">
<Paragraph Background="#FAEDF0"
Foreground="#064663">
Colosseum, Italy
</Paragraph>
</ListItem>
<ListItem Background="#B8E4F0"
Foreground="#161853"
Margin="5">
<Paragraph>
Taj Mahal, India
</Paragraph>
</ListItem>
<ListItem Background="#FAEDF0"
Foreground="Red"
Margin="5">
<Paragraph>
Petra, Jordan
</Paragraph>
</ListItem>

<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="Green">
Christ The Redeemer, Brazil
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#FAEDF0"
Foreground="Brown">
Chichén Itza, Mexico
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph

615 @ C# Corner
Background="#B8E4F0"
Foreground="Purple">
The Great Wall of China, China
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#FAEDF0"
Foreground="#160040">
Machu Picchu
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="#113CFC">
The Great Pyramid of Giza, Egypt
</Paragraph>
</ListItem>
</List>
</ListItem>

<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="Purple">
List Item 2
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#FAEDF0"
Foreground="#160040">
List Item 3
</Paragraph>
</ListItem>
<ListItem Margin="5">
<Paragraph
Background="#B8E4F0"
Foreground="#113CFC">
List Item 4
</Paragraph>
</ListItem>
</List>
</FlowDocument>

Listing 5

The output of Listing 5 looks like Figure 6.

616 @ C# Corner
Figure 6

Dynamic List
ListItems property represents a collection of list items.

Paragraph
Paragraph is a group of contents like a paragraph in a document. Paragraph class in WPF represents a
paragraph of a FlowDocument.

The Paragraph element in XAML represents a paragraph. The following code snippet creates a
Paragraph.
<Paragraph> Inline elements here </Paragraph>

617 @ C# Corner
Similar to other XAML elements, a Paragraph has most of the common properties such as Name, Font
related properties, Foreground and Background. The following code snippet sets a few properties of a
Paragraph.
<Paragraph FontSize="20" Foreground="DarkGreen" Background="LightGray"
TextIndent="10">
<Underline>
Flow Document Elements
</Underline>
</Paragraph>

A Paragraph can host other nested paragraphs. Besides that, a Paragraph can host the following inline
elements.

● Bold
● Figure
● Floater
● Hyperlink
● InlineUIContainer
● Italic
● LineBreak
● Run
● Span
● Underline
Listing 6 is a complete example that shows how to use some of the Inlines in a Paragraph.

<FlowDocument Name="FlDoc" FontFamily="Georgia" >


<Paragraph
Background="#FBFBFB"
FontSize="20"
Foreground="#064663"
TextAlignment="Center"
TextIndent="10">
<Underline>
C# Corner
</Underline>
</Paragraph>

<BlockUIContainer>
<Button
Background="#95D1CC"
BorderBrush="#064663"
Content="About us!"
Foreground="#041C32"

618 @ C# Corner
Height="30"
Width="200" />
</BlockUIContainer>

<Paragraph>
C# Corner, headquartered in Philadelphia, PA, is an online global community
of 3 million software developers. C# Corner serves 5+ million visitors with 9 million
page views each month.
<Bold>We publish the latest news and articles on cutting-edge software
development topics.</Bold>
<LineBreak />
<LineBreak />
Developers share their knowledge and connect via content, forums, and
chapters. Thousands of members benefit from our monthly events, webinars, and
conferences.
<LineBreak />
<LineBreak/>
We also provide tools for career growth such as career advice, resume
writing, training, certifications, books and whitepapers, and videos.
<Bold>We also connect developers with their potential employers via our Job
board.</Bold>
<LineBreak/>
</Paragraph>

<Paragraph FontSize="16" Foreground="#344CB7" >


<Bold>
Mindcracker Network - List Example
</Bold>
</Paragraph>

<List Name="FlowList" Foreground="#0F2C67">


<ListItem>
<Paragraph>C# Corner</Paragraph>
</ListItem>
<ListItem>
<Paragraph>VB.NET Heaven</Paragraph>
</ListItem>
<ListItem>
<Paragraph>.NET Heaven</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Longhorn Corner</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Mindcracker</Paragraph>
</ListItem>
</List>

<Paragraph>
<Span Foreground="#F90716">Span element</Span>
</Paragraph>

<Paragraph>
<Run Foreground="#D06224">Run element</Run>
</Paragraph>
<Paragraph Foreground="#FF5403" FontSize="15">Subscript, Superscript</Paragraph>

619 @ C# Corner
<Paragraph>
<Run Foreground="#AE431E"
Typography.Variants="Superscript">superscripted.</Run>
</Paragraph>
<Paragraph>
<Run Foreground="#F3950D" Typography.Variants="Subscript">subscripted.</Run>
</Paragraph>
<Paragraph Foreground="#753188" FontSize="15" TextAlignment="Center">Blocks,
breaks, paragraph</Paragraph>

<Section />
<Section Foreground="#A9333A">
<Paragraph >this text is preceded by a page break.</Paragraph>
</Section>

<Paragraph Foreground="#FF0075">Text Indent Sample..</Paragraph>


<Paragraph TextIndent="50" Background="#F3F1F5"
Foreground="#3DB2FF">left indentation</Paragraph>

<Paragraph>
<LineBreak/>
</Paragraph>
</FlowDocument>

Listing 6

The output of Listing 6 looks like Figure 7.

620 @ C# Corner
Figure 7

Paragraph Properties
Inlines property represents a collection of Inline items at the top-level of a Paragraph.

The KeepTogether property represents whether the text of the paragraph may be broken by a page
break or column break. The default value of KeepTogether is false. Set this value to true to prevent it
from being broken.

The KeepWithNext property represents whether a break may occur between this paragraph and the
next paragraph. The default value of KeepWithNext is false. Set this value to true to prevent a break
from occurring between this paragraph and the next paragraph.

MinOrphanLines property represents an integer value that specifies the minimum number of lines that
can be left before the break when a Paragraph is broken by a page break or column break. The default
value is 0.

MinWindowLines property represents an integer value that specifies the minimum number of lines that
can be placed after the break when a Paragraph is broken by a page break or column break.

621 @ C# Corner
TextDecorations property represents a TextDecorationCollection that contains text decorations to apply
to a Paragraph. There are four types of text decorations: underline, baseline, strikethrough, and
overline.

TextIndent property represents a double value that indicates how far to indent the first line of a
Paragraph. The default value is 0. Using this property, you can specify indentation in pixel, inch,
centimeter, and point units. Pixel, inch, centimeter, and point are represented by prefixes px, in, cm, and
pt respectively.

The code listed in Listing 7 shows how to set these properties in XAML at design-time.

<Paragraph x:Name="ParagraphExample"
Background="LightGray"
FontSize="20"
Foreground="DarkGreen"
KeepTogether="True"
KeepWithNext="false"
MinOrphanLines="2"
MinWidowLines="1"
TextDecorations="strikethrough"
TextIndent="2cm"/>

Listing 7

The code listed in Listing 8 shows how to set these properties in code-behind at run-time.
Paragraph p1 = new Paragraph();
p1.KeepTogether = true;
p1.KeepWithNext = false;
p1.MinOrphanLines = 0;
p1.MinWidowLines = 1;
p1.TextDecorations = TextDecorations.Strikethrough;
p1.TextIndent = 2;

Listing 8

Dynamic Paragraph
The Paragraph class in WPF represents a paragraph. The code snippet in Listing 9 creates a Paragraph
dynamically and adds its items using Inlines property.
// Create first Paragraph
Paragraph p1 = new Paragraph();
// Create and add a new Bold, Italic and Underline
Bold bld = new Bold();
bld.Inlines.Add(new Run("First Paragraph"));
Italic italicBld = new Italic();
italicBld.Inlines.Add(bld);
Underline underlineItalicBld = new Underline();
underlineItalicBld.Inlines.Add(italicBld);
// Add Bold, Italic, Underline to Paragraph
p1.Inlines.Add(underlineItalicBld);

622 @ C# Corner
Listing 9

Section
A Section is a block-level flow content element used for grouping other Block elements including
BlockUIContainer, List, Paragraph, Section and Table.

The Paragraph element in XAML represents a paragraph. The following code snippet creates a
Paragraph.
<Section > Blocks </ Section>

Similar to other XAML elements, a Section has most of the common properties such as Name, Font
related properties, Foreground and Background. The following code snippet sets a few properties of a
Section.
<Section FontSize="20" Foreground="DarkGreen" Background="LightGray" />

Listing 10 is a complete example of a Section that hosts a Paragraph and another section that hosts a
nested Section.
<FlowDocument x:Name="FlowDocumentExample" FontFamily="Georgia" >
<!-- Section hosting a Paragraph -->
<Section>
<Paragraph FontSize="20" Foreground="#79B4B7" TextIndent="10">
<Underline>
Flow Document Elements
</Underline>
</Paragraph>
</Section>
<!-- Section hosting another Section -->
<Section Foreground="#345B63" >
<Section>
<Paragraph>
C# Corner, headquartered in Philadelphia, PA, is an online global
community of 3 million software developers. C# Corner serves 5+ million visitors with 9
million page views each month.
<Bold>We publish the latest news and articles on cutting-edge
software development topics.</Bold>
<LineBreak />
<LineBreak />
Developers share their knowledge and connect via content, forums, and
chapters. Thousands of members benefit from our monthly events, webinars, and
conferences.
<LineBreak />
<LineBreak/>
We also provide tools for career growth such as career advice, resume
writing, training, certifications, books and whitepapers, and videos.
<Bold>We also connect developers with their potential employers via
our Job board.</Bold>
<LineBreak/>
</Paragraph>
</Section>

623 @ C# Corner
</Section>
</FlowDocument>

Listing 10

The output looks like Figure 8.

Figure 8

Section Properties
Blocks property represents a collection of Block items.

HasTrailingParagraphBreakOnPaste Property represents a boolean value that indicates whether a


trailing paragraph break should be inserted after the last paragraph while placing the contents of a root
Section element on the clipboard. The default value of HasTrailingParagraphBreakOnPaste is false. The
following code snippet sets HasTrailingParagraphBreakOnPaste property to true.
<Section
Background="LightGray"
FontSize="20"
Foreground="DarkGreen"
HasTrailingParagraphBreakOnPaste="True" >

Listing 11

Dynamic Section

624 @ C# Corner
The Section class in WPF represents a section. The code snippet in Listing 12 creates a Section
dynamically and adds its items using Blocks property.
private FlowDocument CreateASectionDynamically()
{
// Create a FlowDocument
FlowDocument doc = new FlowDocument();

// Create a Section
Section sec = new Section();
// Create first Paragraph
Paragraph p1 = new Paragraph();
// Create and add a new Bold, Italic and Underline
Bold bld = new Bold();
bld.Inlines.Add(new Run("First Paragraph"));
Italic italicBld = new Italic();
italicBld.Inlines.Add(bld);
Underline underlineItalicBld = new Underline();
underlineItalicBld.Inlines.Add(italicBld);
// Add Bold, Italic, Underline to Paragraph
p1.Inlines.Add(underlineItalicBld);
// Add Paragraph to Section
sec.Blocks.Add(p1);
// Add Section to FlowDocument
doc.Blocks.Add(sec);
return doc;
}

Listing 12

Table
A Table is a block-level flow content element that provides flat grid-based presentation of data
organized in rows and columns.

The Table element in XAML represents a Table. The following code snippet creates a Table.
<Table> RowGroups </Table>

Similar to other XAML elements, a Table has most of the common properties such as Name, Font related
properties, Foreground and Background. The following code snippet sets a few properties of a Table.

<Table Name="TableExample"
Background="DarkBlue"
Foreground="LemonChiffon"
FontFamily="Calibri"
FontSize="12"
FontStyle="Normal"
FontStretch="SemiCondensed"

625 @ C# Corner
FontWeight="Thin"/>
Listing 13

A Table can have the following elements as child elements.

● FlowDocument

● TableCell

● ListBoxItem

● ListViewItem

● Section

● Floater

● Figure

In this section, you will see some of these elements in action.


Listing 14 is a complete example that uses CellSpacing, Columns, and TableRowGroup to build a table.
Table.Columns is used to specify the number of columns in a Table. TableRow is used to add a row to a
TableRowGroup. TableCell represents a cell of a row.

<FlowDocumentReader>
<FlowDocument>
<Table Name="TableExample" CellSpacing="5">
<Table.Columns>
<TableColumn/>
<TableColumn/>
<TableColumn/>
<TableColumn/>
</Table.Columns>

<TableRowGroup>
<TableRow Background="#577BC1">
<TableCell ColumnSpan="4"
TextAlignment="Center">
<Paragraph
FontSize="18pt"
FontWeight="Bold"
FontFamily="Calibri" >
Monthly Mindcracker Statistics
</Paragraph>
</TableCell>
</TableRow>

<TableRow Background="#5584AC"
FontSize="14pt"
FontWeight="Bold" >
<TableCell>
<Paragraph>Site</Paragraph>
</TableCell>

626 @ C# Corner
<TableCell>
<Paragraph>Users</Paragraph>
</TableCell>
<TableCell>
<Paragraph>Page Views</Paragraph>
</TableCell>
<TableCell>
<Paragraph>Unique</Paragraph>
</TableCell>
</TableRow>

<TableRow Background="#98BAE7" FontSize="11pt" >


<TableCell>
<Paragraph>C# Corner</Paragraph>
</TableCell>
<TableCell>
<Paragraph>2,109,330</Paragraph>
</TableCell>
<TableCell>
<Paragraph>3,224,951</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1,654,009</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="#B8E4F0" FontSize="11pt">
<TableCell>
<Paragraph>.NET Heaven</Paragraph>
</TableCell>
<TableCell>
<Paragraph>267,280</Paragraph>
</TableCell>
<TableCell>
<Paragraph>436,090</Paragraph>
</TableCell>
<TableCell>
<Paragraph>189,675</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="#98BAE7" FontSize="11pt">
<TableCell>
<Paragraph>VB.NET Heaven</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1,224,884</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1,822,228</Paragraph>
</TableCell>
<TableCell>
<Paragraph>944,233</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="#B8E4F0">
<TableCell>
<Paragraph>Longhorn Corner</Paragraph>
</TableCell>
<TableCell>

627 @ C# Corner
<Paragraph>435,009</Paragraph>
</TableCell>
<TableCell>
<Paragraph>744,557</Paragraph>
</TableCell>
<TableCell>
<Paragraph>238,112</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="#292C6D"
Foreground="White"
FontSize="16" >
<TableCell>
<Paragraph>Total:</Paragraph>
</TableCell>
<TableCell>
<Paragraph>4,036,503</Paragraph>
</TableCell>
<TableCell>
<Paragraph>6,227,826</Paragraph>
</TableCell>
<TableCell>
<Paragraph>3,026,029</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>
</FlowDocumentReader>

Listing 14

The output looks like Figure 9.

Figure 9

628 @ C# Corner
Table Properties
CellSpacing property represents the amount of space between cells.

Columns property represents a collection of columns available in a Table.

RowGroups property represents a collection of TableRowGroup in a Table.

Dynamic Table
The Section class in WPF represents a section. The code snippet in Listing 15 creates a Section
dynamically and adds its items using Blocks property.
private FlowDocument CreateDynamicTable()
{
// Create a FlowDocument
FlowDocument doc = new FlowDocument();
// Create a Table and set CellSpacing
Table tbl = new Table();
tbl.CellSpacing = 5;
// Add 4 columns to Table
TableColumn col1 = new TableColumn();
col1.Background = Brushes.Beige;
tbl.Columns.Add(col1);
TableColumn col2 = new TableColumn();
col1.Background = Brushes.Azure;
tbl.Columns.Add(col2);
TableColumn col3 = new TableColumn();
col1.Background = Brushes.Beige;
tbl.Columns.Add(col3);
TableColumn col4 = new TableColumn();
col1.Background = Brushes.Azure;
tbl.Columns.Add(col4);
// Add a TableRowGroup
tbl.RowGroups.Add(new TableRowGroup());
// Add the first title row.
TableRow titleRow = new TableRow();
titleRow.Background = Brushes.LightGray;

// Create a Paragraph that will be added to the row


Paragraph p = new Paragraph(new Run("Monthly Mindcracker Statistics"));
p.FontSize = 22;
p.FontWeight = FontWeights.Bold;
p.FontFamily = new FontFamily("Calibri");
// Create a Table Cell
TableCell c = new TableCell(p);
c.ColumnSpan = 4;
titleRow.Cells.Add(c);
tbl.RowGroups[0].Rows.Add(titleRow);
// Add Header Row
tbl.RowGroups[0].Rows.Add(new TableRow());

629 @ C# Corner
TableRow currentRow = tbl.RowGroups[0].Rows[1];
// Global formatting for the header row.
currentRow.FontSize = 18;
currentRow.FontWeight = FontWeights.Bold;
// Add cells with content to the second row.
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Website"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Users"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Page Views"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("Unique Users"))));
// Add First data Row
tbl.RowGroups[0].Rows.Add(new TableRow());
currentRow = tbl.RowGroups[0].Rows[2];
// Global formatting for the header row.
currentRow.FontSize = 14;
// Add cells with content to the second row.
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("C# Corner"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("2,109,330"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("3,224,951"))));
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("1,654,009"))));
doc.Blocks.Add(tbl);
return doc;
}

Listing 15

Creating a FlowDocument
The FlowDocument element in XAML is used to create a FlowDocument at design-time. A
FlowDocument can have one or more of the following elements as first child elements. We have seen
how to use these elements within a FlowDocument in our previous discussions.

The code listed in Listing 16 creates a FlowDocument and adds Paragraph, List, Section and other
elements to a FlowDocument.

FlowDocument class in WPF is used to create a FlowDocument at run-time in code-behind. The code
listed in Listing creates a FlowDocument at run-time and adds Paragraph, List, Section and other

Refer listing 6 for an example.

Viewing FlowDocument
A FlowDocument can be viewed by using following four different controls:

● FlowDocumentScrollViewer
● FlowDocumentPageViewer
● FlowDocumentReader (Refer from controls chapter)

630 @ C# Corner
● RichTextBox

These controls are discussed in more detail later in this chapter.

FlowDocument Controls
A flow document can be presented in different ways depending on the control used to display the
document. The following controls can be used to represent flow documents.

● FlowDocumentScrollViewer
● FlowDocumentPageViewer
● FlowDocumentReader
● RichTextBox

FlowDocumentScrollViewer
FlowDocumentScrollViewer control is used to display document contents in a continuous scrolling
mode. Unlike a FlowDocumentReader that supports various viewing modes, a
FlowDocumentScrollViewer supports only one viewing mode with horizontal and vertical scrollbars. By
default, a vertical scrollbar is visible and horizontal scrollbar is set to auto that is visible only when it is
needed.

The following code snippet creates a FlowDocumentScrollViewer control and sets its Name,
BorderBrush, Width, and Height and adds the FlowDocument as child.

<FlowDocumentScrollViewer
Name="FlowDocumentScrollViewerExample"
BorderBrush="Black">

<FlowDocument
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True">
<Section Name="Heading"
Background="#F7F7F7"
FontFamily="Georgia"
FontSize="20">
<Paragraph>
Learn about Mindcracker Network
</Paragraph>
</Section>
<Section FontSize="12">
<Paragraph>

631 @ C# Corner
<Bold>Mindcracker Network</Bold> including
<Bold>
Corner</Hyperlink> <Hyperlink NavigateUri="http://www.c-sharpcorner.com">C#
</Bold>
is an online community for Software developers and professionals.
Mindcracker Network allows its members to share their knowledge among
one another via its contents publishing including
<Bold>Articles, Blogs, Tutorials, and Videos.</Bold> It also allows
members to ask and reply questions on
<Bold>Mindcracker Forums.</Bold> Mindcracker Forums
has a Cash Reward program where top 10 contributors win $500 cash each
month.

Mindcracker Network also allows software vendors to publish their news,


press,
and product releases
<Bold>News</Bold> section. Software Vendors may also upload
their products to the
<Bold>Downloads</Bold> section for site members to download and
try their products.
<Bold>Photos</Bold> section allows site members to share their photos
with other members.
<Figure
Background="GhostWhite"
Height="50"
HorizontalAnchor="PageLeft"
HorizontalOffset="100"
VerticalOffset="20"
Width="200">
<Paragraph
Background="#EEEBDD"
FontStyle="Italic"
Foreground="#F90716"
TextAlignment="Left">
developers Mindcracker Network was founded in 1999 as a community where
developers. can learn and share their knowledge and ideas with other
</Paragraph>
</Figure>
<Floater
Background="GhostWhite"
HorizontalAlignment="Left"
Width="285">
<Table CellSpacing="5">
<Table.Columns>
<TableColumn Width="155"/>
<TableColumn Width="130"/>
</Table.Columns>

<TableRowGroup>
<TableRow>

632 @ C# Corner
<TableCell
Background="#F3F0D7"
ColumnSpan="3"
FontSize="16" >
<Paragraph>Mindcracker Statistics</Paragraph>
</TableCell>
</TableRow>
<TableRow
Background="#CEE5D0"
FontSize="11">
<TableCell>
views:</Paragraph> <Paragraph FontWeight="Bold">Monthly Page

</TableCell>
<TableCell>
<Paragraph>3.8 Million</Paragraph>
</TableCell>
</TableRow>

<TableRow
Background="LightGray"
Visitors:</Paragraph> FontSize="11">
<TableCell>
<Paragraph FontWeight="Bold">Monthly Unique

</TableCell>
<TableCell>
<Paragraph>2.3 Million</Paragraph>
</TableCell>
</TableRow>
Visitors:</Paragraph>
<TableRow
Background="#CEE5D0"
FontSize="11">
<TableCell>
<Paragraph FontWeight="Bold">US

</TableCell>
<TableCell>
<Paragraph>43%</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="4">
<Paragraph FontSize="10" FontStyle="Italic">
View more details on
<Hyperlink NavigateUri="http://www.c-
sharpcorner.com/forums/">Mindcracker Network.</Hyperlink>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Floater>
</Paragraph>
<Paragraph>

633 @ C# Corner
<Bold>Mindcracker Network</Bold> websites include C# Corner, VB.NET
Heaven, .NET Heaven,
Mindcracker, Interview Corner, and Longhorn Corner.
<Bold>Longhorn Corner</Bold> is the newest member of the community
that is dedicated to
WPF, Silverlight, and XAML developers.
</Paragraph>
<Paragraph>
<Figure
Background="#FEF9EF"
Height="50"
HorizontalAnchor="PageCenter"
TextAlignment="Left"
Width="140"
WrapDirection="Both">
<Paragraph
Background="#FEF5ED"
FontStyle="Italic"
Foreground="#AA14F0" >
Longhorn Corner is the newest member of Mindcracker Network.
</Paragraph>
</Figure>
Mindcracker Network was founded by developers who believe in sharing
their knowledge
and expertise with fellow developers and also believe that knowledge
should be
available free. Today, Mindcracker is joined by over 1 million registered
members worldwide
and growing fast.
</Paragraph>
</Section>
</FlowDocument>
</FlowDocumentScrollViewer> Listing 16

The output of Listing looks like Figure 10.

634 @ C# Corner
Figure 10

FlowDocumentPageViewer
FlowDocumentPageViewer control is used to display document contents in a paging mode where
contents are broken down in the pages. FlowDocumentScrollViewer provides a number of pages with
previous and next navigation options and a zoom in and zoom out control.

Figure 11 and 12 shows a document with 2 pages.

635 @ C# Corner
Figure 11

636 @ C# Corner
Figure 12

The following code snippet in listing 17 creates a FlowDocumentPageViewer control as shown in figure
11 and 12.

<FlowDocumentPageViewer
Name="FlowDocumentPageViewerExample"
BorderBrush="DarkGray"
Height="500"
Width="300" >
<FlowDocument Name="FlowDocumentExample"
FontFamily="Georgia" >
<Paragraph
Background="#FBFBFB"
FontSize="20"
Foreground="#064663"
TextAlignment="Center"
TextIndent="10">
<Underline>
C# Corner
</Underline>
</Paragraph>
<BlockUIContainer>

637 @ C# Corner
<Button
Background="#95D1CC"
BorderBrush="#064663"
Content="About us!"
Foreground="#041C32"
Height="30"
Width="200" />
</BlockUIContainer>
<Paragraph>
C# Corner, headquartered in Philadelphia, PA, is an online global
community of 3 million software developers. C# Corner serves 5+ million visitors with 9
million page views each month.
<Bold>We publish the latest news and articles on cutting-edge software
development topics.</Bold>
<LineBreak />
<LineBreak />
Developers share their knowledge and connect via content, forums, and
chapters. Thousands of members benefit from our monthly events, webinars, and
conferences.
<LineBreak />
<LineBreak/>
We also provide tools for career growth such as career advice, resume
writing, training, certifications, books and whitepapers, and videos.
<Bold>We also connect developers with their potential employers via our
Job board.</Bold>
<LineBreak/>
</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
Listing 17

FlowDocumentReader
FlowDocumentReader control is used to view a flow document. FlowDocumentReader provides both
scrolling and paging provided by FlowDocumentScrollViewer and FlowDocumentPageViewer. In addition
to that, it provides search functionality.

A typical FlowDocumentViewer with a document looks like Figure 13.

638 @ C# Corner
Figure 13

A FlowDocumentReader control provides built-in functionality for search, zoom, page navigation, and
viewing modes, refer figure 14.

Figure 14

Find

Click on the Find Button at the left bottom of control as highlighted in figure 15, it will let you enter a
text in the textbox and find it in the document. You will also notice next and previous arrows to move to
the next and previous found matching text found in the document.

639 @ C# Corner
Figure 15

Page Navigation

Page navigation controls are used to navigate from one page to another. In the below Figure 16, you
would notice “2 of 2 pages” and previous and next arrows besides them. Clicking on these arrows will
move to the previous and next pages respectively.

Figure 16

640 @ C# Corner
Viewing Modes

There are three viewing mode buttons – Page Mode, Two Page Mode, and Scroll Mode. In the Page
Mode, you will see one page at a time. In Two Page mode, a document is split into two pages, and in
Scroll Mode, contents are being scrolled on a single page and if there are multiple pages in a document,
you will see a scrollbar in the right side of the document.

The default mode is Page Mode, which shows the entire document in a page by page with a paging
option.

Figure 17

Two Page mode option shows a document in two pages as seen in Figure 18.

641 @ C# Corner
Figure 18

The Scroll mode does not have a paging option but displays the entire document in a single page with a
vertical scrollbar in the right side as seen in Figure 19

Figure 19

642 @ C# Corner
Zoom

The last option you see on the FlowDocumentReader controls is the zoom slider control, which lets you
slide from left to right and vice versa. One zoomed document looks like Figure 20.

Figure 20

The following code snippet creates a FlowDocumentReader control and sets its Name, BorderBrush,
Width, and Height.

<FlowDocumentReader
Name="FlowDocumentPageViewerExample"
BorderBrush="DarkGray"
Height="300"
Width="500" >
<FlowDocument Name="FlowDocumentExample"
FontFamily="Georgia" >
<Paragraph
Background="#FBFBFB"
FontSize="20"
Foreground="#064663"
TextAlignment="Center"
TextIndent="10">
<Underline>
C# Corner
</Underline>
</Paragraph>

<BlockUIContainer>
<Button

643 @ C# Corner
Background="#95D1CC"
BorderBrush="#064663"
Content="About us!"
Foreground="#041C32"
Height="30"
Width="200" />
</BlockUIContainer>

<Paragraph>
C# Corner, headquartered in Philadelphia, PA, is an online global
community of 3 million software developers. C# Corner serves 5+ million visitors with 9
million page views each month.
<Bold>We publish the latest news and articles on cutting-edge software
development topics.</Bold>
<LineBreak />
<LineBreak />
Developers share their knowledge and connect via content, forums, and
chapters. Thousands of members benefit from our monthly events, webinars, and
conferences.
<LineBreak />
<LineBreak/>
We also provide tools for career growth such as career advice, resume
writing, training, certifications, books and whitepapers, and videos.
<Bold>We also connect developers with their potential employers via our
Job board.</Bold>
<LineBreak/>
</Paragraph>
</FlowDocument>
</FlowDocumentReader>
Listing 18

The output of Listing 18 looks like Figure 21.

644 @ C# Corner
Figure 21

RichTextBox
The RichTextBox control allows you to view and edit text, paragraph, images, tables, and other rich text
format contents.

In XAML, The RichTextBox tag is used to represent a RichTextBox control.

<RichTextBox/>

The Width and Height properties represent the width and the height of a RichTextBox. The Name
property represents the name of the control, which is a unique identifier of a control. The Margin
property tells the location of a RichTextBox on the parent control. The HorizontalAlignment and
VerticalAlignment properties are used to set horizontal and vertical alignments.

The following code snippet sets the name, height, and width of a RichTextBox control. The code also
sets horizontal alignment to left and vertical alignment to top.

<RichTextBox x:Name="RichTextBoxExample"
Height="300"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="500" />

Listing 19

645 @ C# Corner
Let’s run the listing 19 to see the output.

Figure 22: Empty RichTextBox

Displaying and Edit Text


A RichTextBox control hosts a collection of RichTextBoxItem. The following code snippet adds items to a
RichTextBox control.

<RichTextBox x:Name="RichTextBoxExample"
Height="300"
HorizontalAlignment="Left"
Margin="10"
VerticalAlignment="Top"
Width="500">
<FlowDocument>
<Paragraph>
This is a flow document. This can be edited!
<Bold>Start writing</Bold>
</Paragraph>

<Paragraph Foreground="Blue">
Your paragraph starts from here.
</Paragraph>
</FlowDocument>
</RichTextBox>

Listing 20

The code in listing 20 generates Figure 23 where you can start editing text right away.

646 @ C# Corner
Figure 23: RichTextBox with editable text

Creating and Using RichTectBox Dynamically


In the previous section, we saw how to create and use RichTextBox in XAML. WPF provides a
RichTextBox class that represents a RichTextBox control. In this section, we will see how to use this class
to create and use a RichTextBox control dynamically.

The code listed in Listing 21 creates a FlowDocument, adds a paragraph to the flow document and sets
the Document property of the RichTextBox as FlowDocument.

private void CreateAndLoadRichTextBox()


{
// Create a FlowDocument
FlowDocument mcFlowDoc = new FlowDocument();

// Create a paragraph with text


Paragraph para = new Paragraph();
para.Inlines.Add(new Run("This is a flow document. This can be
edited!"));
para.Inlines.Add(new Bold(new Run("Start writing.)));

// Add the paragraph to blocks of paragraph


mcFlowDoc.Blocks.Add(para);

// Create RichTextBox, set its hegith and width


RichTextBox mcRTB = new RichTextBox();
mcRTB.Width = 560;
mcRTB.Height = 280;

647 @ C# Corner
// Set contents
mcRTB.Document = mcFlowDoc;

// Add RichTextbox to the container


ContainerPanel.Children.Add(mcRTB);
}

Listing 21

Enable Spelling Check


RichTextBox control comes with spelling check functionality out-of-box. By setting SpellCheck.IsEnabled
property to true enables spell checking in a RichTextBox.

SpellCheck.IsEnabled="True"

Now if you type some text, the misspelled word would be underlined with red color. And if you right
click on the same it will give you possible suggestions. See in Figure 24.

Figure 24. RichTextBox with Spell Check Enabled

Loading a Document in RichTextBox


We can use RichTextBox.Items.Remove or RichTextBox.Items.RemoveAt method to delete an item from
the collection of items in the RichTextBox. The RemoveAt method takes the index of the item in the
collection.

648 @ C# Corner
Now, we modify our application and add a new button called Delete Item. The XAML code for this
Button looks like below.

private void OpenMenuItem_Click(object sender, RoutedEventArgs e)


{
OpenFileDialog dlg = new OpenFileDialog();
dlg.InitialDirectory = "c:\\";
dlg.Filter = "Text files (*.txt)|*.txt|All Files (*.*)|*.*";
dlg.RestoreDirectory = true;
LoadTextDocument(dlg.FileName);
}

private void LoadTextDocument(string fileName)


{
TextRange range;
System.IO.FileStream fStream;
if (System.IO.File.Exists(fileName))
{
range = new
TextRange(RichTextBoxExample.Document.ContentStart,
RichTextBoxExample.Document.ContentEnd);
fStream = new System.IO.FileStream(fileName,
System.IO.FileMode.OpenOrCreate);
range.Load(fStream, System.Windows.DataFormats.Text);
fStream.Close();
}
}
Listing 22

Converting RichTextBox Contents to a String


There is no direct method or property in RichTextBox that can extract the document or contents of a
RichTextBox to a string. To convert the contents to a string, we first need to read the contents of a
RichTextBox in a TextRange object and use TextRange.Text property to convert it to a string.

The following code snippet in listing 23 reads a RichTextBox contents from start to end and converts to a
string.

string ConvertRichTextBoxContentsToString(RichTextBox rtb)


{
TextRange textRange = new TextRange(rtb.Document.ContentStart,
rtb.Document.ContentEnd);
return textRange.Text;
}

Listing 23

649 @ C# Corner
Figure
A figure is a portion of flow content with placement properties that can be customized independently
from the primary content flow within a FlowDocument. A figure has the following attributes.

● A figure can be positioned independently of other flow contents.


● A figure does not support paging or wrapping to fit the contents in the given viewer. If a figure
does not fit in a viewer, the portion of figure that falls outside of the viewer will be lost.
● A figure can be positioned vertically and horizontally.
● You can set a figure height and width to fit in multiple pages, columns, or rows.

Figure element in XAML is used to create figures to a FlowDocument. The following code snippet creates
a Paragraph.
<Figure> Blocks </ Figure >

Similar to other XAML elements, a Figure has most of the common properties such as Name, Font
related properties, Foreground and Background. The following code snippet sets a few properties of a
Figure.

<Figure
Background="GhostWhite"
Height="50"
HorizontalAnchor="PageLeft"
HorizontalOffset="100"
VerticalOffset="20"
Width="200">

Listing 4 is a complete example that shows how to use figure with a Paragraph.

<FlowDocument
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True" >
<Section Name="Heading"
FontSize="20"
FontFamily="Georgia"
Background="#FEF5ED">
<Paragraph>
Figure Sample
</Paragraph>
</Section>
<Paragraph>

<Figure
Background="GhostWhite"
Height="50"
HorizontalAnchor="PageLeft"
HorizontalOffset="100"
VerticalOffset="20"
Width="200">
<Paragraph

650 @ C# Corner
Background="#FEF5ED"
FontStyle="Italic"
Foreground="DarkGreen"
TextAlignment="Left">
Mindcracker Network was founded in 1999 as a community where
developers can learn and share their knowledge and ideas with other developers.
</Paragraph>
</Figure>
</Paragraph>
</FlowDocument>

Listing 24

The output of Listing 24 looks like Figure 1.

Figure 25

Figure Properties
Blocks property represents a collection of Block items at the top-level of a Figure.

CanDelayPlacement represents a boolean property that indicates whether this figure can delay its
placement in a FlowDocument.

Height and Width properties represent the height and width of a figure.

HorizontalAnchor is a type FigureHorizontalAnchor enumeration that describes horizontal anchor of a


figure that has values ColumnCenter, ColumnLeft, ColumnRight, ContentCenter, ContentLeft,
ContentRight, PageCenter, PageLeft, and PageRight.

651 @ C# Corner
VerticalAnchor is a type FigureVerticalAnchor enumeration that describes the vertical anchor of a figure
that has values ContentBottom, ContentCenter, ContentTop, PageBottom, PageCenter, PageTop, and
ParagraphTop.

HorizontalOffset and VerticalOffset properties represent the vertical and horizontal offsets.

WrapDirection is a type of WrapDirection enumeration that describes wrap direction and has values
Both, Left, None, and Right.

The code listed in Listing 25 shows how to set these properties in XAML at design-time.

<Figure
Background="GhostWhite"
Height="50"
HorizontalAnchor="PageLeft"
HorizontalOffset="100"
VerticalAnchor="PageCenter"
VerticalOffset="20"
Width="200"
WrapDirection="Both"/>

Listing 25

Dynamic Figure
The Figure class in WPF represents a figure. The code snippet in Listing 26 creates a Figure dynamically
and sets its properties.
private FlowDocument CreateAFigureDynamically()
{
FlowDocument doc = new FlowDocument();
// Create a Figure and set its properties
Figure dynamicFigure = new Figure();
dynamicFigure.Name = "DynamicFigure";
dynamicFigure.Background = Brushes.GhostWhite;
dynamicFigure.Width = new FigureLength(200);
dynamicFigure.Height = new FigureLength(50);
dynamicFigure.HorizontalAnchor = FigureHorizontalAnchor.PageLeft;
dynamicFigure.VerticalAnchor = FigureVerticalAnchor.PageCenter;
dynamicFigure.HorizontalOffset = 100;
dynamicFigure.VerticalOffset = 20;
dynamicFigure.WrapDirection = WrapDirection.Both;
// Create a contnet Paragraph for Figure
Paragraph p1 = new Paragraph(new Run("This text is within a figure"));
dynamicFigure.Blocks.Add(p1);

// Add Figure to a Paragraph


Paragraph p = new Paragraph(dynamicFigure);
// Add Paragraph to a FlowDocument
doc.Blocks.Add(p);
return doc;

652 @ C# Corner
}

Listing 26

Floater
A floater is a portion of flow content with placement properties that can be customized independently
from the primary content flow within a FlowDocument. A floater has the following attributes.

● A floater cannot be positioned.


● You cannot set the offset or anchor on a floater.
● A floater cannot be sized to more than one column. If the size of a floater does not fit in a
column, the outside area will not be visible.
● You cannot set the height of a floater.
● If contents of a floater do not fit in each width, it paginates. It may paginate to the next column,
next page and so on.

The Floater element in XAML is used to create a Floater to a FlowDocument. The following code snippet
creates a floater.
<Floater> Blocks </Floater>

A Floater has only two properties – HorizontalAlignment and Width. The following code snippet sets
these properties.
<Floater Name="FloaterExample"
Background="GhostWhite"
HorizontalAlignment="Left"
Width="300">
</Floater>

Listing 27 is a complete example that shows how to create a Floater and add some contents to it.

<FlowDocument
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True">
<Section Name="Heading"
Background="#FEF5ED"
FontSize="20"
FontFamily="Georgia">
<Paragraph>
Floater Sample
</Paragraph>
</Section>
<Paragraph>
<Floater Name="FloaterExample"
Background="GhostWhite"
HorizontalAlignment="Left"
Width="300">
<Table CellSpacing="5">

653 @ C# Corner
<Table.Columns>
<TableColumn Width="155"/>
<TableColumn Width="130"/>
</Table.Columns>

<TableRowGroup>
<TableRow>
<TableCell
Background="LightBlue"
ColumnSpan="3"
FontSize="16">
<Paragraph>Mindcracker Statistics</Paragraph>
</TableCell>
</TableRow>
<TableRow
Background="LightGoldenrodYellow"
FontSize="11">
<TableCell>
views:</Paragraph> <Paragraph FontWeight="Bold">Monthly Page

</TableCell>
<TableCell>
<Paragraph>3.8 Million</Paragraph>
</TableCell>
</TableRow>

<TableRow
FontSize="11"
Visitors:</Paragraph> Background="LightGray">
<TableCell>
<Paragraph FontWeight="Bold">Monthly Unique

</TableCell>
<TableCell>
<Paragraph>2.3 Million</Paragraph>
</TableCell>
</TableRow>

<TableRow
Background="LightGoldenrodYellow"
FontSize="11">
<TableCell>
<Paragraph FontWeight="Bold">US Visitors:</Paragraph>
</TableCell>
<TableCell>
<Paragraph>43%</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="4">
<Paragraph FontSize="10" FontStyle="Italic">
View more details on
<Hyperlink NavigateUri="http://www.c-
sharpcorner.com/forums/">
Mindcracker Network.
</Hyperlink>
</Paragraph>

654 @ C# Corner
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Floater>
</Paragraph>
</FlowDocument>

Listing 27

The output of Listing 27 looks like Figure 26.

Figure 26

Dynamic Floater
The Floater class in WPF represents a floater. The code snippet in Listing 28 creates a Floater
dynamically and sets its properties.
private FlowDocument CreateAFloaterDynamically()
{
FlowDocument doc = new FlowDocument();
// Create a Floater and set its properties
Floater dynamicFloater = new Floater();
dynamicFloater.Background = Brushes.GhostWhite;
dynamicFloater.Width = 285;
dynamicFloater.HorizontalAlignment = HorizontalAlignment.Center;
// Create a contnet Paragraph for Floater

655 @ C# Corner
Paragraph p1 = new Paragraph(new Run("This text is within a figure"));
dynamicFloater.Blocks.Add(p1);

// Add Floater to a Paragraph


Paragraph p = new Paragraph(dynamicFloater);
// Add Paragraph to a FlowDocument
doc.Blocks.Add(p);
return doc;
}

Listing 28

Bold, Underline, Italic


XAML Bold element is an inline-level content element that makes contents bold. You can place any
Inline element within a Bold element. Here is the Bold, Italic and Underline syntax.

<Bold>
Inlines
</Bold>

<Italic>
Inlines
</Italic>

<Underline>
Inlines
</Underline>

Listing 29 is a complete example that shows how to use Bold, Italic and Underline elements with other
elements to apply bold font on a FlowDocument contents.

<FlowDocumentReader Name="FlowDocumentReaderExample">
<FlowDocument >
<Paragraph>
<Bold>Bold text</Bold>
</Paragraph>
<Paragraph>
<Underline>Underline text</Underline>
</Paragraph>
<Paragraph>
<Bold>
<Underline>Bold and underline text</Underline>
</Bold>
</Paragraph>
<Paragraph>
<Italic>Italic text</Italic>
</Paragraph>
</FlowDocument>

656 @ C# Corner
</FlowDocumentReader>

Listing 29

The output of Listing 29 looks like Figure 27.

Figure 27

Dynamic Bold, Italic and Underline


The Bold, Italic and Underline classes in WPF are used to add bold, Italic and Underline effects to the
contents of a FlowDocument. The code snippet in Listing 30 creates a Paragraph, Bold, Italic, and
Underline and adds these effects to the contents of a FlowDocument.
// Create first Paragraph
Paragraph p1 = new Paragraph();
// Create and add a new Bold, Italic and Underline
Bold bld = new Bold();
bld.Inlines.Add(new Run("First Paragraph"));
Italic italicBld = new Italic();
italicBld.Inlines.Add(bld);
Underline underlineItalicBld = new Underline();
underlineItalicBld.Inlines.Add(italicBld);
// Add Bold, Italic, Underline to Paragraph
p1.Inlines.Add(underlineItalicBld);

Listing 30

657 @ C# Corner
Hyperlink
The Hyperlink element is an inline-level content element that is used to add a hyperlink to a
FlowDocument content. You can add hyperlink support to any Inline element.

Here is the Italic syntax for Hyperlink.

<Hyperlink>
Inlines
</Hyperlink >

Here is an example of hyperlink that sets NavigateUri to C# Corner website URL.

<Hyperlink NavigateUri="http://www.c-sharpcorner.com">
C# Corner
</Hyperlink>

Listing 31 is a complete example that shows how to use a Hyperlink element in a FlowDocument
contents.

<FlowDocument
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True">
<Section Name="Heading"
Background="#FEF5ED"
FontSize="20"
FontFamily="Georgia">
<Paragraph>
Hyperlink Example
</Paragraph>
</Section>
<Paragraph FontSize="10" FontStyle="Italic">
View more details on
<Hyperlink NavigateUri="http://www.c-sharpcorner.com/forums/">
C# Corner.
</Hyperlink>
</Paragraph>
</FlowDocument>

Listing 31

The output of Listing 31 looks like Figure 28.

658 @ C# Corner
Figure 28

Dynamic Hyperlink
The Hyperlink class in WPF is used to add a hyperlink to a FlowDocument. The code snippet in Listing 32
creates a hyperlink dynamically.

private FlowDocument CreateAHyperlinkDynamically()


{
// Create a FlowDocument
FlowDocument doc = new FlowDocument();
// Create a Paragraph and 3 Runs
Paragraph p = new Paragraph();
Run run1 = new Run("Hyperlink Sample ");
Run run2 = new Run(" Hyperlink added");
Run run3 = new Run("C# Corner");
// Create a Hyperlink and set NavigateUri
Hyperlink hlink = new Hyperlink(run3);
hlink.NavigateUri = new Uri("http://www.c-sharpcorner.com");
// Add Runs and Hyperlink to Paragraph
p.Inlines.Add(run1);
p.Inlines.Add(hlink);
p.Inlines.Add(run2);
// Add Paragraph to FlowDocument
doc.Blocks.Add(p);
return doc;
}

Listing 32

659 @ C# Corner
LineBreak
A LineBreak element is an inline-level content element that causes a line break to occur in flow content.

<LineBreak />

Listing 33 is a complete example that shows how to use a linebreak element in a FlowDocument
contents.

<FlowDocument ColumnWidth="400" >


<Paragraph>
<Bold>Mindcracker Network</Bold> including C# Corner
is an online community for Software developers and professionals.
<LineBreak />
<LineBreak />
Mindcracker Network allows its members to share their knowledge among
one another via its contents publishing including
<LineBreak />
<LineBreak />
<Bold>Articles, Blogs, Tutorials, and Videos.</Bold> It also allows members
to
ask and reply questions on
<Bold>Mindcracker Forums.</Bold>
</Paragraph>
</FlowDocument>

Listing 33

The output of Listing 33 looks like Figure 29.

Figure 29

660 @ C# Corner
Dynamic LineBreak
The LineBreak class in WPF is used to add a line break to a FlowDocument. The code snippet in Listing 34
adds a few line breaks dynamically.

private FlowDocument CreateALineBreakDynamically()


{
// Create a FlowDocument
FlowDocument doc = new FlowDocument();
// Create a Paragraph and 3 Runs
Paragraph p = new Paragraph();
Run run1 = new Run("Mindcracker Network</Bold> including C# Corner " );
Run run2 = new Run("is an online community for Software developers and
professionals.");
Run run3 = new Run("C# Corner ");
LineBreak lb1 = new LineBreak();
LineBreak lb2 = new LineBreak();
LineBreak lb3 = new LineBreak();
// Create a Hyperlink and set NavigateUri
Hyperlink hlink = new Hyperlink(run3);
hlink.NavigateUri = new Uri("http://www.c-sharpcorner.com");
// Add Runs and Hyperlink to Paragraph
p.Inlines.Add(run1);
p.Inlines.Add(lb1);
p.Inlines.Add(lb2);
p.Inlines.Add(hlink);
p.Inlines.Add(lb3);
p.Inlines.Add(run2);
// Add Paragraph to FlowDocument
doc.Blocks.Add(p);
return doc;
}

Listing 34

Run
A Run element is an inline-level content element that is used to add text to a FlowDocument. A Run
hosts a text. Here is the syntax of Run.

<Run>
Text
</Run>

Listing 35 is a complete example that shows how to create a Run within a Paragraph to add text to a
FlowDocument.

661 @ C# Corner
<FlowDocument>
<Paragraph>
<Run>This is an example of run text</Run>
<LineBreak/>
<Run>Run 2</Run>
<LineBreak/>
<Run>Run 3</Run>
</Paragraph>
</FlowDocument>

Listing 35

The output of Listing 35 looks like Figure 30.

Figure 30

Dynamic Run
The Run class in WPF is used to add a line break to a FlowDocument. The code snippet in Listing 36 adds
a few line breaks dynamically.

private FlowDocument CreateARunDynamically()


{
// Create a FlowDocument
FlowDocument doc = new FlowDocument();
// Create a Paragraph and 3 Runs
Paragraph p = new Paragraph();
Run run1 = new Run("Mindcracker Network including C# Corner ");
Run run2 = new Run("is an online community for Software developers and
professionals.");
Run run3 = new Run();
run3.Text = "Run text added using Text property";
// Add Runs and Hyperlink to Paragraph
p.Inlines.Add(run1);
p.Inlines.Add(run2);
p.Inlines.Add(new LineBreak());
p.Inlines.Add(new LineBreak());
p.Inlines.Add(run3);

662 @ C# Corner
// Add Paragraph to FlowDocument
doc.Blocks.Add(p);
return doc;
}

Listing 36

Fixed Document
FixedDocument logically binds an ordered sequence of pages together into a single, multi-page, fixed-
layout document. PageContent is the only allowable child element of the FixedDocument element. Each
PageContent element refers to the source of the content for a single page. PageContent elements must
be in sequential markup order, matching the page order of the document.

DocumentViewer

The DocumentViewer control is used to view fixed documents. The DocumentViewer control provides
built-in support for common operations including print output, copy to clipboard, zoom, and text search
features. The control provides access to pages of content through a familiar scrolling mechanism. Editing
is not supported in a DocumentViewer control.

A typical view of a DocumentViewer control looks like Figure 1. The DocumentViewer has built-in
support for Print, Copy, Zoom, 100%, FullPage, Fit Width, and Two Pages.

663 @ C# Corner
Figure 1

664 @ C# Corner
Summary
In this chapter, we discussed how to create and use documents in WPF, initially we learnt what flow
document is? What are the different types of viewing objects and learning their different features? In
the end we saw what the fixed document was.

665 @ C# Corner
Chapter 12: Data Access in WPF

By now, you are familiar with the functionality that can be achieved in applications using WPF. You
examined different kinds of controls, both built-in as well as custom and explored how to create rich
user interfaces, so basically you have good knowledge of presentation layer, having said that while
working with industry level complex applications you would also need to have fair understanding of
DataAccess layer.

WPF, however, is much more than just a rich UI creator. Even as this chapter is being written,
developers across the world are creating powerful lines of business applications such as ERP systems,
CRM systems and the like by using WPF. These applications deal extensively with data in some form or
the other.

WPF provides strong support and powerful features for data access. The latest version of WPF, helps
you develop robust data-bound applications efficiently.

This chapter will explore various aspects of data access with WPF.

If you are already familiar with data access in Windows Forms and/or ASP.NET, you are aware of the
basics of data handling. However, data access in WPF has quite a few differences as compared to that in
Windows Forms and ASP.NET, hence this chapter will begin at the best possible place - the beginning!

The chapter begins with introducing various kinds of data sources and how to create them in WPF. The
chapter then examines the concept of data binding and its implementation through some concrete
examples. Then the chapter describes advanced data topics such as the Entity Framework model,
WebAPIs and WCF services.

Finally, the chapter also describes how to troubleshoot common data-related errors and exceptions.

Data Sources
To begin working with data, you first need to have data stored somewhere, in some format in which it
can also be retrieved. In .NET jargon, a data source holds the data that can be used within your
application. You typically connect to the data source or create an instance of it, and then make use of it
to store and retrieve data for your application.

We are going to explore DataAccess chapter with following models:

● ADO.NET Entity Framework

666 @ C# Corner
● Web APIs – CRUD operations

● Data from a Service – WCF service

● LINQ to SQL

● Dapper

667 @ C# Corner
12.1 : ADO.NET Entity Framework
ADO.NET Entity Framework is a set of APIs that provides application developers a way to build data-
centric applications based on entity data models. The Entity Framework is a part of the .NET family.

A Dataset will be used to store and retrieve data from a data source such as an SQL Server database.
Depending on your requirements, you can also change the data source to an Access database, ODBC
data source, SQL Server Compact database, and so forth.

EF is defined in the System.Data.Entity namespace

Introduction
Entity Framework. It is an ORM tool used as a:
● DDL: Data Definition Language to perform (CREATE, ALTER, DROP => Table)
● DML: Data Manipulation Language (SELECT, INSERT, UPDATE, DELETE => Records inside a table)

When one has good knowledge of SQL or RDBMS, they most likely follow the DBFirst approach.

● DBFirst
One follows this approach when he has a clear understanding of the requirements of the project
in the beginning & starts creating DB as per requirements. The DBFirst approach creates an
entity framework from an existing database.
● CodeFirst
One follows this approach when he does not have a clear understanding of the requirements of
the project in the beginning & starts creating OOPS classes first as he gets new requirements
and connects the dots looking forward. The CodeFirst approach creates model Classes,
properties, DbContext etc. first, then creates a new database or updated database based on
these models/entities and their relationships.

We are going to focus on the DBFirst approach for this example, for that we are going to map an existing
DB in your ongoing project.

Step 1

Say you have a Presentation layer, It could be WPF or Website or Console application. We are obviously
going to use a WPF application for our examples. Now let’s dig into the question on how to get the data
from SQL Server.

First, you need to install SQL Server on your premises which could be your machine or a server or cloud.
SQL Server is used to develop and test databases in a production or non-production environment.

668 @ C# Corner
You can download SQL Server from Microsoft’s website. Once you run the SQL server’s installer, you'll
be able to see the screen as shown in figure 1.

Figure 1

Once the SQL server is finished installation, you can click on the Connect now button (shown in figure 2)
to test the connection and you are good to go.

669 @ C# Corner
Figure 2

On the top of this, you need MS-SQL server management studio. You need Management studio to
interact, configure SQL server. You can install whichever latest version is available to you. Currently
release version is 18.10 as you can see in figure 3.

670 @ C# Corner
Figure 3

Now that we are done with installation of both “SQL Server” and “MS-SQL server management studio”.
We can skip to the good part. Our focus is to show the connectivity and configuration between WPF and
Entity Framework. So, we won’t get into relational database’s complexity for now. Go ahead and fire up
“MS-SQL server management studio”, we are using “localhost” as Server Name, but you can specify the
configuration as per your requirements. Find quick guide here: https://docs.microsoft.com/en-
us/sql/ssms/quickstarts/ssms-connect-query-sql-server?view=sql-server-ver15

After setup has been done, go ahead and create a DB, we are using “WPFSimplifiedEmployeeDB” as
Database name then click ok.

671 @ C# Corner
Figure 4

Now let’s create an Employee table, as you can see in figure 5, we have an Employee table with 4
columns. Emp_ID, Emp_Name, Emp_Designation and IsManager.

672 @ C# Corner
Figure 5

Let’s fill some dummy data in the Employee table. As you can see from figure 6 we have four records in
the table.

Figure 6

By now you know how to create a WPF application. So, go ahead and create a WPF application. We have
named our application as “WPFSimplified”. Right now, we don’t have to do anything in that app. Our
focus today is on the DataAccess layer.

Note: It is always a good practice to keep the DB layer separate from the presentation layer so that these
2 modules maintain the loose coupling.

673 @ C# Corner
With that said go ahead and add add the an application which would be type of “Class library” as shown
in figure 7.

Figure 7

Next it will ask you for the project name, go ahead and call it “DataAccess”, usually in three tier
architecture this layer deals with data. Then select the desired path and click next. And with that you are
good to go.

674 @ C# Corner
Figure 8

Now we have 2 applications under one solution. And we obviously want the “DataAccess” layer to share
data with “PresentationLayer” and to achieve this just add the DataAccess assembly’s reference to the
WPFSimplified assembly. As shown in figure 9 right click on dependencies in WPFSimplified app, this will
open a Reference manager from there select projects and check DataAccess assembly then click ok.

675 @ C# Corner
Figure 9

After successfully adding reference, you’d be able to see DataAccess’s reference under Projects of
WPFSimplified assembly. Shown in figure 10.

Figure 10

676 @ C# Corner
Now to work with Entity Framework, we need its dlls. Select the “DataAccess” project and right click and
select “Manage Nuget Packages”. It will open the NuGet package manager and then search for Entity
Framework and install the Entity Framework package highlighted in figure 11.

Figure 11

We are done with configuration; next we need to import Data Models from SQLServer into our project.
This is the same Employee table we created earlier. Right click on the “DataAccess” project then click on
the “Add New” item which will open the dialog shown in figure 12. Under the Data option, select
“ADO.NET Entity Data Model”. Give the desired name to the model, we are calling it EmployeeDetails
and click on an Add button. This will open up the Entity Data Model Wizard, which we will walk you
through next.

677 @ C# Corner
Figure 12

To choose the model, you will have multiple choices as shown in figure 13. Choose the one which suits
your application. For this example, we are going to select the first option “EF Designer from database”
and then click on the next.

678 @ C# Corner
Figure 13

Next, Select the data source. For us we are using Microsoft SQL Server. And our server is localhost only,
so we’ll keep the server’s name to localhost. Then below select the name of the database you wish to
communicate. As you can see in figure 14, we have selected WPFSimplifiedEmployeeDB. At last, test
connection to ensure if connection is successful and click ok.

679 @ C# Corner
Figure 14

In the next dialog, Choose the Data connection, check the option for “Save connection settings in
APP.config”, this will automatically add the connection string to App.config then click next.

680 @ C# Corner
Figure 15

Finally, the next dialog will let you select Tables, Views and Stored procedures from the Data source. For
our example we only have one table, so we are going to select that. Expand the Table’s hierarchy and
select Employee as shown in figure 16. You can specify the desired name for your model and then click
finish.

681 @ C# Corner
Figure 16

After finishing the wizard, it will add the selected data models and create model specific classes for you.
As shown in figure 17, you can see the Employee entity has been added to our project successfully.

682 @ C# Corner
Figure 17

Let’s add some code to make sure everything is working as it is supposed to.

Open your WPF application and add the ListView. We are using ListView to show the multiple records of
employees. Also, we are using DataTemplate from the resources chapter. Code snippet in listing 1 is the
full version of XAML that we are using for this example.
<Window x:Class="WPFSimplified.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFSimplified"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="EmployeeDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TextBlockEmployeeDetail"
FontWeight="Bold" >
<Run Text=" | "/>
<Run Text="Emp Id: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_ID}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Name: "
Foreground="#344CB7"/>

683 @ C# Corner
<Run Text="{Binding Emp_Name}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Designation: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Designation}"
Foreground="#CD1818"/>
<Run Text=" | Manager: "
Foreground="#344CB7"/>
</TextBlock>
<CheckBox IsChecked="{Binding IsManager}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock FontSize="30"
Foreground="#B91646"
HorizontalAlignment="Center"
Margin="0 0 0 20"
Text="Employee details:"/>
<ListView x:Name="ListViewItemTemplateExample"
HorizontalAlignment="Center"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.Row="1"/>
</Grid>
</Window>

Listing 1

We got our UI ready, let’s head over to code behind to load ListView’s ItemSource with employee’s
details. Listing 2 has the method GetEmployeeDetails(). All we are doing is to create an instance of
model and query on the employee table, we are not filtering any employees in this example but with
LINQ you can add where clause to do so. Then store the result in an IQueryable object and assign it to
the ItemSource of the ListView.
private void GetEmployeeDetails()
{
using WPFSimplifiedEmployeeDBEntities db = new();
IQueryable<Employee> query = from emp in db.Employees
select emp;
ListViewItemTemplateExample.ItemsSource = query.ToList();
}

Listing 2

Listing 3 shows an auto generated model of Employee from the table we had in SQL server. It
automatically generates the class with properties matching the number and type of the column in SQL
server.

684 @ C# Corner
//
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//
namespace DataAcess
{
using System;
using System.Collections.Generic;

public partial class Employee


{
public Nullable<int> Emp_ID { get; set; }
public string Emp_Name { get; set; }
public string Emp_Designation { get; set; }
public bool IsManager { get; set; }
}
}

Listing 3.

Now run the project and you should be seeing the output as figure 18.

Figure 18

Figure 19 is a snapshot of the employee table.

Figure 19

685 @ C# Corner
Note: You need to specify the connection string in the startup project as well, if you don’t then might end
up with the following exception.

Figure 20

In our case, the StartUp project is a WPF app, and that might not have App.config by default. You can
add App.config from the “Add New” dialog under the general tab as shown in figure 21.

686 @ C# Corner
Figure 21

Now copy the connection string from DataAccess’s app and paste it in WPF app’s App.config and you are
good to go.

Figure 22

Congratulations, you have successfully configured DBFirst into your project. Now we can perform all
kinds of data manipulations using the entity framework.

Summary
In this chapter, we learnt how to configure SQL server, create a table and then we learned how to
configure Entity Framework to WPF app and map the entities.

687 @ C# Corner
12.2 : Web API
In the last chapter, we saw how to get data from the entity framework. We are going to use the same
project and let’s extend its functionalities with web APIs.

What is the REST API?


It is called s RESTful API which uses HTTP requests & perform following operations

GET Fetches the records from DB e.g., select queries

PUT Updates the records into DB e.g., update queries

POST Creates the records into DB e.g., insert queries

DELETE Deletes the records from DB e.g., delete queries

When to use REST API?


Imagine you have a WPF application and a website and both of these applications are going to access
the same database. In that case, it would be a foolish move to design & develop a database for both
applications separately.

Rather, one can have a database placed at one point and expose the APIs to 'n' number of applications
based on their requirements.

Advantages of having this architecture


● Loose coupling
With such a design, modules won't be highly integrated with each other.
● Extensible
So if tomorrow the client decides to have a mobile application as well as a website & a WPF app,
then we won't have to create a new DB just for WPF. Just expose the API to WPF applications &
we are good to go.

688 @ C# Corner
Figure 1: Architecture of REST API

Now it's time for some solid action. Open your WPFSimplified application Right click on solution explorer
=> Add new Project => Select Asp.Net web Application as shown in figure 2.

Figure 2

689 @ C# Corner
Next, in Configure your new project dialog. Name your project and click the create button.

Figure 3

Next, Select Web API & hit the create button.

Figure 4

690 @ C# Corner
For the .Net Core platform, Wizard will ask for additional information. Which includes Configuration of
HTTPS, Enabling Docker, Target framework as shown in figure 5.

Figure 5

After successful configuration, Web API will add HomeController & ValuesController in your project
under the controller folder.

Note: You need to have IIS installed into your system and select WebAPIs project as a startup project too.
So now you’ll have multiple startup projects. First is WPFSimpilfied app and this one.

Now run the project. It will be published on IIS and will open in a web browser.

Localhost is your system & next to that is the port number (e.g., 44364) on which REST API is running.

691 @ C# Corner
Figure 5

Open ValuesController

It has default Get, Post, Put & Delete interfaces as shown in listing 1.

public class ValuesController : ApiController


{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody] string value)
{
}

// PUT api/values/5
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}

692 @ C# Corner
}

Listing 1

Let's call a get method, which is returning a string array of values "value1" & "value2" and see if that's
working. Paste the following URL in your web browser.

Note: Replace port number as per your application and make sure project WebAPIs is running.

https://localhost: 44364/api/values

your browser would show the following output.

Figure 6

Perfect, that tells us that we have successfully configured the Rest API.

Next, we are going to create a new controller for employees. Right-click on the Controllers folder => Add
new controller.

693 @ C# Corner
Figure 7

Select Web API 2 Controller – Empty and click on an Add button, as shown in figure 8.

694 @ C# Corner
Figure 8

Next, it will ask for Name. Go ahead and name it EmployeeController as shown in figure 9.

Figure 9

It will add the following class EmployeeController extending the ApiController class.
public class EmployeeController : ApiController
{
}

Listing 2

Now we are going to start creating CRUD operations.

695 @ C# Corner
First things first, Add DataAccess's reference to WebAPIs's project, refer figure 10.

Note: You also need Entity Framework’s dlls in WebAPI’s project. You can refer to the previous chapter to
understand how to do the same.

Figure 10

Let's see what we have in the database, Figure 11 shows that we have 4 records in the employee table.

Figure 11

Let’s understand the first interface, which is GET.

696 @ C# Corner
GET Interface
First, let's fetch employee details based on employee id. Remember, to fetch the details we must use
the get method.

● The attribute [HttpGet] specifies it is a get method. By default.


● Return type IHttpActionResult: returns status code, error details, response data in content in
HTTP format
● WPFSimplifiedEmployeeDBEntities is our DbContext to fetch employee entities with data.
o returns ok if there are any records.
o returns not found error if no records are there.
o returns an exception if the request is not processable.

If you pass the specific id of the employee, then details of that employee are returned. Code listed in
listing 3 shows how to use employee model to fetch the employee details based on employee id and if
you pass wrong id then we return Http code 404 (Not found) and for any other exception we return Http
code 400 (Bad request). Open your EmployeeController and paste the code snippet from the following
listing.

public class EmployeeController : ApiController


{

/// <summary>
/// Filter out employee whose details are asked
/// </summary>
/// <param name="id">id of employee</param>
/// <returns>employee details of id</returns>
[HttpGet]
public IHttpActionResult Get(int id)
{
try
{
using (WPFSimplifiedEmployeeDBEntities entities = new
WPFSimplifiedEmployeeDBEntities())
{
Employee emp = entities.Employees.FirstOrDefault(em => em.Emp_ID == id);
return emp != null ? Ok(emp) : (IHttpActionResult)Content(HttpStatusCode.NotFound,
"Employee with Id: " + id + " not found");
}
}
catch (Exception ex)
{
return Content(HttpStatusCode.BadRequest, ex);
}
}

697 @ C# Corner
Listing 3

If you run the application and paste the following URI, you’d see the results of the employee with
Emp_ID = 1.

https://localhost:44364/api/Employee/1

Note: Replace port number as per your application and make sure project WebAPIs is running.

Figure 12

It’s good to know that our APIs are working. Now let’s merge it into a WPF application.

Let’s create an app as per snapshot shown in figure 13. This is a full-fledged app for all the CRUD
operations of REST APIs.

698 @ C# Corner
Figure 13

1. With a CREATE interface, we are going to add an employee.


2. With the UPDATE, we are going to update employee’s information.
3. With READ, we are going to fetch employee’s details.
4. With DELETE, we are going to delete the employee’s record.

Let’s define an architecture for the application.

1. Presentation layer is a WPF application which has 4 buttons each for every CRUD operation.
2. DataAccess layer to manage entity framework, this will hold our employee model and
DbContext.
3. Last the WebAPIs layer, all the calls from button click will be redirected here, which will interact
with DbContext to perform CRUD operations.

The following snapshot of the solution is shown in figure 14, which gives the big picture on overall
application.

In following figure,

699 @ C# Corner
● Three layers are highlighted in red.
● DbContext is highlighted in yellow.
● EmployeeController is highlighted in saffron, this controller is responsible for performing CRUD
operations.
● MainWindow.xaml and its code behind is the UI layer responsible for user input and making
CRUD calls.
● Last, APIHelper is the class where all 4 CRUD operations are going to be listed, managing
HttpClient and its parameters for each operation.

Figure 14

Open MainWindow.xaml and add the code snippet listed in listing 4. We are using DataTemplate for
ListView to show employee details, a TextBox to accept user inputs to get employee ID and 4 Buttons as
shown in figure 13. One registration form to get employee details and create a new employee record,
and one TextBlock at the end to show the message if the operation was successful or not.

700 @ C# Corner
Note: we are using separate listviews, one to get all employee records and other is to get employee
details by Emp_ID.
<Window x:Class="WPFSimplified.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFSimplified"
mc:Ignorable="d" Background="#082032"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="EmployeeDataTemplate">
<StackPanel Orientation="Horizontal"
Width="430">
<TextBlock x:Name="TextBlockEmployeeDetail"
FontWeight="Bold" >
<Run Text=" | "/>
<Run Text="Emp Id: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_ID}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Name: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Name}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Designation: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Designation}"
Foreground="#CD1818"/>
<Run Text=" | Manager: "
Foreground="#344CB7"/>
</TextBlock>
<CheckBox IsChecked="{Binding IsManager}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid HorizontalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock FontSize="15"
Foreground="#CEE5D0"
HorizontalAlignment="Left"
Margin="10 20 0 5"
Text="Employee details:"
Grid.ColumnSpan="1"/>
<ListView x:Name="ListViewAllEmployees"

701 @ C# Corner
HorizontalAlignment="Center" Background="#EEEEEE"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.ColumnSpan="1"
Grid.Row="1" />

<StackPanel
Margin="5 20 5 5"
Grid.Row="2">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TextBlockEmployeeID"
FontSize="15"
Foreground="#CEE5D0"
Margin="5 0 0 0"
Text="Employee ID:" />
<TextBox x:Name="TextBoxEmployeeID"
Margin="20 0 0 0"
Width="100" />

<Button x:Name="ButtonFind"
Background="#2E4C6D"
Click="ButtonFind_Click"
Content="Find / Get"
Foreground="White"
Margin="20 0 0 0"
Width="100" />
<Button x:Name="ButtonDelete"
Background="#2E4C6D"
Click="ButtonDelete_Click"
Content="Delete"
Foreground="White"
Margin="18 0 0 0"
Width="100" />
</StackPanel>
<ListView x:Name="ListViewFindEmployee"
HorizontalAlignment="Center"
Margin="5 10 0 5"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.ColumnSpan="1"
Grid.Row="1" />
</StackPanel>
<Border Background="#11324D"
BorderBrush="White"
BorderThickness="1,1,1,1"
CornerRadius="30,30,30,30"
HorizontalAlignment="Center"
Grid.Row="3">
<Grid x:Name="GridPost"
Margin="10 10 10 0"
Width="260">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>

702 @ C# Corner
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelEmpID"
Content="Emp ID:"
Foreground="White"
Margin="0 10 0 0"/>
<Label x:Name="LabelEmployeeName"
Content="Employee Name:"
Foreground="White"
Grid.Row="1"/>
<Label x:Name="LabelDesignation"
Content="Designation:"
Foreground="White"
Grid.Row="2"/>
<Label x:Name="LabelManager"
Content="Manager:"
Foreground="White"
Grid.Row="3"/>
<TextBox x:Name="TextBoxEmpID"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>
<TextBox x:Name="TextBoxEmployeeName"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="1"/>
<TextBox x:Name="TextBoxDesignation"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>
<CheckBox x:Name="CheckBoxIsManager"
Margin="0 4 0 0"
Grid.Column="1"
Grid.Row="3"/>
<StackPanel Margin="20 10 0 0"
Orientation="Horizontal"
Grid.Row="4"
Grid.ColumnSpan="2">
<Button x:Name="ButtonAddEmployee"
Background="#2E4C6D"
Click="ButtonAddEmployee_Click"
Content="Add / Post"
Foreground="White"
Height="20"

703 @ C# Corner
HorizontalAlignment="Center"
Width="100"/>
<Button x:Name="ButtonUpdateEmployee"
Background="#2E4C6D"
Click="ButtonUpdateEmployee_Click"
Content="Update / Put"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
</StackPanel>
<TextBlock x:Name="TextBlockMessage"
Foreground="White"
HorizontalAlignment="Center"
Margin="20 8 0 10"
Grid.Row="5"
Grid.ColumnSpan="2"/>
</Grid>
</Border>
</Grid>
</Window>
Listing 4

Tip: If you get a configuration exception, go ahead, and install web API packages with NuGet’s command
line, fire the command shown in figure 13.

Figure 13

1. Get interface
First we are going to fetch all the records of employees, then in the second approach we will take
employee id from the user and fetch the specific record that matches that employee id.

First approach, fetching all the records of an employee table. As far as XAML is concerned, all you need
is ListView to display the number of records.

Note: We are using DataTemplate from previous examples, you can refer to templates chapter to
understand it in detail. Find DataTemplate’s code from listing 4.

Code snippet in listing 5 is a part of listing 4 which is responsible to display records of all employees.

<TextBlock FontSize="15"
Foreground="#CEE5D0"
HorizontalAlignment="Left"
Margin="10 20 0 5"

704 @ C# Corner
Text="Employee details:"
Grid.ColumnSpan="1"/>
<ListView x:Name="ListViewAllEmployees"
HorizontalAlignment="Center" Background="#EEEEEE"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.ColumnSpan="1"
Grid.Row="1" />

Listing 5

Let’s first create a get method to fetch all employee records. We need to write this logic in the Employee
controller. Open EmployeeController and add following namespaces.
using DataAccess;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

Listing 6

Then create a Get method and decorate with [HttpGet] attribute, the attribute [HttpGet] specifies it is a
get method. Then create an instance of WPFSimplifiedEmployeeDBEntities, it is our DbContext to fetch
an employee entity with data. For precaution in catch block return HttpStatusCode 400 which
represents the BadRequest. Finally add the return type of IHttpActionResult which returns status code,
error details, response data in content in HTTP format.

● returns ok if there are any records.


● returns not found error if no records are there.
● returns an exception if the request is not processable.

Following listing 7 shows how to create a Get call in the Employee controller.

public class EmployeeController : ApiController


{
[HttpGet]
public IHttpActionResult Get()
{
try
{
using (WPFSimplifiedEmployeeDBEntities entities = new
WPFSimplifiedEmployeeDBEntities())
{
List<Employee> emp = entities.Employees.ToList();
return Ok(emp);
}
}
catch (Exception ex)
{
return Content(HttpStatusCode.BadRequest, ex);
}

705 @ C# Corner
}

Listing 7

These API methods get called with HttpClient’s object. If you recall from our architecture's point of view
we need one ApiHelper class to handle HttpClient’s object. Create an ApiHelper in WPF assembly, refer
to figure 14 to understand its placement and add the following method listed in listing 8. We need to set
the parameters to call the API, as you can see from listing 8, we have HttpClient’s object, where we are
passing the URI, setting a timeout in the case of delay or failure. Setting media type to JSON and then
sending all these parameters as a package to call Get method from EmployeeController.

public static class ApiHelper


{
#region [GET]
/// <summary>
/// Get employee details.
/// </summary>
/// <param name="url"></param>
/// <returns>Employee details by ID</returns>
public static Task<HttpResponseMessage> GetCall(string url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new();
client.BaseAddress = new Uri(url);
client.Timeout = TimeSpan.FromSeconds(900);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
Task<HttpResponseMessage> response = client.GetAsync(url);
response.Wait();
return response;
}
#endregion

Listing 8

Now all we need to do is to call the GetCall method from listing 8. This employee’s list is going to be
loaded when the application runs, so we need to make an API call in the Window_Loaded event. Listing
9 shows how you can make a call to GetCall method, we need to pass the URI to call the specific API.
Finally, assign the list to the ItemsSource of ListViewAllEmployees.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
Task<HttpResponseMessage> employeeDetails =
ApiHelper.GetCall($"https://localhost:44364/api/Employee/");
if (employeeDetails.Result.StatusCode == HttpStatusCode.OK)

706 @ C# Corner
{
List<Employee> employeeResultDetails =
employeeDetails.Result.Content.ReadAsAsync<List<Employee>>().Result;
ListViewAllEmployees.ItemsSource = employeeResultDetails;
}
}

Listing 9

Now go ahead and run the application. You’d be able to see all the records as shown in figure 14.

Figure 14

Let’s design approach 2, In this we will accept the user input and display the specific record.

In XAML, you need 2 things, TextBox to accept user inputs and a button to call a GET API. We are also
adding a header, so we need one more TextBlock. Code snippet in listing 10 shows these 3 controls in
XAML.

<TextBlock x:Name="TextBlockEmployeeID"
FontSize="15"
Foreground="#CEE5D0"
Margin="5 0 0 0"
Text="Employee ID:"/>
<TextBox x:Name="TextBoxEmployeeID"
Margin="20 0 0 0"
Width="100"/>
<Button x:Name="ButtonFind"
Background="#2E4C6D"
Click="ButtonFind_Click"
Content="Find / Get"
Foreground="White"
Margin="20 0 0 0"
Width="100"/>

Listing 10

Let’s move to the EmployeeController and add the following method. Note this time GET method is also
accepting one parameter which is nothing but the Emp_ID against which we are fetching the record. For
logic just filter the record based on passed Emp_ID.

/// <summary>
/// Filter out epmloyee whose details are asked

707 @ C# Corner
/// </summary>
/// <param name="id">id of employee</param>
/// <returns>employee details of id</returns>
[HttpGet]
public IHttpActionResult Get(int id)
{
try
{
using (WPFSimplifiedEmployeeDBEntities entities = new
WPFSimplifiedEmployeeDBEntities())
{
Employee emp = entities.Employees.FirstOrDefault(em => em.Emp_ID ==
id);
return emp != null ? Ok(emp) :
(IHttpActionResult)Content(HttpStatusCode.NotFound, "Employee with Id: " + id + " not
found");
}
}
catch (Exception ex)
{
return Content(HttpStatusCode.BadRequest, ex);
}
}

Listing 11

For APIHelper, we can use the same GetCall method, we don’t need an extra method. It can serve the
purpose for both the first and second approach. Now on the button's click event add the following code.
Pay close attention to the URI that we pass. We are passing the user input as a part of URI. Finally, assign
the list to the ItemsSource of ListViewFindEmployee.

private void ButtonFind_Click(object sender, RoutedEventArgs e)


{
Task<HttpResponseMessage> employeeDetails =
ApiHelper.GetCall($"https://localhost:44364/api/Employee/" + TextBoxEmployeeID.Text);
if (employeeDetails.Result.StatusCode == System.Net.HttpStatusCode.OK)
{
Employee resultData =
employeeDetails.Result.Content.ReadAsAsync<Employee>().Result;
ListViewFindEmployee.ItemsSource = new List<Employee>(){ resultData };
}
}

Listing 12

Go ahead and run the application, add an Emp_ID in the search box and click on the “Find/Get” button.
The output of this approach would look like figure 15.

708 @ C# Corner
Figure 15

Alright, we got the success for fetching the record. Let’s try out the remaining 3 interfaces as well.

Next in line is, POST interface

In XAML, we need to create a form to accept user input for all the columns in our employee table
followed by an “Add/Post” button, which is responsible for sending all the forms data in URI and calling
the POST API of AiHelper class.
<Grid x:Name="GridPost"
Margin="10 10 10 0"
Width="260">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelEmpID"
Content="Emp ID:"
Foreground="White"
Margin="0 10 0 0"/>
<Label x:Name="LabelEmployeeName"
Content="Employee Name:"
Foreground="White"
Grid.Row="1"/>
<Label x:Name="LabelDesignation"
Content="Designation:"
Foreground="White"
Grid.Row="2"/>
<Label x:Name="LabelManager"
Content="Manager:"
Foreground="White"
Grid.Row="3"/>
<TextBox x:Name="TextBoxEmpID"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>
<TextBox x:Name="TextBoxEmployeeName"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="1"/>

709 @ C# Corner
<TextBox x:Name="TextBoxDesignation"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>
<CheckBox x:Name="CheckBoxIsManager"
Margin="0 4 0 0"
Grid.Column="1"
Grid.Row="3"/>
<StackPanel x:Name="StackPanelPostPut"
Margin="20 10 0 0"
Orientation="Horizontal"
Grid.Row="4"
Grid.ColumnSpan="2">
<Button x:Name="ButtonAddEmployee"
Background="#2E4C6D"
Click="ButtonAddEmployee_Click"
Content="Add / Post"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Width="100"/>
</StackPanel>
<TextBlock x:Name="TextBlockMessage"
Foreground="White"
HorizontalAlignment="Center"
Margin="20 8 0 10"
Grid.Row="5"
Grid.ColumnSpan="2"/>
</Grid>
Listing 13

Add the following Post method in EmployeeController. You can either use HttpResponseMessage or
IHttpActionResult. We are using IHttpActionResult because it is easy to understand. All we are doing is
adding the new employee’s object to the list of employees and saving it to the database.

/// <summary>
/// Creates a new employee
/// </summary>
/// <param name="employee"></param>
/// <returns>details of newly created employee</returns>
[HttpPost]
public HttpResponseMessage Post([FromUri] Employee employee)
{
try
{
using (WPFSimplifiedEmployeeDBEntities entities = new
WPFSimplifiedEmployeeDBEntities())
{
entities.Employees.Add(employee);
entities.SaveChanges();

710 @ C# Corner
HttpResponseMessage res =
Request.CreateResponse(HttpStatusCode.Created, employee);
res.Headers.Location = new Uri(Request.RequestUri +
employee.Emp_ID.ToString());
return res;
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}

Listing 14

Now add the following method from listing 15 to ApiHelpers class, here we are using generics because
objects could be of any type and our APIs should be independent of the type.
#region [POST]

/// <summary>
/// Creates a new employee
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="model"></param>
/// <param name="headerType"></param>
/// <returns>True if employee is crated</returns>
public static Task<HttpResponseMessage> PostCall<T>(string url, T model, string
headerType = "application/json") where T : class
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new();
client.BaseAddress = new Uri(url);
client.Timeout = TimeSpan.FromSeconds(60);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue(headerType));
var response = client.PostAsJsonAsync(url, model);
response.Wait();
return response;
}
#endregion

Listing 15

Now at last, “Add/Post” button’s click event creates a new employee’s object, and assigns the values
from the UI. Then pass these values as a part of URI as demonstrated in listing 16.

#region [POST]
private void ButtonAddEmployee_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(TextBoxEmpID.Text))
{
return;

711 @ C# Corner
}

Employee newEmployee = new()


{
Emp_ID = Convert.ToInt32(TextBoxEmpID.Text),
Emp_Name = TextBoxEmployeeName.Text,
Emp_Designation = TextBoxDesignation.Text,
IsManager = Convert.ToBoolean(CheckBoxIsManager)
};
string apiUrl = $"https://localhost:44364/api/Employee?Emp_ID=" +
newEmployee.Emp_ID
+ "&Emp_Name="
+ newEmployee.Emp_Name
+
"&Emp_Designation=" + newEmployee.Emp_Designation;
Task<HttpResponseMessage> employeeDetails =
ApiHelper.PostCall(apiUrl,newEmployee);
TextBlockMessage.Text = employeeDetails.Result.StatusCode ==
HttpStatusCode.Created
? newEmployee.Emp_Name + "'s details has successfully been added!"
: "Failed to update" + newEmployee.Emp_Name + "'s details.";
}
#endregion

Listing 16

Now, fill up the form as shown in figure 16 and click on the “Add/Post” button. As you can see in the
message shown at the bottom of the form “Ricky’s details have successfully been added” confirms that
the operation was successful.

Figure 16

You can cross check the same with the database. Figure 17 shows how a newly added record would look
in the employee table.

712 @ C# Corner
Figure 17

PUT interface
Let's update Marty’s designation from “scientist” to “physics”.
In XAML, we already have created the form to accept user input for an employee in listing 13. All we
need is a new button to call a PUT API.

<Button x:Name="ButtonUpdateEmployee"
Background="#2E4C6D"
Click="ButtonUpdateEmployee_Click"
Content="Update / Put"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>

Listing 17

Add the following Put method in EmployeeController. In this method first, we need to fetch the record
of an employee that needs to be updated, then override the values of that object.

The put has 2 parameters


● Id against which we must update the record. Pass through URI as params
● The new information must be updated.
Add an update statement for each property, because you may not know which property user wants to
update. Must check for null conditions.

/// <summary>
/// Update details of employee based on id
/// </summary>
/// <param name="id"></param>
/// <param name="emp"></param>
/// <returns>updated details of employee</returns>
[HttpPut]
public HttpResponseMessage Put(int id, [FromUri] Employee emp)
{
try
{
using (WPFSimplifiedEmployeeDBEntities entities = new
WPFSimplifiedEmployeeDBEntities())
{

713 @ C# Corner
Employee employee = entities.Employees.Where(em => em.Emp_ID ==
id).FirstOrDefault();
if (employee != null)
{
if (!string.IsNullOrWhiteSpace(emp.Emp_Name))
{
employee.Emp_Name = emp.Emp_Name;
}
if(!string.IsNullOrWhiteSpace(emp.Emp_Designation))
{
employee.Emp_Designation = emp.Emp_Designation;
}
employee.IsManager = emp.IsManager;
entities.SaveChanges();
HttpResponseMessage res = Request.CreateResponse(HttpStatusCode.OK, "Employee
with id" + id + " updated");
res.Headers.Location = new Uri(Request.RequestUri + id.ToString());
return res;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Employee with
id" + id + " is not found!");
}
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}

Listing 18

Now add the following method to the ApiHelpers class.

#region [PUT]
/// <summary>
/// Updates employees details
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
class /// <param name="model"></param>
public static Task<HttpResponseMessage> PutCall<T>(string url, T model) where T :

{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new();
client.BaseAddress = new Uri(url);
client.Timeout = TimeSpan.FromSeconds(900);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
Task<HttpResponseMessage> response = client.PutAsJsonAsync(url, model);

714 @ C# Corner
response.Wait();
return response;
}
catch (Exception)
{
throw;
}
}
#endregion

Listing 19

Finally, you have to select the record which you wish to update from the employee’s list, add the
updates values then click the “Update/Put” button. On the “Update/Put” button’s click event, create a
new employee’s object, assign the values from UI. We can fetch the Emp_ID from the selected record.
Then pass all these values as a part of URI as demonstrated in listing 20.
You’d notice there is a condition which is checking if the user has selected the record to update or not.

#region [PUT]
private void ButtonUpdateEmployee_Click(object sender, RoutedEventArgs e)
{
if (ListViewAllEmployees.SelectedItem is Employee)
{
Employee selectedEmployee = ListViewAllEmployees.SelectedItem as Employee;
Employee newEmployee = new()
{
Emp_ID = Convert.ToInt32(selectedEmployee.Emp_ID),
Emp_Name = TextBoxEmployeeName.Text,
Emp_Designation = TextBoxDesignation.Text,
IsManager = Convert.ToBoolean(CheckBoxIsManager)
};
string apiUrl = $"https://localhost:44364/api/Employee?Emp_ID=" + newEmployee.Emp_ID
+ "&Emp_Name=" + newEmployee.Emp_Name
+ "&Emp_Designation=" + newEmployee.Emp_Designation;
Task<HttpResponseMessage> employeeDetails = ApiHelper.PutCall(apiUrl, newEmployee);
TextBlockMessage.Text = employeeDetails.Result.StatusCode == HttpStatusCode.Created
? "Morty" + "'s details has successfully been updated!"
: "Failed to update" + newEmployee.Emp_Name + "'s details.";
}
}
#endregion

Listing 20

As you can see in figure 19, We have selected Morty’s record, and added “Physicist” in the designation
field and at last after clicking on the “Update/Put” button it shows the message for success.

715 @ C# Corner
Figure 18

You can cross check the same with the database. Figure 19 shows how a newly updated record would
look in the employee table.

Figure 19

DELETE interface
Let's delete Marty’s record from the table.
In XAML, we already have created the form to take any request change. All we need is a new button to
call a Delete API.

<Button x:Name="ButtonDelete"
Background="#2E4C6D"
Click="ButtonDelete_Click"
Content="Delete"
Foreground="White"
Margin="18 0 0 0"
Width="100"/>

716 @ C# Corner
Listing 21

Add the following Delete method in EmployeeController. We need to fetch the record of an employee
that needs to be deleted, then remove the record.

This method has 1 parameter


● Id against which we must delete the record.
Call SaveChanges method and return the result.

/// <summary>
/// Deletes the respected employee based on id passed.
/// </summary>
/// <param name="id"></param>
/// <returns>id of deleted employee</returns>
[HttpDelete]
public HttpResponseMessage Delete(int id)
{
try
{
using (WPFSimplifiedEmployeeDBEntities entities = new
WPFSimplifiedEmployeeDBEntities())
{
Employee employee = entities.Employees.Where(emp => emp.Emp_ID ==
id).FirstOrDefault();
if (employee != null)
{
entities.Employees.Remove(employee);
entities.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, "Employee with id" + id + "
Deleted");
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Employee with id"
+ id + " is not found!");
}
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}

Listing 22

Now add the following method to the ApiHelpers class.

#region [DELETE]
/// <summary>
/// Delete employee's record
/// </summary>
/// <param name="url"></param>
public static Task<HttpResponseMessage> DeleteCall(string apiUrl)

717 @ C# Corner
{
try
{ ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new();
client.BaseAddress = new Uri(apiUrl);
client.Timeout = TimeSpan.FromSeconds(900);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
Task<HttpResponseMessage> response = client.DeleteAsync(apiUrl);
response.Wait();
return response;
}
catch (Exception)
{
throw;
}
}
#endregion

Listing 23

Finally, you have to select the record which you wish to delete from the employee’s list, then click the
Delete button. On the button's click event, add the code listed in listing 20.

#region [DELETE]

private void ButtonDelete_Click(object sender, RoutedEventArgs e)


{
if (ListViewAllEmployees.SelectedItem is Employee)
{
Employee selectedEmployee = ListViewAllEmployees.SelectedItem as Employee;
Task<HttpResponseMessage> employeeDetails =
ApiHelper.DeleteCall($"https://localhost:44364/api/Employee?Emp_ID=" +
selectedEmployee.Emp_ID);

TextBlockMessage.Text = employeeDetails.Result.StatusCode == HttpStatusCode.OK


? selectedEmployee.Emp_Name + "'s details has successfully been "
+ Environment.NewLine + "deleted!"
: "Failed to delete " + selectedEmployee.Emp_Name + "'s details. ";
}
}
#endregion

Listing 24

As you can see in figure 20, We have selected Morty’s record, and then clicked the Delete button, after
the record has been successfully deleted from the database. We can show the message for successful
deletion.

718 @ C# Corner
Figure 20

You can cross check the same with the database. Figure 21 shows if the deleted record has been
removed from the employee table.

Figure 21

Summary
In this chapter, we learned what WebAPIs are, how to perform CRUD operations. Later we created an
application to perform Create, Update, Read and Delete operations on employee databases.

719 @ C# Corner
12.3 : WCF

WCF – Windows Communication Foundation is used to develop service-based applications. WCF makes
communication possible between 2 independent applications via endpoints.

We are going to use the Windows Communication Foundation (WCF) service as a data source. WCF Data
Services consists of patterns and libraries enabling the creation and consumption of data services
through the Web or an intranet.

An application that sends HTTP requests and processes responses in the format that a data service
returns can work with WCF Data Services.

We are going to use the same application we developed for entity framework and WebAPI. One of the
end points would be our WPF application and we will host the WCF service locally.

So basically, our WPF application will consume the WCF service to communicate, these two applications
can not only share XML or JSON, but are also capable of sharing whole objects too, such as the
employee object that we have been playing with so far.

Create a WCF App


Open WPFSimplified application, Right click on solution and click add a new application and in “Add a
new project” wizard select “WCF Service Application”. Refer to figure 1.

720 @ C# Corner
Figure 1

Once a project has been added, you’d notice interface IService1 and service Service1.svc as highlighted
in figure 2. The listing 1 shows how interface IService1 looks like. Now expand the svc file and open the
Service1.svc.cs class file. Under the carpet this service class inherits the same IService1 interface, listing
2 shows how Service1 class looks like.

721 @ C# Corner
Figure 2

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface
name "IService1" in both code and config file together.
[ServiceContract]
public interface IService1
{

[OperationContract]
string GetData(int value);

[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
[OperationContract]
List<Employee> GetManagers(bool isManager);
}

Listing 1

namespace WCFSimplified
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name
"Service1" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select
Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
public class Service1 : IService1
{
public string GetData(int value)

722 @ C# Corner
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
}

Listing 2

In order to add your own method here, you first need to add the method signature in interface
IService1, and then implement the updated interface in service class Service1.svc.cs

Note: In the service interface every method is decorated with [OperationContract] attribute.

Let’s create a method to get the list of all the managers from the database. As you can see from the
database snapshot in figure 3, there are 2 managers in the employee table, Julien, and Olivia. So, our
method signature will return the list of employees and will accept the Boolean parameter. If the value of
the parameter is true, we will return the list of employees who are managers. If the value of parameter
is false then we will return the list of employees who are not managers.

Figure 3

Code snippet in listing 3 is a method signature to filter employees by manager. Go ahead and add the
following method to Iservice.

[OperationContract]
List<Employee> GetManagers(bool isManager);

Listing 3

723 @ C# Corner
Note: In order to access the Employee’s class in WCFSimplified project, you need to add the DataAccess
assembly’s reference.

After updating the Iservice interface, it would look like figure 4.

Figure 4

Once you add the method signature in IService, Service1 class will notify you to implement the interface,
as shown in figure 5. Go ahead, do the needful.

Figure 5

724 @ C# Corner
Once you are done that, you will see the method GetManager(), throwing NotImplementedException, as
shown in figure 6.

Figure 6

Now let’s write logic for the GetManager’s method, we first need to create an instance of our
DataModel (WPFSimplifiedEmployeeDBEntities) that we created in the Entity Framework chapter. If we
directly use the instance of WPFSimplifiedEmployeeDBEntities, we’ll get a compile time error as shown
in figure 7. In order to solve this, just click on “Find and install latest version”, this will install the latest
version of Entity Framework to your WCF application.

Figure 7

725 @ C# Corner
Once you have done that, you can directly access the employee’s list from the data model and just filter
it based on the manager. Code snippet 4 shows the overall implementation of the GetManager’s
method.

public List<Employee> GetManagers(bool isManager)


{
using (WPFSimplifiedEmployeeDBEntities entities = new WPFSimplifiedEmployeeDBEntities())
{
List<Employee> employees = entities.Employees.Where(x => x.IsManager ==
isManager).ToList();
return employees;
}
}

Listing 4

Note: You need to add WCF project into a startup project with WPF application. Check the figure 8 for
better understanding.

Figure 8

Now if you run the project, you will still get an error highlighted in figure 9.

726 @ C# Corner
Figure 9

The reason is that we need to have connection string for our model “WPFSimplifiedEmployeeDBEntities”
with every startup project and as we have just added WCFSimplified into startup project’s list, we need
to add connection string in this project’s web.config too, refer to figure 10.

Figure 10

And now only the last thing is remaining. Right click on the Service1.svc file and click on “Set As Start
Page” as shown in figure 11.

727 @ C# Corner
Figure 11

Now hit the run button. Once the WCF application starts running, it will open up a WCF Test Client as
shown in following figure 12. Double click on GetManagers() method, which will trigger the right hand
panel. From there select the parameter, in this example we have isManager, as you can see the default
value is false. Now click the Invoke button as highlighted in figure 12.

728 @ C# Corner
Figure 12

Once you click on the invoke button with false value for isManager Boolean, you will get a list of
employees who are not managers as shown in figure 13.

729 @ C# Corner
Figure 13

Now, let’s change the value to true and see what happens.

730 @ C# Corner
Figure 14

As you can see in figure 14, with isManager’s value passed to be true, we get the employees who are
managers.

This confirms that the WCF service is working as it is supposed to.

731 @ C# Corner
Configure a WCF App into WPF App
Right click on the WPF app and select “Add -> Service reference”, refer figure 15. This will open the
wizard to add the service’s reference.

Figure 15

732 @ C# Corner
First dialog box in the wizard is “Add service reference”, out of 3 options select WCF Web Service as
shown in figure 16.

Figure 16

733 @ C# Corner
Next screen will ask you for the URI of the service, you can get this URI from “WCF Test Client”, right
click and copy the URI as shown in figure 17.

Figure 17

Once you have the URI, paste that in the URI textbox highlighted in figure 18, then click on discover
button, after successful search it will load the Service1, select the Service1, change the namespace if you
want and click on next button.

734 @ C# Corner
Figure 18

Next screen will ask you if you want to specify the data type options, you can change as per your
requirements, for this example we don’t need it so we are leaving everything as it is to default selection
and hit the next button.

735 @ C# Corner
Figure 19

In last screen, it will ask if to select access specifiers for auto generated classes, you can either select
public or internal. We are selecting public and click finish.

736 @ C# Corner
Figure 20

Once you’re done with referencing the service with WPF application. It will show the following screen
with a list of service references. And as you can see in figure 21, we have Service1.svc successfully
configured.

Figure 21

Now all we are left with is to call this service on our UI.

Let’s modify our application a little bit.

737 @ C# Corner
We need a CheckBox and a ListView. If CheckBox is selected, we will show all the managers and if
CheckBox is not selected, we will show all the other employees in ListView.

Listing 5 is XAML code for the above scenario.

<StackPanel Margin="10 20 0 0"


Grid.Row="4">
<StackPanel x:Name="WCFData"
Orientation="Horizontal">
<CheckBox x:Name="CheckBoxLoadManager"
Checked="CheckBoxLoadManager_Checked"
Unchecked="CheckBoxLoadManager_Unchecked"
Content="Load Manager"
Foreground="White"/>
</StackPanel>
<ListView x:Name="ListViewManager"
Background="#EEEEEE"
HorizontalAlignment="Center"
Margin="0 20 0 0"
ItemTemplate="{StaticResource EmployeeDataTemplate}"/>
</StackPanel>

Listing 5

In listing 5, we have 2 events associated with CheckBox, Checked and Unchecked, these 2 events are
fired when CheckBox is checked and unchecked respectively. Let’s write logic for the checked event. In
the listing 6, first we are creating an instance of Service and then all you have to do is to call the
respective method, if there is a large amount of data that has to be fetched then you can call the Async
method as well. Then assign the list of employees to ListView’s ItemSource. Notice while calling
GetManagerAsync() method with parameter true, which will return us the list of managers.

private void CheckBoxLoadManager_Checked(object sender, RoutedEventArgs e)


{
ServiceReference1.Service1Client employees = new();
Task<ServiceReference1.Employee[]> result = employees.GetManagersAsync(true);
ListViewManager.ItemsSource = result.Result.ToList();
}
Listing 6

In listing 7, we are keeping the same logic with one single change. That is , while calling the
GetManagerAsync() method we are passing the parameter value to false, which will return us the list of
employees who are not managers.
private void CheckBoxLoadManager_Unchecked(object sender, RoutedEventArgs e)
{
ServiceReference1.Service1Client employees = new();
Task<ServiceReference1.Employee[]> result = employees.GetManagersAsync(false);
ListViewManager.ItemsSource = result.Result.ToList();
}

738 @ C# Corner
Listing 7

Now go ahead and simply run the application. In figure 22, you can see that the list of managers has
been loaded when the CheckBox is selected.

Figure 22

If you uncheck the box, you’d be able to see the list of the rest of the employees who are not managers.

739 @ C# Corner
Figure 23

Summary
In this chapter, we learnt to create a WCF application, later we understood how to configure a WCF
application with Entity Framework then we learnt to configure service with WPF application.

740 @ C# Corner
12.4 : LINQ to SQL
Now you shall learn another means to bind the data to a WPF application.

LINQ is a set of technologies introduced in Visual Studio 2008 to facilitate working with data from
different data sources that may be present in different data formats. LINQ provides powerful and at the
same time flexible capabilities for querying data.

According to MSDN library, LINQ is a “set of extensions to the .NET that encompass language-integrated
query, set, and transform operations. It extends C# and Visual Basic with native language syntax for
queries and provides class libraries to take advantage of these capabilities.” Wikipedia has a simpler
definition: LINQ is “a Microsoft .NET Framework component that adds native data querying capabilities
to .NET languages.”

One of the important implementations of LINQ is “LINQ to SQL” which gives you a runtime infrastructure
for managing relational data as objects, without losing the ability to perform query operations. LINQ To
SQL is one of the approaches in LINQ through which you can bind any LINQ-enabled data source using
SQL syntax.

You can bind to data in a WPF application using LINQ To SQL. There are many different approaches to do
this. Let us explore one of them now.

We can use the same “WPFSimplified” WPF application from the previous chapter. What we need in this
chapter is to create a new database connection using the following steps:

Select server explorer in visual studio from the left side then right click Data Connections and select Add
Connection as shown in figure 1.

Figure 1

741 @ C# Corner
Specify the connection setting as per your configuration. For this example we have a server on a local
machine so we are selecting localhost as server name then specify the name of the database as
highlighted in figure 2.

Figure 2

742 @ C# Corner
After successfully connecting, you would be able to see the tables from your database under the Tables
folder. We are working with an employee table as you can see in figure 3 it has been appeared under
table folder.

Figure 3

If you double click on the employee table, it will open the designer for the table as shown in figure 4.

Figure 4
Next, under the Data, you’ll find the LINQ to SQL classes option. Select this option. This will add a dbml
file which will be added to your project.

743 @ C# Corner
Figure 5

Now double click on the dbml file, it will show an empty screen as shown in figure 6. All you have to do
is drag and drop the tables you are working with. We are going to drag and drop the only table we are
working with which is an Employee table.

744 @ C# Corner
Figure 6

Figure 7 shows how it looks once you’re done with dragging and dropping the tables into the dbml file.

745 @ C# Corner
Figure 7

Let’s see what we have in the database to work with. Figure 8 is the snapshot of the employee table
from SQL server.

Figure 8

Finally we are done with the configuration, Now let’s start the coding.

We are going to explore all 4 operations. Read, insert, update and delete.

746 @ C# Corner
Read operation
Open up MainWindow.xaml and add the following code from listing 1. Our approach is to load the
ComboBox with a list of employee’s names fetched from our employee table and on the selection of an
employee we will fill the ListView with selected employee’s details.

Add one more grid-row to our existing application. You can develop an independent application too if
you like. The code would be the same as listing 1.

<Grid Grid.Row="5">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock FontSize="15"
Foreground="#CEE5D0"
HorizontalAlignment="Left"
Margin="7 10 0 10"
Text="Employee details By LINQ to SQL:"
Grid.ColumnSpan="1"/>
<ComboBox Name="ComboBoxSelectEmployee"
Height="23"
HorizontalAlignment="Left"
Margin="7 0 0 0"
SelectionChanged="ComboBoxSelectEmployee_SelectionChanged"
VerticalAlignment="Top"
Width="200"
Grid.Row="1"/>
<ListView x:Name="ListViewLINQtoSQL"
Background="#EEEEEE"
HorizontalAlignment="Center"
Margin="0 10 0 0"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.Row="2"/>
</Grid>

Listing 1

Once you have the UI ready, head back to code behind. The first thing you need to do is to fetch the
employee’s records from the database, for this you need to create an instance of
DataClasses1DataContext. Once you have the list of employees you can perform a LINQ operation to
filter on the employee's name and store the result in a list of strings. Then simply assign this list of
strings to the ItemSource of a ComboBox.

Note: you’ll have to call this method in on window.loaded event or in the constructor of the MainWidow.

/// <summary>
/// LINQ to SQL
/// </summary>
private void LoadEmployeeComboBox()
{

747 @ C# Corner
DataClasses1DataContext edc = new();
IQueryable<string> query = from s in edc.Employees select s.Emp_Name;
ComboBoxSelectEmployee.ItemsSource = query.ToList();
}

Listing 2

Now, if you observe listing 1, you’d notice we have an event on ComboBox which is SelectionChanged,
So whenever a user selects an item this event gets fired. In listing 3, what we are doing is, we are storing
the value of selectedItem, then passing this value in LINQ’s where clause, which will filter the employee
with this name, then again just assign the result to ListView.

private void ComboBoxSelectEmployee_SelectionChanged(object sender,


System.Windows.Controls.SelectionChangedEventArgs e)
{
string empName = ComboBoxSelectEmployee.SelectedItem.ToString();
DataClasses1DataContext empDetails = new();
var query = from emp in empDetails.Employees
where emp.Emp_Name == empName
select emp;
ListViewLINQtoSQL.ItemsSource = query.ToList();
}

Listing 3

That’s all you needed to fetch the details.

In figure 9, you can see we have highlighted the XAML part which we have added in listing 1. From the
ComboBox we selected Marty’s name and based on that selection we have loaded his details.

748 @ C# Corner
Figure 9

Now let’s select the Employee whose name is Julien.

749 @ C# Corner
Figure 10

As you can see in figure 11, Julien’s details have been loaded.

750 @ C# Corner
Figure 11

Insert operation

751 @ C# Corner
We already have the employee registration form in XAML to accept user’s input for employee details. To
refresh your memory let us show the XAML for Employee registration form. In the following registration
form, ignore the first 2 Buttons, Add and Update, those buttons are from the REST APIs chapter, to
perform insert and update we have added 2 new buttons below them. Listing 4 has XAML for the overall
employee registration form with 2 newly added buttons. To learn about this form in detail readthe REST
APIs chapter.

<Border Background="#11324D"
BorderBrush="White"
BorderThickness="1,1,1,1"
CornerRadius="30,30,30,30"
HorizontalAlignment="Center"
Grid.Row="3">
<Grid x:Name="GridPost"
Margin="10 10 10 0"
Width="260">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelEmpID"
Content="Emp ID:"
Foreground="White"
Margin="0 10 0 0"/>
<Label x:Name="LabelEmployeeName"
Content="Employee Name:"
Foreground="White"
Grid.Row="1"/>
<Label x:Name="LabelDesignation"
Content="Designation:"
Foreground="White"
Grid.Row="2"/>
<Label x:Name="LabelManager"
Content="Manager:"
Foreground="White"
Grid.Row="3"/>
<TextBox x:Name="TextBoxEmpID"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>
<TextBox x:Name="TextBoxEmployeeName"
Height="20"
Width="150"

752 @ C# Corner
Grid.Column="1"
Grid.Row="1"/>
<TextBox x:Name="TextBoxDesignation"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>
<CheckBox x:Name="CheckBoxIsManager"
Margin="0 4 0 0"
Grid.Column="1"
Grid.Row="3"/>
<StackPanel Grid.Row="4"
Grid.ColumnSpan="2">
<StackPanel x:Name="StackPanelPostPut"
Margin="20 10 0 0"
Orientation="Horizontal">
<Button x:Name="ButtonAddEmployee"
Background="#2E4C6D"
Click="ButtonAddEmployee_Click"
Content="Add / Post"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Width="100"/>
<Button x:Name="ButtonUpdateEmployee"
Background="#2E4C6D"
Click="ButtonUpdateEmployee_Click"
Content="Update / Put"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
</StackPanel>
<StackPanel x:Name="StackPanelInsertLINQ"
Margin="20 5 0 0"
Orientation="Horizontal">
<Button x:Name="ButtonAddEmployeeLINQ"
Background="#2E4C6D"
Click="ButtonAddEmployeeLINQ_Click"
Content="Insert: LINQ"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Width="100"/>
<Button x:Name="ButtonUpdateEmployeeLINQ"
Background="#2E4C6D"
Click="ButtonUpdateEmployeeLINQ_Click"
Content="Update: LINQ"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
</StackPanel>
</StackPanel>

753 @ C# Corner
<TextBlock x:Name="TextBlockMessage"
Foreground="White"
HorizontalAlignment="Center"
Margin="20 8 0 10"
Grid.Row="5"
Grid.ColumnSpan="2"/>
</Grid>
</Border>

Listing 4

Now the logic for the Insert button. In listing 5, first we need to create an instance of DataContext,
followed by creating a new object of an employee class and assign the details from the UI. Then call the
InsertOnSubmit() method and pass the newly created employee’s object. This method is responsible for
insert operation. Finally call the SubmitChanges() method to commit the changes. That’s all.

Next, we are fetching the details of the newly added employee and showing the success message on
messagebox.

private void ButtonAddEmployeeLINQ_Click(object sender, RoutedEventArgs e)


{
DataClasses1DataContext emp = new();
Employee newEmployee = new()
{
Emp_ID = Convert.ToInt32(TextBoxEmpID.Text),
Emp_Name = TextBoxEmployeeName.Text,
Emp_Designation = TextBoxDesignation.Text,
IsManager = Convert.ToBoolean(CheckBoxIsManager)
};
//Insert an employee's details to the database
emp.Employees.InsertOnSubmit(newEmployee);
//Save changes to the database.
emp.SubmitChanges();

//Get the details of an new inserted employee


Employee insertedEmployee = emp.Employees.FirstOrDefault(employee =>
employee.Emp_Name == newEmployee.Emp_Name);
MessageBox.Show(insertedEmployee.Emp_Name + "'s details has been added to the
database!");
}

Listing 5

In figure 12, you can see we have added an employee with the name Oliver and it’s been successfully
added to the database.

754 @ C# Corner
Figure 12

You can cross check in your database to confirm if the database is updated with a new record or not.
Figure 13 is a snapshot of our database.

Figure 13

Update operation

755 @ C# Corner
XAML doesn’t need any extra change, all we need is the Update button’s click event handler.

In code snippet in listing 6, first again create an instance of DataContext, then first fetch the employee’s
record based on the name passed from the UI, then create a new employee’s object, fill up with values
from UI, then just call the SubmitChanges method.

Next, fetch the updated record and show the successful message on the message box.

private void ButtonUpdateEmployeeLINQ_Click(object sender, RoutedEventArgs e)


{
DataClasses1DataContext emp = new();
Employee updateEmployee = emp.Employees.FirstOrDefault(employee => employee.Emp_Name
== TextBoxEmployeeName.Text);

Employee newEmployee = new()


{
Emp_ID = Convert.ToInt32(TextBoxEmpID.Text),
Emp_Name = TextBoxEmployeeName.Text,
Emp_Designation = TextBoxDesignation.Text,
IsManager = Convert.ToBoolean(CheckBoxIsManager)
};
//Save the new changes to the database.
emp.SubmitChanges();

//Get the details of newly updated employee


Employee updatedEmployee = emp.Employees.FirstOrDefault(employee => employee.Emp_Name
== newEmployee.Emp_Name);
MessageBox.Show(updatedEmployee.Emp_Name.Trim() + "'s details has been upodated to
the database!");
}

Listing 6

Now you run the application and update employee’s records as shown in figure 14.

756 @ C# Corner
Figure 14

Figure 15 shows the snapshot of the updated details of the Oliver.

Figure 15

Delete Operation

757 @ C# Corner
Let’s delete Oliver's record. First fetch Oliver's record from the database, then simply call the
DeleteOnSubmit() method. Finally, to save changes to the database by calling the SubmitChanges()
method.

private void DeleteEmployee()


{
DataClasses1DataContext emp = new();
//Fetch an employee's record to be delete
Employee deleteEmployee = emp.Employees.FirstOrDefault(emp => emp.Emp_Name ==
"Oliver");
emp.Employees.DeleteOnSubmit(deleteEmployee);
//Save changes to the database.
emp.SubmitChanges();
}

Listing 7

Figure 16 shows the snapshot of the deleted record of Oliver.

Figure 16

Summary
We learned how to map databases from server to visual studio, then we saw how to map LINQ to SQL
data context. Later we saw how the operations read, insert, update and delete works with LINQ to SQL.

758 @ C# Corner
12.5 : Dapper

Our next ORM tool is dapper. Dapper is developed by stackoverflow, the forum for developers across
the globe. With previous ORM tools such as entity framework, we used LINQ to query on our database.
Now with dapper we can fire SQL queries straight from the client application, we will have to create
model classes to store the query result.

Let’s create a WPF application to perform CRUD operations on the database. If you remember, we have
a database named “WPFSimplifiedEmployeeDB”. Figure 1 is a snapshot of an Employee table where we
have 4 records to work with.

Figure 1

First thing first, go ahead and fire up visual studio and create a new WPF application, then right click on
a newly created app in solution explorer and open “NuGet package manager” and install Dapper as
shown in figure 2.

Figure 2

759 @ C# Corner
Now let’s create an application. Figure 3 is a snapshot of how our application would look like. Employee
details are where we need to fetch the records of all employees. Below is the registration form using
which we are going to create a new employee record. The Update button will update the employee
record based on employee ID mentioned in Emp ID TextBox and updates the information provided in
the form. The delete button will delete the employee’s record from the database by the employee ID
passed.

Figure 3

Open MainWindow.xaml and add the code snippet listed in listing 1. We are using DataTemplate for
ListView to show employee details, then below we have registration form to create a new employee
record, followed by 3 buttons for each operation insert, update and delete.
<Window x:Class="WPFSimplifiedDapper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFSimplifiedDapper"
mc:Ignorable="d" Background="#082032"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="EmployeeDataTemplate">
<StackPanel Orientation="Horizontal"
Width="430">
<TextBlock x:Name="TextBlockEmployeeDetail"
FontWeight="Bold" >
<Run Text=" | "/>
<Run Text="Emp Id: "

760 @ C# Corner
Foreground="#344CB7"/>
<Run Text="{Binding Emp_ID}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Name: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Name}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Designation: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Designation}"
Foreground="#CD1818"/>
<Run Text=" | Manager: "
Foreground="#344CB7"/>
</TextBlock>
<CheckBox IsChecked="{Binding IsManager}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>

<Grid HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock FontSize="15"
Foreground="#CEE5D0"
HorizontalAlignment="Left"
Margin="0 20 0 5"
Text="Employee details:"
Grid.ColumnSpan="1"/>
<ListView x:Name="ListViewAllEmployees"
HorizontalAlignment="Center" Background="#EEEEEE"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.ColumnSpan="1"
Grid.Row="1" />
<Border Background="#11324D"
BorderBrush="White"
BorderThickness="1,1,1,1"
CornerRadius="30,30,30,30"
HorizontalAlignment="Center"
Margin="0 20 0 0"
Grid.Row="2">
<Grid x:Name="GridPost"
Margin="10 10 10 0"
Width="330">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>

761 @ C# Corner
<RowDefinition Height="Auto"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelEmpID"
Content="Emp ID:"
Foreground="White"
Margin="0 10 0 0"/>
<Label x:Name="LabelEmployeeName"
Content="Employee Name:"
Foreground="White"
Grid.Row="1"/>
<Label x:Name="LabelDesignation"
Content="Designation:"
Foreground="White"
Grid.Row="2"/>
<Label x:Name="LabelManager"
Content="Manager:"
Foreground="White"
Grid.Row="3"/>
<TextBox x:Name="TextBoxEmpID"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>
<TextBox x:Name="TextBoxEmployeeName"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="1"/>
<TextBox x:Name="TextBoxDesignation"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>
<CheckBox x:Name="CheckBoxIsManager"
Margin="0 4 0 0"
Grid.Column="1"
Grid.Row="3"/>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Grid.Row="4"
Grid.ColumnSpan="2">
<Button x:Name="ButtonAddEmployee"
Background="#2E4C6D"
Click="ButtonAddEmployee_Click"
Content="Insert"
Foreground="White"
Height="20"
HorizontalAlignment="Center"

762 @ C# Corner
Width="100"/>
<Button x:Name="ButtonUpdateEmployee"
Background="#2E4C6D"
Click="ButtonUpdateEmployee_Click"
Content="Update"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
<Button x:Name="ButtonDeleteEmployee"
Background="#2E4C6D"
Click="ButtonDeleteEmployee_Click"
Content="Delete"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>

Listing 1

To perform SQL operations. We need SqlConnection class to establish the connection with the database
and this object accepts connection string as parameter. Before we do that, first install the
System.Data.SqlClient into your application, or you can create an instance of SqlConnection class and
install the package as highlighted in figure 3.

Figure 3

Next the connection string. Following code snippet is a string variable which defines the connection
string. First specify the source which is the path of the server then catalog which is the name of the

763 @ C# Corner
database and then credentials, since we have no external user credentials on our database we have
using Integrated Security the default windows authentication.
private readonly string SqlConnectionString = @"Data Source = localhost;initial
catalog=WPFSimplifiedEmployeeDB;Integrated Security=True";

Listing 2

Next we need an employee class as a model class to map with the employee table.

public class Employee


{
public int Emp_ID { get; set; }
public string Emp_Name { get; set; }
public string Emp_Designation { get; set; }
public bool IsManager { get; set; }
}

Listing 3

Get Operation
Following method gets all the records of employee table. Start with creating a list of employees which
will hold the result.

Then create a query, for this example we are fetching all the records so our query is pretty straight
forward.

Next, create an instance of the SqlConnection class and pass the SqlConnectionString that we created in
listing 2.

Then use the open method to open a database connection. Next use the query method of the type of
employee and pass the query string that we created. At last close the connection with close method and
assign the result the ItemSource of ListView.
/// <summary>
/// Get employee details
/// </summary>
private void GetEmployeeDetails()
{
List<Employee> employees = new();
string query = "Select * from Employee";
using SqlConnection connection = new(SqlConnectionString);
connection.Open();
employees = connection.Query<Employee>(query).ToList();
connection.Close();
ListViewAllEmployees.ItemsSource = employees;
}

764 @ C# Corner
Listing 3

Either you can call this method in the Window_Loaded event or in the constructor in
MainWindow.xaml.cs, now go ahead and run the application you’d see the result as shown in figure 4.

Figure 4

Insert Operation
First add a click event on the Insert Button. Then write the logic in click’s event handler as per listing 4.

At the first line we are converting the Boolean value of manager CheckBox to integers as our database
column IsManager stores a bit value.

Then creating an insert query to add a new employee record.

Then open the connection and call the Execute method, pass the query as parameter, now this method
returns the integer value indicating number of affected records . We are showing this integer value in
the message box. If the value is 0 which means the record has not been inserted.

/// <summary>
/// Insert an employee record into employee db
/// </summary>
/// <param name="employee"></param>
private void ButtonAddEmployee_Click(object sender, RoutedEventArgs e)
{
int isManager = (bool)CheckBoxIsManager.IsChecked ? 1 : 0;
string query = $"Insert into Employee values('{TextBoxEmpID.Text}',
'{TextBoxEmployeeName.Text}', '{TextBoxDesignation.Text}', {isManager})";
using SqlConnection connection = new(SqlConnectionString);
connection.Open();
int insertedRows = connection.Execute(query);
connection.Close();
MessageBox.Show("Number of rows inserted: " + insertedRows);
}

Listing 4

Now run the application, fill the details in the form and press the Insert button. You’d see the message
box as shown in figure 5. We are creating a new employee with employee id 5, name Stark and with

765 @ C# Corner
designation CEO, and since he is a CEO he can’t be manager so keeping manager’s checkbox uncheck
which is false.

Figure 5

Let’s cross check with our database. Figure 6 is a snapshot of our database after insert operation and as
you can see there is a new record added into the employee table.

Figure 6

Update Operation
First add a click event on the update Button. Then write the logic as per listing 5.

At the first line we are converting the Boolean value of manager CheckBox to integers as our database
column IsManager stores bit value.

Then creating an update query to update the employee record. In the query, notice that we are
updating the record by employee id.

766 @ C# Corner
Then open the connection and call the Execute method, pass the query as parameter. This method
returns the integer value indicating the number of records affected. We are showing this integer value
of the message box. If the value is 0 which means the record has not been inserted.

/// <summary>
/// updates employee record against given employee id
/// </summary>
/// <param name="employee"></param>
private void ButtonUpdateEmployee_Click(object sender, RoutedEventArgs e)
{
int isManager = (bool)CheckBoxIsManager.IsChecked ? 1 : 0;
string query = $"Update Employee set Emp_Name = '{TextBoxEmployeeName.Text}',
Emp_Designation = '{TextBoxDesignation.Text}', IsManager = {isManager} Where Emp_ID =
'{TextBoxEmpID.Text}'";
using SqlConnection connection = new(SqlConnectionString);
connection.Open();
int updatedRows = connection.Execute(query);
connection.Close();
MessageBox.Show("Number of rows updated: " + updatedRows);
}

Listing 5

In this example let’s update the record with employee id 5, so first enter 5 in the first field of form. Let's
change the employee name from Stark to Elon and the rest is the same. And click the update button.
You’d be able to see the result as per figure 6.

Figure 6

767 @ C# Corner
Let’s cross check the database, In figure 7 you can see the name for the 5th employee has been changed
to Elon.

Figure 7

Delete Operation
Delete operation is pretty straight forward. Delete the employee’s record by employee id and show the
number of deleted rows.
/// <summary>
/// Delete employee with specified Employee ID
/// </summary>
/// <param name="employeeID"></param>
private void ButtonDeleteEmployee_Click(object sender, RoutedEventArgs e)
{
string query = $"Delete from Employee Where Emp_ID = '{TextBoxEmpID.Text}'";
using SqlConnection connection = new(SqlConnectionString);
connection.Open();
var deletedRows = connection.Execute(query);
connection.Close();
MessageBox.Show("Number of rows deleted: " + deletedRows);
}

Listing 6

In figure 8, since we are deleting the 5th employee’s record we have entered 5 in Employee ID TextBox.
And then click on a delete button.

768 @ C# Corner
Figure
8

And as you can see in the database’s snapshot in figure 9 we have successfully deleted the employee’s
record with employee id 5.

Figure 9

Summary
In this chapter, we understood what dapper is, then we learnt fetch,insert, update, delete operations
with dapper with WPF application.

769 @ C# Corner
12.6: ADO.NET

ADO stands for ActiveX Data Object, developed by Microsoft to fill the gap between application and
data. We covered ADO.NET with entity framework and LINQ to SQL in previous chapters. In this chapter
we are going to cover 2 type data providers with ADO.NET, one is DataSet and another is SqlClient.

We can fire SQL queries directly from the application. We can also fire stored procedures to perform all
CRUD operations on the data on a server.

Let’s create a WPF application to perform CRUD operation on a database with ADO.NET. If you
remember, we have a database named “WPFSimplifiedEmployeeDB”. Figure 1 is a snapshot of an
Employee table. We have 4 records to work with.

Figure 1

Now let’s create an application. Figure 2 is a snapshot of how our application would look like. Employee
details are where we need to fetch the records of all employees. The below is the registration form
where we are going to create, update and delete an employee record. The Insert button will add the
new employee record into the employee table. The Update button will update the employee record
based on employee ID passed and updates the information provided in the form. The delete button will
delete the employee record from the database by employee ID passed.

770 @ C# Corner
Figure 2

Open MainWindow.xaml and add the code snippet listed below. We are using DataTemplate for
ListView to show employee details, then below we have a registration form to create a new employee
record, followed by 3 buttons for each operation.
<Window x:Class="WPFSimplifiedADONet.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFSimplifiedADONet"
mc:Ignorable="d" Background="#041C32"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="EmployeeDataTemplate">
<StackPanel Orientation="Horizontal"
Width="430">
<TextBlock x:Name="TextBlockEmployeeDetail"
FontWeight="Bold" >
<Run Text=" | "/>
<Run Text="Emp Id: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_ID}"
Foreground="#CD1818"/>

771 @ C# Corner
<Run Text=" | "/>
<Run Text="Name: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Name}"
Foreground="#CD1818"/>
<Run Text=" | "/>
<Run Text="Designation: "
Foreground="#344CB7"/>
<Run Text="{Binding Emp_Designation}"
Foreground="#CD1818"/>
<Run Text=" | Manager: "
Foreground="#344CB7"/>
</TextBlock>
<CheckBox IsChecked="{Binding IsManager}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>

<Grid HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock FontSize="15"
Foreground="#CEE5D0"
HorizontalAlignment="Left"
Margin="0 20 0 5"
Text="Employee details:"
Grid.ColumnSpan="1"/>
<ListView x:Name="ListViewAllEmployees"
HorizontalAlignment="Center" Background="#EEEEEE"
ItemTemplate="{StaticResource EmployeeDataTemplate}"
Grid.ColumnSpan="1"
Grid.Row="1" />
<Border Background="#11324D"
BorderBrush="White"
BorderThickness="1,1,1,1"
CornerRadius="30,30,30,30"
HorizontalAlignment="Center"
Margin="0 20 0 0"
Grid.Row="2">
<Grid x:Name="GridPost"
Margin="20 15 10 0"
Width="330">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>

772 @ C# Corner
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="LabelEmpID"
Content="Emp ID:"
Foreground="White"
Margin="0 10 0 0"/>
<Label x:Name="LabelEmployeeName"
Content="Employee Name:"
Foreground="White"
Grid.Row="1"/>
<Label x:Name="LabelDesignation"
Content="Designation:"
Foreground="White"
Grid.Row="2"/>
<Label x:Name="LabelManager"
Content="Manager:"
Foreground="White"
Grid.Row="3"/>
<TextBox x:Name="TextBoxEmpID"
Height="20"
Width="150"
Margin="0 10 0 0"
Grid.Column="1"/>
<TextBox x:Name="TextBoxEmployeeName"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="1"/>
<TextBox x:Name="TextBoxDesignation"
Height="20"
Width="150"
Grid.Column="1"
Grid.Row="2"/>
<CheckBox x:Name="CheckBoxIsManager"
Margin="15 4 0 0"
Grid.Column="1"
Grid.Row="3"/>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Grid.Row="4"
Grid.ColumnSpan="2">
<Button x:Name="ButtonAddEmployee"
Background="#2E4C6D"
Click="ButtonAddEmployee_Click"
Content="Insert"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Width="100"/>
<Button x:Name="ButtonUpdateEmployee"
Background="#2E4C6D"
Click="ButtonUpdateEmployee_Click"

773 @ C# Corner
Content="Update"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
<Button x:Name="ButtonDeleteEmployee"
Background="#2E4C6D"
Click="ButtonDeleteEmployee_Click"
Content="Delete"
Foreground="White"
Height="20"
HorizontalAlignment="Center"
Margin="10 0 0 0"
Width="100"/>
</StackPanel>
<TextBlock x:Name="TextBlockMessage"
Foreground="White"
HorizontalAlignment="Center"
Margin="20 8 0 10"
Grid.Row="5"
Grid.ColumnSpan="2"/>
</Grid>
</Border>
</Grid>
</Window>

Listing 1

774 @ C# Corner
Once you have the UI ready, we can move towards adding ADO.NET’s DataSet to the project. Open
server explorer right clicks on data connections and clicks on a “Add connection” menu. It will open the
dialog box shown in figure 3.

Figure 3

Once you have the database mapped, you can click on newly added tables, and it will open the design of
the selected table as shown in figure 4.

775 @ C# Corner
Figure 4

Now we need to map this table to our wpf project. And for that we need a DataSet. To achieve this, right
click on a wpf project, select Add new item and under the data section, select DataSet. Refer figure 5 for
the same.

776 @ C# Corner
Figure 5

Now double click and open the newly added xsd file and drag the employee table and drop it on the file.
This will map tables to wpf projects. As you can see from figure 6, we have added employee table to our
project.

777 @ C# Corner
Figure 6

We need an employee class as a model class to map with the employee table.
public class Employee
{
public int Emp_ID { get; set; }
public string Emp_Name { get; set; }
public string Emp_Designation { get; set; }
public bool IsManager { get; set; }
}

Listing 3

778 @ C# Corner
Get/ Read Operation
Following method gets all the records from the employee table. In this method first you need to create a
list of employees which will hold the result. Then create an instance of a dataset and map it with
EmployeeDataSetTableAdapters’s object by calling its fill method. Then loop through all the rows of the
table, So in our example as we have 4 employees, loop will run 4 times.

For every iteration, create a new employee’s object and add it to the list of employees.

Note: While fetching the data you can either use index number or you can use the name of table, or
column. To demonstrate how it works we are using an index for table, which represents table 0, which
in our case is an employee table, then for every column of the employee table we are specifying column
name.

It is always good practice to use table names in square brackets instead of numbers, because this is easy
to read.

Finally, assign the result to the ItemSource of ListView.

private void GetEmployeeDetails()


{
List<Employee> employees = new();
EmployeeDataSet dataSet = new();
EmployeeDataSetTableAdapters.EmployeeTableAdapter employeeTableAdapter = new();
employeeTableAdapter.Fill(dataSet.Employee);

for (int i=0; i<dataSet.Tables[0].Rows.Count; i++)


{
employees.Add(new Employee()
{
Emp_ID = Convert.ToInt32(dataSet.Tables[0].Rows[i]["Emp_ID"]),
Emp_Designation = dataSet.Tables[0].Rows[i]["Emp_Designation"].ToString(),
Emp_Name = dataSet.Tables[0].Rows[i]["Emp_Name"].ToString(),
IsManager = Convert.ToBoolean(dataSet.Tables[0].Rows[i]["IsManager"])
});
}
ListViewAllEmployees.ItemsSource = employees;

Listing 4

Now call this method in the Window_Loaded event or call it in the constructor in MainWindow.xaml.cs,
go ahead and run the application you’d see the result as shown in figure 7.

779 @ C# Corner
Figure 7

ADO.NET with SqlClient


To perform SQL operations. We need a SqlConnection object to establish the connection with the
database and this object accepts connection string as parameter. Before we do that, first install the
System.Data.SqlClient into your application, or you can create an instance of SqlConnection and install
the package as highlighted in figure 8.

Figure 8

Next the connection string. Following code snippet is a string variable which defines the connection
string. First specify the source which is the path of the server then catalog which is the name of the
database and since we have no external user credentials on our database, we have using Integrated
Security the default windows authentication.
private readonly string SqlConnectionString = @"Data Source = localhost;initial
catalog=WPFSimplifiedEmployeeDB;Integrated Security=True";

Listing 5

780 @ C# Corner
Insert/ Create Operation
On a click event of Insert button, write the logic as per listing 6.

At the first line we are converting the Boolean value of manager CheckBox to integers as our database
column IsManager stores bit value. Then creating an insert query to add a new employee record. Then
create SqlConnection’s object and pass the connectionstring that we created in listing 5.

Later create an instance of SqlCommand which will take the query and SqlConnection’s object as a
parameter Finally open the connection to the database with an open method, Call ExecuteNonQuery
method and close the connection. The ExecuteNonQuery method returns the integer value indicating
the number of records affected. We are showing this integer value of the message box. If the value is 0
which means the record has not been inserted.

At last, we are calling GetEmployeeDetails() to show newly added records on UI.

/// <summary>
/// Insert an employee record into employee db
/// </summary>
/// <param name="employee"></param>
private void ButtonAddEmployee_Click(object sender, RoutedEventArgs e)
{
int isManager = (bool)CheckBoxIsManager.IsChecked ? 1 : 0;
string query = $"Insert into Employee values('{TextBoxEmpID.Text}',
'{TextBoxEmployeeName.Text}', '{TextBoxDesignation.Text}', {isManager})";
using SqlConnection connection = new(SqlConnectionString);
SqlCommand command = new(query, connection);
connection.Open();
int insertedRows = command.ExecuteNonQuery();
connection.Close();
MessageBox.Show("Number of rows inserted: " + insertedRows);
GetEmployeeDetails();
}

Listing 6

Now run the application, fill the details in the form and press the Insert button. You’d see the message
box as shown in figure 5. We are creating a new employee with employee id 5, name Bill and with
designation as CEO, and he is a manager too so keeping the manager's checkbox check which is true.

781 @ C# Corner
Figure 9

Now just click the OK button on a MessageBox, then List will get updated with newly added Bill’s record.

Figure 10

782 @ C# Corner
Let’s cross check with our database. Figure 11 is a snapshot taken of our database after an insert
operation and as you can see there is a new record added into the employee table.

Figure 11

Update Operation
First, add a click event on the update Button. Then write the logic as per listing 7. Same as above we
begin with converting Boolean value of manager CheckBox to integers as our database column
IsManager stores bit value. Then creating an update query to update the employee record. In the query,
notice that we are updating the record by employee id.

Rest pattern is the same as listing 6.

/// <summary>
/// updates employee record against given employee id
/// </summary>
/// <param name="employee"></param>
private void ButtonUpdateEmployee_Click(object sender, RoutedEventArgs e)
{
int isManager = (bool)CheckBoxIsManager.IsChecked ? 1 : 0;
string query = $"Update Employee set Emp_Name = '{TextBoxEmployeeName.Text}',
Emp_Designation = '{TextBoxDesignation.Text}', IsManager = {isManager} Where Emp_ID =
'{TextBoxEmpID.Text}'";
using SqlConnection connection = new(SqlConnectionString);
SqlCommand command = new(query, connection);
connection.Open();
int updatedRows = command.ExecuteNonQuery();
connection.Close();
MessageBox.Show("Number of rows updated: " + updatedRows);
GetEmployeeDetails();
}

Listing 7

In this example let’s update the record with employee id 5, so first enter 5 in the first field of form. Let's
change the designation of Bill to developer, and as he is now a developer he is no longer manager so
let’s uncheck that. And click the update button. You’d be able to see the result as per figure 12.

783 @ C# Corner
Figure 12

Now just click the OK button on a MessageBox, then List will get updated with newly updated Bill’s
record.

Figure 13

784 @ C# Corner
Let’s cross check the database, In figure 14 you can see the 5th employee’s record has been updated.

Figure 14

Delete Operation
Delete operation is pretty straight forward. Delete the employee’s record by employee id and show the
number of deleted rows.

/// <summary>
/// Delete employee with specified Employee ID
/// </summary>
/// <param name="employeeID"></param>
private void ButtonDeleteEmployee_Click(object sender, RoutedEventArgs e)
{
string query = $"Delete from Employee Where Emp_ID = '{TextBoxEmpID.Text}'";
using SqlConnection connection = new(SqlConnectionString);
SqlCommand command = new(query, connection);
connection.Open();
var deletedRows = command.ExecuteNonQuery();
connection.Close();
MessageBox.Show("Number of rows deleted: " + deletedRows);
GetEmployeeDetails();
}

Listing 8

In figure 15, since we are deleting the 5th employee’s record we have entered 5 in Employee ID TextBox.
And then click on a delete button.

785 @ C# Corner
Figure 15

Now just click the OK button on a MessageBox, then List will get updated without Bill’s record.

Figure 16

786 @ C# Corner
And as you can see in the database we have successfully deleted the employee’s record with employee
id 5.

Figure 17

Summary
In this chapter we learned how to map databases with ADO.NET. We created a WPF application to
demonstrate CRUD operations with DataSet and SQLconnection.

787 @ C# Corner
OUR MISSION
Free Education is Our Basic Need! Our mission is to empower millions of developers worldwide by
providing the latest unbiased news, advice, and tools for learning, sharing, and career growth. We’re
passionate about nurturing the next young generation and help them not only to become great
programmers, but also exceptional human beings.

ABOUT US
CSharp Inc, headquartered in Philadelphia, PA, is an online global community of software
developers. C# Corner served 29.4 million visitors in year 2021. We publish the latest news and articles
on cutting-edge software development topics. Developers share their knowledge and connect via
content, forums, and chapters. Thousands of members benefit from our monthly events, webinars,
and conferences. All conferences are managed under Global Tech Conferences, a CSharp
Inc sister company. We also provide tools for career growth such as career advice, resume writing,
training, certifications, books and whitepapers, and videos. We also connect developers with their potential
employers via our Job board. Visit C# Corner

MORE BOOKS

You might also like