Universal Windows Platform – Tutorials – Set Three


Setup and Start

Setup and Start

Set Three


Input Dialog

Input Dialog

Access Keys

Access Keys

Light Effect

Light Effect

Shade Effect

Shade Effect

Lucky Dominoes

Lucky Dominoes

Lucky Roshambo

Lucky Roshambo

Deal or Not

Deal or Not

High or Low

High or Low

Codes Game

Codes Game

Flags Game

Flags Game

Chase Game

Chase Game

Slide Game

Slide Game

GifView App

GifView App

PdfView App

PdfView App

JpgInfo App

JpgInfo App

ZipFile App

ZipFile App

Operator App

Operator App

Speaking App

Speaking App

Calendar App

Calendar App

Contacts App

Contacts App

Custom TextBox

Custom TextBox

Custom ComboBox

Custom ComboBox

Matrix Control

Matrix Control

Lights Control

Lights Control

Stacked Control

Stacked Control

Directs Control

Directs Control

Uniform Control

Uniform Control

Docking Control

Docking Control

Badges

Badges

Tile Output

Tile Styles

Toast Styles

Toast Styles

Database

Database

Set Two


Custom Dialog

Custom Dialog

Navigation View

Navigation View

Drag and Drop

Drag and Drop

Photo Rotate

Photo Rotate

Lucky Roulette

Lucky Roulette

Lucky Bingo

Lucky Bingo

Hit or Miss

Hit or Miss

Four in Row

Four in Row

Fruit Game

Fruit Game

Light Game

Light Game

Order Game

Order Game

Sound Game

Sound Game

Appointment App

Appointment App

Cryptograph App

Cryptograph App

Compression App

Compression App

Recognition App

Recognition App

Tailored App

Tailored App

Adaptive App

Adaptive App

Keyboard App

Keyboard App

Jsonfile App

Jsonfile App

Custom Checkbox

Custom Checkbox

Custom Toggle

Custom Toggle

Segment Control

Segment Control

Radial Control

Radial Control

Offset Control

Offset Control

Gauge Control

Gauge Control

Font Control

Font Control

Colour Control

Colour Control

Cortana Command

Cortana Command

Tile Output

Tile Output

Toast Input

Toast Input

Spotify

Spotify

Set One


Hello World

Hello World

Command Bar

Command Bar

Data Input

Data Input

Image Rotate

Image Rotate

Lucky Dice

Lucky Dice

Lucky Lotto

Lucky Lotto

Noughts and Crosses

Noughts and Crosses

Memory Game

Memory Game

Touch Game

Touch Game

Playing Cards

Playing Cards

Web Browser

Web Browser

RSS Reader

RSS Reader

Text Editor

Text Editor

Rich Editor

Rich Editor

Task Editor

Task Editor

Draw Editor

Draw Editor

Slide Player

Slide Player

Media Player

Media Player

Audio Recorder

Audio Recorder

Video Recorder

Video Recorder

Custom Button

Custom Button

Custom Slider

Custom Slider

Clock Control

Clock Control

Carousel Control

Carousel Control

Wrap Control

Wrap Control

Dial Control

Dial Control

Flip Control

Flip Control

Expand Control

Expand Control

Location

Location

Tiles

Tiles

Toasts

Toasts

Agent

Agent

Source Code

Source Code
Advertisements

Universal Windows Platform – Database

Toast Styles demonstrates how to display the different types of Toast notifications that are possible to be displayed in the Action Centre in Windows 10

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in a Name and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

From the Menu choose Tools, then NuGet Package Manager and Manage NuGet Packages for Solution…

vs2017-tools-nuget-package-manager-manage-nuget-packages

Step 6

Then in NuGet select Browse and search for Microsoft.Data.SQLite as indicated and select Microsoft.Data.SQLite by Microsoft and then check the box under Project as indicated and select Install.

vs2017-nuget-database

Step 7

Then if Preview Changes is displayed, select Ok

vs2017-nuget-preview-changes-database

Step 8

License Acceptance will then be displayed, read through the terms displayed then to continue, select I Accept to Install the NuGet Package.

vs2017-nuget-license-database

Step 9

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 10

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Library.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 11

Once in the Code View for Library.cs the following should be entered:

using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

public class Item
{
    public int Id { get; set; }
    public string Album { get; set; }
    public string Artist { get; set; }
    public string Genre { get; set; }
}

public class Library
{
    private const string field_id = "@Id";
    private const string field_album = "@Album";
    private const string field_artist = "@Artist";
    private const string field_genre = "@Genre";
    private const string connection_string = "Filename=database.db";
    private const string table_create = "CREATE TABLE IF NOT EXISTS Items " +
        "(Id INTEGER PRIMARY KEY AUTOINCREMENT, " +
        "Album NVARCHAR(255) NULL, Artist NVARCHAR(255) NULL, Genre NVARCHAR(255) NULL)";
    private const string table_insert = "INSERT INTO Items VALUES (NULL, @Album, @Artist, @Genre)";
    private const string table_update = "UPDATE Items SET Album = @Album, " +
        "Artist = @Artist, Genre = @Genre WHERE Id = @Id";
    private const string table_delete = "DELETE FROM Items WHERE Id = @Id";
    private const string table_select = "SELECT Id, Album, Artist, Genre FROM Items";

    private async Task<Item> Dialog(Item item)
    {
        Thickness margin = new Thickness(5);
        TextBlock id = new TextBlock()
        {
            Text = item.Id.ToString(),
            Margin = margin,
        };
        TextBox album = new TextBox()
        {
            Text = item.Album ?? string.Empty,
            Margin = margin,
            PlaceholderText = "Album"
        };
        TextBox artist = new TextBox()
        {
            Text = item.Artist ?? string.Empty,
            Margin = margin,
            PlaceholderText = "Artist"
        };
        TextBox genre = new TextBox()
        {
            Text = item.Genre ?? string.Empty,
            Margin = margin,
            PlaceholderText = "Genre"
        };
        StackPanel panel = new StackPanel()
        {
            Orientation = Orientation.Vertical
        };
        panel.Children.Add(id);
        panel.Children.Add(album);
        panel.Children.Add(artist);
        panel.Children.Add(genre);
        ContentDialog dialog = new ContentDialog()
        {
            Title = "Database",
            PrimaryButtonText = "Save",
            CloseButtonText = "Cancel",
            Content = panel
        };
        ContentDialogResult result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            item.Album = album.Text;
            item.Artist = artist.Text;
            item.Genre = genre.Text;
            return item;
        }
        return null;
    }

    private async Task<bool> AddItemAsync(Item item)
    {
        bool result = false;
        using (SqliteConnection connection = new SqliteConnection(connection_string))
        {
            await connection.OpenAsync();
            SqliteCommand insert = new SqliteCommand()
            {
                Connection = connection,
                CommandText = table_insert
            };
            insert.Parameters.AddWithValue(field_album, item.Album);
            insert.Parameters.AddWithValue(field_artist, item.Artist);
            insert.Parameters.AddWithValue(field_genre, item.Genre);
            try
            {
                await insert.ExecuteScalarAsync();
                result = true;
            }
            catch (SqliteException)
            {
                result = false;
            }
            connection.Close();
        }
        return result;
    }

    private async Task<bool> EditItemAsync(Item item)
    {
        bool result = false;
        using (SqliteConnection connection = new SqliteConnection(connection_string))
        {
            await connection.OpenAsync();
            SqliteCommand insert = new SqliteCommand()
            {
                Connection = connection,
                CommandText = table_update
            };
            insert.Parameters.AddWithValue(field_id, item.Id);
            insert.Parameters.AddWithValue(field_album, item.Album);
            insert.Parameters.AddWithValue(field_artist, item.Artist);
            insert.Parameters.AddWithValue(field_genre, item.Genre);
            try
            {
                await insert.ExecuteScalarAsync();
                result = true;
            }
            catch (SqliteException)
            {
                result = false;
            }
            connection.Close();
        }
        return result;
    }

    private async Task<bool> DeleteItemAsync(Item item)
    {
        bool result = false;
        using (SqliteConnection connection = new SqliteConnection(connection_string))
        {
            await connection.OpenAsync();
            SqliteCommand delete = new SqliteCommand()
            {
                Connection = connection,
                CommandText = table_delete
            };
            delete.Parameters.AddWithValue(field_id, item.Id);
            try
            {
                await delete.ExecuteNonQueryAsync();
                result = true;
            }
            catch (SqliteException)
            {
                result = false;
            }
            connection.Close();
        }
        return result;
    }

    public async Task<bool> CreateAsync()
    {
        bool result = false;
        using (SqliteConnection connection = new SqliteConnection(connection_string))
        {
            await connection.OpenAsync();
            SqliteCommand create = new SqliteCommand(table_create, connection);
            try
            {
                await create.ExecuteNonQueryAsync();
                result = true;
            }
            catch (SqliteException)
            {
                result = false;
            }
            connection.Close();
        }
        return result;
    }

    public async Task<List<Item>> ListAsync()
    {
        List<Item> results = new List<Item>();
        using (SqliteConnection connection = new SqliteConnection(connection_string))
        {
            await connection.OpenAsync();
            SqliteCommand select = new SqliteCommand(table_select, connection);
            try
            {
                SqliteDataReader query = await select.ExecuteReaderAsync();
                while (query.Read())
                {
                    Item item = new Item()
                    {
                        Id = query.GetInt32(0),
                        Album = query.GetString(1),
                        Artist = query.GetString(2),
                        Genre = query.GetString(3)
                    };
                    results.Add(item);
                }
            }
            catch (SqliteException)
            {
                results = null;
            }
            connection.Close();
        }
        return results;
    }

    public async Task<bool> AddAsync()
    {
        Item item = await Dialog(new Item());
        if (item != null)
        {
            return await AddItemAsync(item);
        }
        return false;
    }

    public async Task<bool> EditAsync(AppBarButton button)
    {
        Item item = await Dialog((Item)button.Tag);
        if (item != null)
        {
            return await EditItemAsync(item);
        }
        return false;
    }

    public async Task<bool> DeleteAsync(AppBarButton button)
    {
        Item item = (Item)button.Tag;
        if (item != null)
        {
            return await DeleteItemAsync(item);
        }
        return false;
    }
}

The NuGet package Microsoft.Data.SQLite is used in the Project and used in the Library.cs – there’s a Item class that defines the object to be stored in the Database with “Id”, “Album”, “Artist” and “Genre” properties. In the Library Class there are some const defining the fields that are in the Database for parameterised queries, the “connection_string” for the database and the SQL instructions to Create the Database and to Insert, Update, Delete and Select data from the Database. There’s a Dialog method which takes an Item Object as a parameter for editing then defines a TextBox for each property of the Item Class plus a TextBlock to show the “Id” and returns the Item Object.

The AddItemAsync method takes in an Item Object then uses the SqliteConnection to connect to the Database then opens it with OpenAsync and then sets up an Insert with an SqliteCommand and sets the Parameters to be the string properties from the Item Class and then Executes the Command with ExecuteScalarAsync. EditItemAsync takes in an Item Object then uses the SqliteConnection to connect to the Database then Opens it with OpenAsync and then sets up an Update with an SqliteCommand and sets the Parameters to be all the properties from the Item Class and then Executes the Command with ExecuteScalarAsync.

The DeleteItemAsync method takes in an Item Object then uses the SqliteConnection to connect to the Database then Opens it with OpenAsync and then sets up a Delete with an SqliteCommand and sets the Parameters to be the “Id” from the Item Class and then Executes the Command with ExecuteNonQueryAsync. CreateAsync uses the SqliteConnection to connect to the Database then opens it with OpenAsync and then sets up the a Create with an SqliteCommand and then Executes the Command with ExecuteNonQueryAsync. ListAsync uses the SqliteConnection to connect to the Database then Opens it with OpenAsync and then sets up a Select with an SqliteCommand and then Executes the Command with ExecuteReaderAsync with a SqliteDataReader, then While it can Read from the results it creates an Item from the returned Columns and add them to the results – this is returned as a List of Item.

There’s an AddAsync method that uses Dialog to create a new Item and this is passed to the AddItemAsync method to be added to the Database, EditAsync uses the passed in AppBarButton which has an Item bound to the “Tag” Property of it then passes this into the Dialog method and then used with the EditItemAsync method to update the Database. DeleteAsync uses the passed in AppBarButton which has an Item bound to the “Tag” Property of it then passes this into the DeleteItemAsync method to remove it from the Database.

Step 12

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-database

Step 13

From the Menu choose View and then Designer

vs2017-view-designer

Step 14

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<ListBox Margin="50" Name="Display">
	<ListBox.ItemContainerStyle>
		<Style TargetType="ListBoxItem">
			<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
		</Style>
	</ListBox.ItemContainerStyle>
	<ListBox.ItemTemplate>
		<DataTemplate>
			<Grid>
				<Grid.ColumnDefinitions>
					<ColumnDefinition Width="Auto"/>
					<ColumnDefinition Width="20*"/>
					<ColumnDefinition Width="20*"/>
					<ColumnDefinition Width="20*"/>
					<ColumnDefinition Width="Auto"/>
				</Grid.ColumnDefinitions>
				<Grid Padding="5" Grid.Column="0" Background="{ThemeResource AccentButtonBackground}">
					<TextBlock Text="{Binding Id}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonForeground}"/>
				</Grid>
				<Grid Padding="5" Grid.Column="1" Background="{ThemeResource AccentButtonForeground}">
					<TextBlock Text="{Binding Album}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonBackground}"/>
				</Grid>
				<Grid Padding="5" Grid.Column="2" Background="{ThemeResource AccentButtonForeground}">
					<TextBlock Text="{Binding Artist}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonBackground}"/>
				</Grid>
				<Grid Padding="5" Grid.Column="3" Background="{ThemeResource AccentButtonForeground}">
					<TextBlock Text="{Binding Genre}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonBackground}"/>
				</Grid>
				<StackPanel Grid.Column="4" Orientation="Horizontal">
					<AppBarButton Name="Edit" Icon="Edit" Label="Edit" Tag="{Binding}" Click="Edit_Click"/>
					<AppBarButton Name="Delete" Icon="Delete" Label="Delete" Tag="{Binding}" Click="Delete_Click"/>
				</StackPanel>
			</Grid>
		</DataTemplate>
	</ListBox.ItemTemplate>
</ListBox>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Add" Label="Add" Click="Add_Click"/>
</CommandBar>

The MainPage has an AppBarButton for Add – this will show the Dialog to add a new Item into the Database. Then theres a ListBox that will have a list of Item set to it’s DataSource and has a DataTemplate that displays a list of Id, Album, Artist and Genre for each Item in the Database plus an AppBarButton for Edit and Delete.

Step 15

From the Menu choose View and then Code

vs2017-view-code

Step 16

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

Library library = new Library();

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
	await library.CreateAsync();
	Display.ItemsSource = await library.ListAsync();
}

private async void Add_Click(object sender, RoutedEventArgs e)
{
	if (await library.AddAsync())
	{
		Display.ItemsSource = await library.ListAsync();
	}
}

private async void Edit_Click(object sender, RoutedEventArgs e)
{
	if (await library.EditAsync((AppBarButton)sender))
	{
		Display.ItemsSource = await library.ListAsync();
	}
}

private async void Delete_Click(object sender, RoutedEventArgs e)
{
	if (await library.DeleteAsync((AppBarButton)sender))
	{
		Display.ItemsSource = await library.ListAsync();
	}
}

Below the MainPage() Method an instance of the Library Class is created, OnNavigatedTo is Called when the MainPage is Displayed and calls the CreatAsync and ListAsync Methods in the Library Class. Add_Click, Edit_Click and Delete_Click call their respective methods in the Library Class and ListAsync to set the ItemsSource of the ListBox.

Step 17

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 18

After the Application has started running you can then select Add to create a new Item, this will display a Dialog where you can enter the Album, Artist and Genre. Items added will be displayed in the List where you can Edit or Delete them.

ran-database

Step 19

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Although this is just a basic example of creating and using a Database it shows how straight-forward it is to have data be persistable in an application – anything added will be recalled on subsequent runs of the Application unless deleted for example. This brings back an example from an older set of Tutorials done for Visual Basic many years ago and here it is updated for today using SQLite Database.

Creative Commons License

Universal Windows Platform – Toast Styles

Toast Styles demonstrates how to display the different types of Toast notifications that are possible to be displayed in the Action Centre in Windows 10

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in a Name and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Library.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for Library.cs the following should be entered:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

public class Item
{
    public string Style { get; set; }
    public string Value { get; set; }
}

public class Library
{
    public IEnumerable<string> GetTemplates()
    {
        return Enum.GetValues(typeof(ToastTemplateType))
            .Cast<ToastTemplateType>().Select(s => s.ToString());
    }

    private void UpdateToast(Item item)
    {
        ToastTemplateType template = (ToastTemplateType)Enum.Parse(typeof(ToastTemplateType), item.Style);
        XmlDocument toast = ToastNotificationManager.GetTemplateContent(template);
        XmlNodeList text = toast.GetElementsByTagName("text");
        if (text.Length > 0)
        {
            text[0].AppendChild(toast.CreateTextNode(item.Value));
        }
        XmlNodeList image = toast.GetElementsByTagName("image");
        if (image.Length > 0)
        {
            image[0].Attributes.GetNamedItem("src").NodeValue =
            "Assets/Square44x44Logo.scale-200.png";
        }
        ToastNotification notification = new ToastNotification(toast);
        ToastNotificationManager.CreateToastNotifier().Show(notification);
    }

    private async Task<Item> DialogAsync()
    {
        ComboBox template = new ComboBox()
        {
            HorizontalAlignment = HorizontalAlignment.Stretch,
            Margin = new Thickness(5),
            ItemsSource = GetTemplates()
        };
        template.SelectedIndex = 0;
        TextBox text = new TextBox()
        {
            PlaceholderText = "Text",
            Margin = new Thickness(5)
        };
        StackPanel panel = new StackPanel()
        {
            Orientation = Orientation.Vertical
        };
        panel.Children.Add(template);
        panel.Children.Add(text);
        ContentDialog dialog = new ContentDialog()
        {
            Title = "Toast Styles",
            PrimaryButtonText = "Update",
            CloseButtonText = "Cancel",
            Content = panel
        };
        ContentDialogResult result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            return new Item() { Style = (string)template.SelectedItem, Value = text.Text };
        }
        return null;
    }

    public async void Toast()
    {
        Item result = await DialogAsync();
        if (result != null)
        {
            UpdateToast(result);
        }
    }
}

There’s a GetTemplates method to get the ToastTemplateType then returns those as an IEnumerable of string. UpdateToast takes a string “style” and “value” – the former is used to get the correct ToastTemplateType based on the style passed in, the latter is used to create a node for the template to represent the value used on the Toast, a ToastNotification is created from this and passed to the Update method of the ToastNotificationManager with CreateToastNotifier. The Dialog has a ComboBox set to the templates using GetTemplates and has a TextBox to enter the value to show – the selected template and value is returned as an Item Class which here is a pair of string values for each of those selections.

The Toast method uses the Dialog method to get the Tuple that contains the selected template and value to use and this is passed to the UpdateToast method from the “result” of the Dialog.

Step 8

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 9

From the Menu choose View and then Designer

vs2017-view-designer

Step 10

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Comment" Label="Toast" Click="Toast_Click"/>
</CommandBar>

The MainPage has a CommandBar with an AppBarButton of Toast which will display the Dialog to then display a Toast Notification in the Action Centre in Windows 10

Step 11

From the Menu choose View and then Code

vs2017-view-code

Step 12

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

Library library = new Library();

private void Toast_Click(object sender, RoutedEventArgs e)
{
	library.Toast();
}

Below the MainPage() Method an instance of the Library Class is created, then Toast_Click is used to call the Toast Method from the Library Class.

Step 13

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 14

After the Application has started running you can then select Toast display a Dialog where you select Style from the ComboBox and Text.

ran-toast-styles

Step 15

The Toast will be displayed in Windows 10 in the Action Centre with the Text entered.

ran-toast-styles

Step 16

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Toast Styles shows how you can use the built-in templates for creating toast notifications in different ways, there are more options in some of the templates to product more complex layouts and this example is just the start of showing how flexable toast notifications can be and how easy it is to update them, makes a great feature of an application that needs to show something with a toast in a variety of different ways.

Creative Commons License

Universal Windows Platform – Tile Styles

Tile Styles demonstrates how to display the different types of Tile notifications that are possible for an application’s pinned Tile in Windows 10

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in a Name and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Library.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for Library.cs the following should be entered:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
using Windows.UI.StartScreen;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

public class Item
{
    public string Style { get; set; }
    public string Value { get; set; }
}

public class Library
{
    public IEnumerable<string> GetTemplates()
    {
        return Enum.GetValues(typeof(TileTemplateType)).Cast<TileTemplateType>()
        .Select(s => s.ToString()).Distinct();
    }

    private void UpdateTile(Item item)
    {
        TileTemplateType template = (TileTemplateType)Enum.Parse(typeof(TileTemplateType), item.Style);
        XmlDocument tile = TileUpdateManager.GetTemplateContent(template);
        XmlNodeList text = tile.GetElementsByTagName("text");
        if (text.Length > 0)
        {
            for (int i = 0; i < text.Length; i++)
            {
                text[i].AppendChild(tile.CreateTextNode(item.Value));
            }
        }
        XmlNodeList image = tile.GetElementsByTagName("image");
        if (image.Length > 0)
        {
            for (int i = 0; i < image.Length; i++)
            {
                image[i].Attributes.GetNamedItem("src").NodeValue =
                "Assets/Square44x44Logo.scale-200.png";
            }
        }
        TileNotification notification = new TileNotification(tile);
        string output = tile.GetXml();
        TileUpdateManager.CreateTileUpdaterForApplication().Update(notification);
    }

    private async Task<Item> DialogAsync()
    {
        ComboBox template = new ComboBox()
        {
            HorizontalAlignment = HorizontalAlignment.Stretch,
            Margin = new Thickness(5),
            ItemsSource = GetTemplates()
        };
        template.SelectedIndex = 0;
        TextBox text = new TextBox()
        {
            PlaceholderText = "Text",
            Margin = new Thickness(5)
        };
        StackPanel panel = new StackPanel()
        {
            Orientation = Orientation.Vertical
        };
        panel.Children.Add(template);
        panel.Children.Add(text);
        ContentDialog dialog = new ContentDialog()
        {
            Title = "Tile Styles",
            PrimaryButtonText = "Update",
            CloseButtonText = "Cancel",
            Content = panel
        };
        ContentDialogResult result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            return new Item() { Style = (string)template.SelectedItem, Value = text.Text };
        }
        return null;
    }

    public async Task<bool> PinAsync()
    {
        bool isPinned = false;
        AppListEntry entry = (await Package.Current.GetAppListEntriesAsync()).FirstOrDefault();
        if (entry != null)
        {
            isPinned = await StartScreenManager.GetDefault().ContainsAppListEntryAsync(entry);
        }
        if (!isPinned)
        {
            isPinned = await StartScreenManager.GetDefault().RequestAddAppListEntryAsync(entry);
        }
        return isPinned;
    }

    public async void Tile()
    {
        Item result = await DialogAsync();
        if (result != null)
        {
            UpdateTile(result);
        }
    }
}

There’s a GetTemplates method to get the TileTemplateType and then return those that contain the value “Text” so that only supported templates are returned. UpdateTile takes a string “style” and “value” – the former is used to get the correct TileTemplateType based on the style passed in, the latter is used to create a node for the template to represent the value used on the Tile, a TileNotification is created from this and passed to the Update method of the TileUpdateManager with CreateTileUpdaterForApplication. The Dialog method has a ComboBox set to the templates using GetTemplates and has a TextBox to enter the value to show – the selected template and value is returned as an Item Class which has a pair of string values for each of those selections.

The PinAsync method determines if the application is pinned to start with the GetAppListEntriesAsync from the Package.Current with ContainsAppListEntryAsync from the StartScreenManager.GetDefault method and if not uses the RequestAddAppListEntryAsync to pin the application to start. The Tile method uses the Dialog method to get the Item Class that contains the selected template and value to use and this is passed to the UpdateTile method from the “result” of the Dialog.

Step 8

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 9

From the Menu choose View and then Designer

vs2017-view-designer

Step 10

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Pin" Label="Pin" Click="Pin_Click"/>
	<AppBarButton Icon="SetTile" Label="Tile" Click="Tile_Click"/>
</CommandBar>

The MainPage has a CommandBar with two AppBarButton Controls, Pin to perform Pin-to-Start and Tile which will show the Dialog to update the Application’s Tile on the Start Menu in Windows 10

Step 11

From the Menu choose View and then Code

vs2017-view-code

Step 12

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

Library library = new Library();

private async void Pin_Click(object sender, RoutedEventArgs e)
{
	await library.PinAsync();
}

private void Tile_Click(object sender, RoutedEventArgs e)
{
	library.Tile();
}

Below the MainPage() Method an instance of the Library Class is created, then Pin_Click is used to call the PinAsync Method from the Library Class and Tile_Click the Tile Method.

Step 13

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 14

After the Application has started running you can then select Pin to pin-to-start the Application and then select Tile display a Dialog where you select Style from the ComboBox and Text.

ran-tile-styles

Step 15

The Tile will be displayed in Windows 10 on the Start Menu for the Application using the Template with the Text entered.

ran-tile-styles

Step 16

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Tile Styles shows how you can use the built-in templates for updating tiles in different ways, there are more options in some of the templates to product more complex layouts and this example is just the start of showing how flexable tile notifications can be and how easy it is to update them, makes a great feature of an application that needs to show something on it’s tile in a variety of different ways.

Creative Commons License

Universal Windows Platform – Badges

Badges demonstrates how to display Badges in Windows 10 these are small notifications that appear on the icon for an application either on the Task Bar Icon or Pinned Tile of an Application.

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in a Name and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Library.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for Library.cs the following should be entered:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
using Windows.UI.StartScreen;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

public class Library
{
    private readonly List<string> glyphs = new List<string>
    {
        "number", "activity", "alarm", "attention", "available", "away",
        "busy", "error", "newMessage", "paused", "playing", "unavailable"
    };

    private async Task<string> DialogAsync()
    {
        ComboBox glyph = new ComboBox()
        {
            HorizontalAlignment = HorizontalAlignment.Stretch,
            Margin = new Thickness(5),
            ItemsSource = glyphs
        };
        glyph.SelectedIndex = 0;
        TextBox number = new TextBox()
        {
            PlaceholderText = "Number",
            Margin = new Thickness(5)
        };
        StackPanel panel = new StackPanel()
        {
            Orientation = Orientation.Vertical
        };
        panel.Children.Add(glyph);
        panel.Children.Add(number);
        ContentDialog dialog = new ContentDialog()
        {
            Title = "Badges",
            PrimaryButtonText = "Update",
            CloseButtonText = "Cancel",
            Content = panel
        };
        ContentDialogResult result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            string selected = (string)glyph.SelectedItem;
            return (selected == "number") ? number.Text : selected;
        }
        return null;
    }

    private void UpdateBadge(string value)
    {
        bool isNumber = int.TryParse(value, out int number);
        XmlDocument badge = BadgeUpdateManager.GetTemplateContent(isNumber ?
            BadgeTemplateType.BadgeNumber : BadgeTemplateType.BadgeGlyph);
        XmlNodeList attributes = badge.GetElementsByTagName("badge");
        IXmlNode node = attributes[0].Attributes.GetNamedItem("value");
        node.NodeValue = value;
        BadgeNotification notification = new BadgeNotification(badge);
        BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(notification);
    }

    public async Task<bool> PinAsync()
    {
        bool isPinned = false;
        AppListEntry entry = (await Package.Current.GetAppListEntriesAsync()).FirstOrDefault();
        if (entry != null)
        {
            isPinned = await StartScreenManager.GetDefault().ContainsAppListEntryAsync(entry);
        }
        if (!isPinned)
        {
            isPinned = await StartScreenManager.GetDefault().RequestAddAppListEntryAsync(entry);
        }
        return isPinned;
    }

    public async void Badge()
    {
        string result = await DialogAsync();
        if (result != null)
        {
            UpdateBadge(result);
        }
    }
}

There’s a list of string for the glyphs supported by a Badge, then a Dialog method that has a ComboBox set to those “glyphs” and a TextBox where a number can be entered between 1 and 99 and returns the entered value as a string. The UpdateBadge method takes a string and checks if this is numeric then gets the template for either BadgeNumber or BadgeGlyph based on this value then the “value” is set to the passed in value and a BadgeNotification created from this and passed to the Update method of the BadgeUpdateManager with CreateBadgeUpdaterForApplication.

The PinAsync method determines if the application is pinned to start with the GetAppListEntriesAsync from the Package.Current with ContainsAppListEntryAsync from the StartScreenManager.GetDefault method and if not uses the RequestAddAppListEntryAsync to pin the application to start. The Badge method uses the Dialog method to get the value to use on a Badge and uses the UpdateBadge method with the “result” of the the Dialog.

Step 8

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 9

From the Menu choose View and then Designer

vs2017-view-designer

Step 10

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Name="Pin" Icon="Pin" Label="Pin" Click="Pin_Click"/>
	<AppBarButton Icon="SetTile" Label="Badge" Click="Badge_Click"/>
</CommandBar>

The MainPage has a CommandBar with two AppBarButton Controls, Pin to perform Pin-to-Start and Badge which will show the Dialog to update the Application’s Badge on the Task Bar or Tile

Step 11

From the Menu choose View and then Code

vs2017-view-code

Step 12

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

Library library = new Library();

private async void Pin_Click(object sender, RoutedEventArgs e)
{
	await library.PinAsync();
}

private void Badge_Click(object sender, RoutedEventArgs e)
{
	library.Badge();
}

Below the MainPage() Method an instance of the Library Class is created, then Pin_Click is used to call the PinAsync Method from the Library Class and Badge_Click the Badge Method.

Step 13

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 14

After the Application has started running you can then select Pin to pin-to-start the Application and then select Badge display a Dialog where you select Number or Glyph from the ComboBox and Number to use if that option has been selected from the ComboBox.

ran-badges

Step 15

The Badge will be displayed in Windows 10 on the TaskBar or the Pinned Tile for the Application.

ran-badges

Step 16

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Badges show how easy it is to use this kind of notification – the majority of examples for this tended to be in Javascript mostly but this shows how straight-forward it is to do it from C# instead and the example is based from the official documentation for updated Badges.

Creative Commons License

Universal Windows Platform – Docking Control

Docking Control demonstrates how to create a DockingPanel which is a Panel where the elements can be docked to the Top, Bottom, Left or Right of the Control.

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in the Name as DockingControl and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as DockingPanel.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for DockingPanel.cs the following should be entered:

using System;
using System.Globalization;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace DockingControl
{
    public class DockingPanel : Panel
    {
        private static bool _ignorePropertyChange;

        public enum Dock
        {
            Left = 0,
            Top = 1,
            Right = 2,
            Bottom = 3
        }

        private static void OnLastChildFillPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            if (d is DockingPanel panel)
                panel.InvalidateArrange();
        }

        private static void OnDockPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (_ignorePropertyChange)
            {
                _ignorePropertyChange = false;
                return;
            }
            UIElement element = (UIElement)d;
            Dock value = (Dock)e.NewValue;
            if ((value != Dock.Left) && (value != Dock.Top) &&
                (value != Dock.Right) && (value != Dock.Bottom))
            {
                _ignorePropertyChange = true;
                element.SetValue(DockProperty, (Dock)e.OldValue);
                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "InvalidValue", value), "value");
            }
            if (VisualTreeHelper.GetParent(element) is DockingPanel panel)
                panel.InvalidateMeasure();
        }

        public static readonly DependencyProperty LastChildFillProperty =
        DependencyProperty.Register("LastChildFill", typeof(bool),
        typeof(DockingPanel), new PropertyMetadata(true, OnLastChildFillPropertyChanged));

        public static readonly DependencyProperty DockProperty =
        DependencyProperty.RegisterAttached("Dock", typeof(Dock),
        typeof(DockingPanel), new PropertyMetadata(Dock.Left, OnDockPropertyChanged));

        public bool LastChildFill
        {
            get { return (bool)GetValue(LastChildFillProperty); }
            set { SetValue(LastChildFillProperty, value); }
        }

        public static Dock GetDock(UIElement element)
        {
            if (element == null) throw new ArgumentNullException("element");
            return (Dock)element.GetValue(DockProperty);
        }

        public static void SetDock(UIElement element, Dock dock)
        {
            if (element == null) throw new ArgumentNullException("element");
            element.SetValue(DockProperty, dock);
        }

        protected override Size ArrangeOverride(Size size)
        {
            double left = 0.0;
            double top = 0.0;
            double right = 0.0;
            double bottom = 0.0;
            UIElementCollection children = Children;
            int count = children.Count - (LastChildFill ? 1 : 0);
            int index = 0;
            foreach (UIElement element in children)
            {
                Rect rect = new Rect(left, top,
                  Math.Max(0.0, size.Width - left - right),
                  Math.Max(0.0, size.Height - top - bottom));
                if (index < count)
                {
                    Size desiredSize = element.DesiredSize;
                    switch (GetDock(element))
                    {
                        case Dock.Left:
                            left += desiredSize.Width;
                            rect.Width = desiredSize.Width;
                            break;
                        case Dock.Top:
                            top += desiredSize.Height;
                            rect.Height = desiredSize.Height;
                            break;
                        case Dock.Right:
                            right += desiredSize.Width;
                            rect.X = Math.Max(0.0, size.Width - right);
                            rect.Width = desiredSize.Width;
                            break;
                        case Dock.Bottom:
                            bottom += desiredSize.Height;
                            rect.Y = Math.Max(0.0, size.Height - bottom);
                            rect.Height = desiredSize.Height;
                            break;
                    }
                }
                element.Arrange(rect);
                index++;
            }
            return size;
        }

        protected override Size MeasureOverride(Size size)
        {
            double width = 0.0;
            double height = 0.0;
            double maxWidth = 0.0;
            double maxHeight = 0.0;
            foreach (UIElement element in Children)
            {
                Size remainingSize = new Size(
                    Math.Max(0.0, size.Width - width),
                    Math.Max(0.0, size.Height - height));
                element.Measure(remainingSize);
                Size desired = element.DesiredSize;
                switch (GetDock(element))
                {
                    case Dock.Left:
                    case Dock.Right:
                        maxHeight = Math.Max(maxHeight, height + desired.Height);
                        width += desired.Width;
                        break;
                    case Dock.Top:
                    case Dock.Bottom:
                        maxWidth = Math.Max(maxWidth, width + desired.Width);
                        height += desired.Height;
                        break;
                }
            }
            maxWidth = Math.Max(maxWidth, width);
            maxHeight = Math.Max(maxHeight, height);
            return new Size(maxWidth, maxHeight);
        }
    }
}

The DockingPanel Class Inherits the Panel Class and then has a bool value for ignoring property changes then defines an enum for the “Dock” positions of Left, Top, Right and Bottom. There’s an OnLastChildFillPropertyChanged event handler to call InvalidateArrange and OnDockPropertyChanged event handler which checkes the “_ignorePropertyChange” value and returns if true or gets the UIElement and checks the NewValue and adjusts the DockProperty accordingly based on it being none of the Dock values and then calls the InvalidateMeasure if needed if it’s a nested Docking Control.

There’s a pair of DependencyProperty for LastChildFill and Dock which set the relevent bool and Dock values. ArrangeOverride responds to Size changes that require the layout to be updated and goes through all the UIElement Children and creates a Rect to then get the correct sizes based on the Dock value to set the correct Width or Height. MeasureOverride returns a Size based on working out for each UIElement of the control and getting the correct sizes based on the Dock values and works out the Size to return based from the calculated “maxWidth” and “maxHeight”.

Step 8

Once done select from the Menu, Build, then Build Solution

vs2017-build-build-solution

Step 9

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 10

From the Menu choose View and then Designer

vs2017-view-designer

Step 11

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<Viewbox Margin="50">
	<local:DockingPanel HorizontalAlignment="Center" VerticalAlignment="Center">
		<Rectangle Width="100" Height="100" Fill="Red" Margin="10" local:DockingPanel.Dock="Top"/>
		<Rectangle Width="100" Height="100" Fill="Orange" Margin="10" local:DockingPanel.Dock="Bottom"/>
		<Rectangle Width="100" Height="100" Fill="Yellow" Margin="10" local:DockingPanel.Dock="Left"/>
		<Rectangle Width="100" Height="100" Fill="Green" Margin="10" local:DockingPanel.Dock="Right"/>
		<Rectangle Width="100" Height="100" Fill="Cyan" Margin="10"/>
	</local:DockingPanel>
</Viewbox>

The MainPage has a Viewbox with the DockingPanel Control itself with the Children set to a set of Rectangle Controls.

Step 12

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 13

After the Application has started it should then appear displaying the UniformPanel Control with some items where the size of each element is determined by the first item in the control

ran-docking-control

Step 14

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Docking Control is based off the Dock Panel in the Silverlight Toolkit by Microsoft although with the Metro, Modern and Fluent design language progression this control doesn’t fit with the current guidelines for interfaces in general based on the Universal Windows Platform but it may still be useful for certain pages within an application where being able to dock elements to the Top, Bottom, Left or Right.

Creative Commons License

Universal Windows Platform – Uniform Control

Uniform Control demonstrates how to create a UniformPanel where all the elements in the Panel are sized the same way based from the first item in the panel.

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in the Name as UniformControl and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as UniformPanel.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for UniformPanel.cs the following should be entered:

using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace UniformControl
{
    public class UniformPanel : Panel
    {
        private int _columns;
        private int _rows;

        public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register("Columns", typeof(int),
        typeof(UniformPanel), new PropertyMetadata(0));

        public static readonly DependencyProperty FirstColumnProperty =
        DependencyProperty.Register("FirstColumn", typeof(int),
        typeof(UniformPanel), new PropertyMetadata(0));

        public static readonly DependencyProperty RowsProperty =
        DependencyProperty.Register("Rows", typeof(int),
        typeof(UniformPanel), new PropertyMetadata(0));

        public int Columns
        {
            get { return (int)GetValue(ColumnsProperty); }
            set { SetValue(ColumnsProperty, value); }
        }

        public int FirstColumn
        {
            get { return (int)GetValue(FirstColumnProperty); }
            set { SetValue(FirstColumnProperty, value); }
        }

        public int Rows
        {
            get { return (int)GetValue(RowsProperty); }
            set { SetValue(RowsProperty, value); }
        }

        private void UpdateComputedValues()
        {
            _columns = Columns;
            _rows = Rows;
            if (FirstColumn >= _columns) FirstColumn = 0;
            if ((_rows == 0) || (_columns == 0))
            {
                var row = 0;
                var column = 0;
                int count = Children.Count;
                while (column < count)
                {
                    UIElement element = Children[column];
                    if (element.Visibility != Visibility.Collapsed)
                    {
                        row++;
                    }
                    column++;
                }
                if (row == 0) row = 1;
                if (_rows == 0)
                {
                    if (_columns > 0)
                    {
                        _rows = ((row + FirstColumn) + (_columns - 1)) / _columns;
                    }
                    else
                    {
                        _rows = (int)Math.Sqrt(row);
                        if ((_rows * _rows) < row)
                        {
                            _rows++;
                        }
                        _columns = _rows;
                    }
                }
                else if (_columns == 0)
                {
                    _columns = (row + (_rows - 1)) / _rows;
                }
            }
        }

        protected override Size ArrangeOverride(Size size)
        {
            Rect rectangle = new Rect(0.0, 0.0,
            size.Width / _columns, size.Height / _rows);
            double width = rectangle.Width;
            double value = size.Width - 1.0;
            rectangle.X += rectangle.Width * FirstColumn;
            foreach (UIElement element in Children)
            {
                element.Arrange(rectangle);
                if (element.Visibility != Visibility.Collapsed)
                {
                    rectangle.X += width;
                    if (rectangle.X >= value)
                    {
                        rectangle.Y += rectangle.Height;
                        rectangle.X = 0.0;
                    }
                }
            }
            return size;
        }

        protected override Size MeasureOverride(Size size)
        {
            UpdateComputedValues();
            Size available = new Size(size.Width / (_columns), size.Height / (_rows));
            double width = 0.0;
            double height = 0.0;
            int value = 0;
            int count = Children.Count;
            while (value < count)
            {
                UIElement element = Children[value];
                element.Measure(available);
                Size desired = element.DesiredSize;
                if (width < desired.Width) width = desired.Width;
                if (height < desired.Height) height = desired.Height;
                value++;
            }
            return new Size(width * _columns, height * _rows);
        }
    }
}

The UniformPanel Class Inherits the Panel class and then has Columns, FirstColumn and Rows properties. The UpdateComputedValues method gets the Columns and Rows and adjusts the layout accordingly based on the Visibility of the elements to produce the correct number of Rows and Columns needed. ArrangeOverride respnds to Size changes that require the layout to be updated and arranges these based from a Rect from the Width and Height plus the number of rows and columns. MeasureOverride returns a Size by first using UpdateComputedValues then setting the Available size and then resizing each Child of the control to be the desired Size value.

Step 8

Once done select from the Menu, Build, then Build Solution

vs2017-build-build-solution

Step 9

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 10

From the Menu choose View and then Designer

vs2017-view-designer

Step 11

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<Viewbox Margin="50">
	<local:UniformPanel HorizontalAlignment="Center" VerticalAlignment="Center">
		<Rectangle Width="75" Height="75" Fill="Black" Margin="5"/>
		<Rectangle Width="75" Height="75" Fill="Red"/>
		<Rectangle Width="75" Height="75" Fill="Orange"/>
		<Rectangle Width="75" Height="75" Fill="Yellow"/>
		<Rectangle Width="75" Height="75" Fill="Green"/>
		<Rectangle Width="75" Height="75" Fill="Cyan"/>
		<Rectangle Width="75" Height="75" Fill="Blue"/>
		<Rectangle Width="75" Height="75" Fill="Magenta"/>
		<Rectangle Width="75" Height="75" Fill="Purple"/>
	</local:UniformPanel>
</Viewbox>

The MainPage has a Viewbox with the UniformPanel Control itself with the Children set to a set of Rectangle Controls.

Step 12

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 13

After the Application has started it should then appear displaying the UniformPanel Control with some items where the size of each element is determined by the first item in the control

ran-uniform-control

Step 14

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Uniform Control is based off the Uniform Grid in the WinRTXamlToolkit by Filip Skakun and is quite a useful control to have, in the example all the other items in the control are sized based from the initial element so they all have a uniform size – this makes it easy to create proportional layouts with the correct spacing based on the largest elements, something that might come in useful when creating applications.

Creative Commons License

Universal Windows Platform – Directs Control

Directs Control demonstrates how to create a Directional Pad control and also indicate which direction has been selected.

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in the Name as DirectsControl and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Directs.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for Directs.cs the following should be entered:

using System;
using Windows.Devices.Input;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

namespace DirectsControl
{
    public class Directs : Grid
    {
        private const int size = 3;
        private const string path_up = "M 0,0 40,0 40,60 20,80 0,60 0,0 z";
        private const string path_down = "M 0,20 20,0 40,20 40,80 0,80 z";
        private const string path_left = "M 0,0 60,0 80,20 60,40 0,40 z";
        private const string path_right = "M 0,20 20,0 80,0 80,40 20,40 z";

        public enum Directions
        {
            Up = 0,
            Down = 1,
            Left = 2,
            Right = 3
        }

        public delegate void DirectionEvent(object sender, Directions direction);
        public event DirectionEvent Direction;

        public static readonly DependencyProperty ForegroundProperty =
        DependencyProperty.Register("Foreground", typeof(Brush),
        typeof(Directs), null);

        public Brush Foreground
        {
            get { return (Brush)GetValue(ForegroundProperty); }
            set { SetValue(ForegroundProperty, value); }
        }

        private Path StringToPath(string value)
        {
            return (Path)XamlReader.Load(
                $"<Path xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'><Path.Data>{value}</Path.Data></Path>"
            );
        }

        private void Path_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            PointerPoint point = e.GetCurrentPoint(this);
            bool fire = (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse) ?
                point.Properties.IsLeftButtonPressed : point.IsInContact;
            if (fire)
            {
                Path path = ((Path)sender);
                if (Direction != null)
                {
                    this.Direction(path, (Directions)Enum.Parse(typeof(Directions), path.Name));
                }
            }
        }

        private void Add(ref Grid grid,
            string name, string value, 
            int row, int column, 
            int? rowspan, int? columnspan,
            VerticalAlignment? vertical = null, 
            HorizontalAlignment? horizontal = null)
        {
            Path path = StringToPath(value);
            path.Name = name;
            path.Margin = new Thickness(5);
            if (vertical != null) path.VerticalAlignment = vertical.Value;
            if (horizontal != null) path.HorizontalAlignment = horizontal.Value;
            path.SetBinding(Path.FillProperty, new Binding()
            {
                Source = this,
                Path = new PropertyPath("Foreground"),
                Mode = BindingMode.TwoWay
            });
            path.PointerMoved += Path_PointerMoved;
            path.SetValue(Grid.RowProperty, row);
            path.SetValue(Grid.ColumnProperty, column);
            if (rowspan != null) path.SetValue(Grid.RowSpanProperty, rowspan);
            if (columnspan != null) path.SetValue(Grid.ColumnSpanProperty, columnspan);
            grid.Children.Add(path);
        }

        public Directs()
        {
            Grid grid = new Grid()
            {
                Height = 180,
                Width = 180
            };
            grid.Children.Clear();
            grid.ColumnDefinitions.Clear();
            grid.RowDefinitions.Clear();
            for (int index = 0; (index < size); index++)
            {
                grid.RowDefinitions.Add(new RowDefinition()
                {
                    Height = (index == 1) ? GridLength.Auto : new GridLength(100, GridUnitType.Star)
                });
                grid.ColumnDefinitions.Add(new ColumnDefinition()
                {
                    Width = (index == 1) ? GridLength.Auto : new GridLength(100, GridUnitType.Star)
                });
            }
            Add(ref grid, "Up", path_up, 0, 1, 2, null, VerticalAlignment.Top, null);
            Add(ref grid, "Down", path_down, 1, 1, 2, null, VerticalAlignment.Bottom, null);
            Add(ref grid, "Left", path_left, 1, 0, null, 2, null, HorizontalAlignment.Left);
            Add(ref grid, "Right", path_right, 1, 1, null, 2, null, HorizontalAlignment.Right);
            Viewbox box = new Viewbox()
            {
                Child = grid
            };
            this.Children.Add(box);
        }
    }
}

There are const Values for the string items for the shapes that will make up each part of the Directional Pad, then there’s an enum to represent the Directions, a DirectionEvent for when the Direction changes and a DependencyProperty for the Foreground of the Control. There is a Method to convert the shapes into a Path to be displayed and a Path_PointerMoved Method that will respond to Events raised by each part of the Directional Pad, the Add Method is used to create each part of the Directional Pad and is used by the Directs Constructor to create the look-and-feel of the Control create the Up, Down, Left and Right parts.

Step 8

Once done select from the Menu, Build, then Build Solution

vs2017-build-build-solution

Step 9

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 10

From the Menu choose View and then Designer

vs2017-view-designer

Step 11

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<StackPanel Margin="50" VerticalAlignment="Center" HorizontalAlignment="Center">
	<TextBlock Name="Label" HorizontalAlignment="Center" Style="{StaticResource SubtitleTextBlockStyle}"/>
	<local:Directs x:Name="Pad" Height="400" Width="400" Foreground="{ThemeResource AccentButtonBackground}" Direction="Pad_Direction"/>
</StackPanel>

The MainPage has a StackPanel with a TextBlock to indicate the Direction selected and the Directs Control itself with the Direction Event Handler set.

Step 12

From the Menu choose View and then Code

vs2017-view-code

Step 13

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

private void Pad_Direction(object sender, Directs.Directions direction)
{
	Label.Text = direction.ToString();
}

Below the MainPage() Method there is the Pad_Direction Event Handler which will set the TextBlock to be the Direction selected by the Directs Control

Step 14

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 15

After the Application has started running you can then select the parts of the Directs Control for Up, Down, Left and Right.

ran-directs-control

Step 16

To Exit the Application select the Close button in the top right of the Application

vs2017-close

This control shows how to create a control that emulates the behaviour of a physical Directional Pad – that is when you press a Direction it continues to register that Direction plus when it’s changed to another one, this can be with a continuous press of a Mouse, Pen or Touch to switch between the different directions. Although this example is simple and just displays display text in a Label to show the Direction, it could form the basis of a game controller.

Creative Commons License

Universal Windows Platform – Stacked Control

Stacked Control demonstrates how to create a Control to display values in the form of a horizontal stacked bar chart – in this case displaying the first few values of the famous Fibonacci sequence.

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in the Name as StackedControl and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Stacked.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for Stacked.cs the following should be entered:

using System.Collections.Generic;
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

namespace StackedControl
{
    public class Stacked : Grid
    {
        private List<double> _items = new List<double>();

        private List<double> Percentages()
        {
            List<double> results = new List<double>();
            double total = _items.Sum();
            foreach (double item in _items)
            {
                results.Add((item / total) * 100);
            }
            return results.OrderBy(o => o).ToList();
        }

        private Rectangle GetRectangle(Color colour, int column)
        {
            Rectangle rect = new Rectangle()
            {
                Fill = new SolidColorBrush(colour)
            };
            rect.SetValue(Grid.ColumnProperty, column);
            return rect;
        }

        private void Layout()
        {
            List<double> percentages = Percentages();
            this.ColumnDefinitions.Clear();
            for (int index = 0; index < percentages.Count(); index++)
            {
                double percentage = percentages[index];
                ColumnDefinition column = new ColumnDefinition()
                {
                    Width = new GridLength(percentage, GridUnitType.Star)
                };
                this.ColumnDefinitions.Add(column);
                Color colour = (index < Palette.Count()) ? Palette[index] : Colors.Black;
                this.Children.Add(GetRectangle(colour, index));
            }
        }

        public List<Color> Palette { get; set; } = new List<Color>();

        public List<double> Items
        {
            get { return _items; }
            set { _items = value; Layout(); }
        }

        public void Fibonacci(params Color[] colours)
        {
            Palette = colours.ToList();
            int fibonacci(int value) => value > 1 ?
            fibonacci(value - 1) + fibonacci(value - 2) : value;
            Items = Enumerable.Range(0, Palette.Count())
            .Select(fibonacci).Select(s => (double)s).ToList();
        }
    }
}

The Stacked Class itself which inherits from a Grid and has a List of double to represent the values of the Chart. Tne Percentages Method works out the percentage of each item that’s needed for the Chart based on it’s Value, GetRectangle is used to get a Rectangle to use as a Chart item, Layout is used to create the look-and-feel of the Chart, Pallette is the List of Color to be used in the Chart and a Property which encapsulates the Chart items. There’s a Fibonacci Method which allows the Chart to be populated based on the values of the Fibonacci sequence.

Step 8

Once done select from the Menu, Build, then Build Solution

vs2017-build-build-solution

Step 9

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 10

From the Menu choose View and then Designer

vs2017-view-designer

Step 11

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<local:Stacked Margin="50" x:Name="Display"/>

The MainPage just has the Stacked Control itself.

Step 12

From the Menu choose View and then Code

vs2017-view-code

Step 13

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

protected override void OnNavigatedTo(NavigationEventArgs e)
{            
	Display.Fibonacci(
	Windows.UI.Colors.Black,
	Windows.UI.Colors.Gray,
	Windows.UI.Colors.Red,
	Windows.UI.Colors.Orange,
	Windows.UI.Colors.Yellow,
	Windows.UI.Colors.Green,
	Windows.UI.Colors.Cyan,
	Windows.UI.Colors.Blue,
	Windows.UI.Colors.Magenta,
	Windows.UI.Colors.Purple);
}

Below the MainPage() Method there is the OnNavigatedTo Event Handler which triggers the Fibonacci Method of the Stacked Control.

Step 14

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 15

After the Application has started it should then appear displaying a Stacked Chart displaying the first few numbers of the Fibonacci sequence

ran-stacked-control

Step 16

To Exit the Application select the Close button in the top right of the Application

vs2017-close

This Control is used to display some of the Fibonacci numbers as an example and has a basic colour palette set which the example uses to set how many item to add to the chart and it could be changed so you could also set an “Orientation” or style it in any way desired and used for things such as a space used indicator for example.

Creative Commons License

Universal Windows Platform – Lights Control

Lights Control demonstrates how to create a Lights Control to display indicator lights – in this case was used to display the sequence of lights for a UK Traffic Light.

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in the Name as LightsControl and select a Location and then select Ok to create the Project
vs2017-new-project-window

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Lights.cs before selecting Add to add the file to the Project

vs2017-add-new-item-library

Step 7

Once in the Code View for Lights.cs the following should be entered:

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

namespace LightsControl
{
    public class Light : Grid, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public static readonly DependencyProperty ForegroundProperty =
        DependencyProperty.Register("Foreground", typeof(Brush),
        typeof(Light), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

        public static readonly DependencyProperty SizeProperty =
        DependencyProperty.Register("Size", typeof(double),
        typeof(Light), new PropertyMetadata((double)100));

        public static readonly DependencyProperty OffProperty =
        DependencyProperty.Register("Off", typeof(Visibility),
        typeof(Light), new PropertyMetadata(Visibility.Collapsed));

        public Brush Foreground
        {
            get { return (Brush)GetValue(ForegroundProperty); }
            set
            {
                SetValue(ForegroundProperty, value);
                NotifyPropertyChanged("Foreground");
            }
        }

        public double Size
        {
            get { return (double)GetValue(SizeProperty); }
            set
            {
                SetValue(SizeProperty, value);
                NotifyPropertyChanged("Size");
            }
        }

        public Visibility Off
        {
            get { return (Visibility)GetValue(OffProperty); }
            set
            {
                SetValue(OffProperty, value);
                NotifyPropertyChanged("Off");
            }
        }

        public Light()
        {
            this.Margin = new Thickness(5);
            Ellipse element = new Ellipse()
            {
                Stretch = Stretch.Fill,
                Height = Size,
                Width = Size
            };
            element.SetBinding(Ellipse.FillProperty, new Binding()
            {
                Source = this,
                Path = new PropertyPath("Foreground"),
                Mode = BindingMode.TwoWay
            });
            Ellipse overlay = new Ellipse()
            {
                Fill = new SolidColorBrush(Colors.Black),
                Stretch = Stretch.Fill,
                Opacity = 0.75,
                Height = Size,
                Width = Size
            };
            overlay.SetBinding(Ellipse.VisibilityProperty, new Binding()
            {
                Source = this,
                Path = new PropertyPath("Off"),
                Mode = BindingMode.TwoWay
            });
            this.Children.Add(element);
            this.Children.Add(overlay);
        }

        public bool IsOn
        {
            get { return Off == Visibility.Collapsed; }
            set
            {
                Off = value ? Visibility.Collapsed : Visibility.Visible;
                NotifyPropertyChanged("IsOn");
                NotifyPropertyChanged("Off");
            }
        }
    }

    public class Lights : StackPanel
    {
        private Light _red = new Light { Foreground = new SolidColorBrush(Colors.Red) };
        private Light _orange = new Light { Foreground = new SolidColorBrush(Colors.Orange) };
        private Light _green = new Light { Foreground = new SolidColorBrush(Colors.Green) };

        private async Task<bool> Delay(int seconds = 2)
        {
            await Task.Delay(seconds * 1000);
            return true;
        }

        public Lights()
        {
            this.Orientation = Orientation.Vertical;
            this.Children.Add(_red);
            this.Children.Add(_orange);
            this.Children.Add(_green);
        }

        public async void Traffic()
        {
            _red.IsOn = false;
            _orange.IsOn = false;
            _green.IsOn = true;
            await Delay();
            _green.IsOn = false;
            await Delay();
            _orange.IsOn = true;
            await Delay();
            _orange.IsOn = false;
            await Delay();
            _red.IsOn = true;
            await Delay();
            _red.IsOn = true;
            await Delay();
            _orange.IsOn = true;
            await Delay();
            _red.IsOn = false;
            _orange.IsOn = false;
            _green.IsOn = true;
            await Delay();
        }
    }
}

There is a Light Class which implements the INotifyPropertyChanged Interface and contains a NotifyPropertyChanged Method to allow the Control to respond to updates, there are DependencyProperty and Properties for Foreground, Size and Off – this indicates if the Light should be enabled or not. The Light Constructor is used to create the look-and-feel of the Light itself and there is an IsOn Property to set the Off Property accordingly.

The Lights Class extends a StackPanel with three Light Controls within and a Delay Method which will be used to pause any output and a Traffic Method which contains the whole sequence for a traffic light – based on the UK traffic light sequence.

Step 8

Once done select from the Menu, Build, then Build Solution

vs2017-build-build-solution

Step 9

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-library

Step 10

From the Menu choose View and then Designer

vs2017-view-designer

Step 11

The Design View will be displayed along with the XAML View and in this between the Grid and /Grid elements, enter the following XAML:

<Viewbox>
	<local:Lights Margin="50" x:Name="Display" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Viewbox>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Play" Label="Play" Click="Play_Click"/>
</CommandBar>

The MainPage has the Lights Control itself along with a CommandBar with an AppBarButton to trigger the Play_Click Event.

Step 12

From the Menu choose View and then Code

vs2017-view-code

Step 13

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

private void Play_Click(object sender, RoutedEventArgs e)
{
	Display.Traffic();
}

Below the MainPage() Method there is the Play_Click Event Handler which triggers the Traffic Method of the Lights Control.

Step 14

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 15

After the Application has started running you can then select Play to go cycle through the UK traffic light sequence displayed using the Control.

ran-lights-control

Step 16

To Exit the Application select the Close button in the top right of the Application

vs2017-close

The Control is used to cycle through the light sequence from a UK Traffic light to demonstrate the principle of using the lights and to show they update accordingly and it could be expanded upon to display differently or as-is with more combinations of lights or appear more like traffic lights or even less like them to represent something else.

Creative Commons License