Universal Windows Platform – Custom TextBox

Custom Textbox demonstrates how to create a custom Style for a TextBox 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 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 the Project is created from the Solution Explorer select App.xaml

vs2017-app

Step 6

From the Menu choose View and then Designer

vs2017-view-designer

Step 7

Once in the Design View for App.xaml between the Application and /Application elements the following should be entered:

<Application.Resources>
	<Style x:Key="CustomTextBox" TargetType="TextBox">
		<Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}"/>
		<Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}"/>
		<Setter Property="Foreground" Value="Gold"/>
		<Setter Property="Background" Value="{ThemeResource TextControlBackground}"/>
		<Setter Property="SelectionHighlightColor" Value="{ThemeResource TextControlSelectionHighlightColor}"/>
		<Setter Property="BorderThickness" Value="2"/>
		<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
		<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
		<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto"/>
		<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto"/>
		<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
		<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
		<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
		<Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}"/>
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="TextBox">
					<Grid>
						<Grid.ColumnDefinitions>
							<ColumnDefinition Width="*"/>
							<ColumnDefinition Width="Auto"/>
						</Grid.ColumnDefinitions>
						<Grid.RowDefinitions>
							<RowDefinition Height="Auto"/>
							<RowDefinition Height="*"/>
						</Grid.RowDefinitions>
						<VisualStateManager.VisualStateGroups>
							<VisualStateGroup x:Name="CommonStates">
								<VisualState x:Name="Disabled">
									<Storyboard>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="HeaderContentPresenter">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlHeaderForegroundDisabled}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BorderElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundDisabled}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushDisabled}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundDisabled}"/>
										</ObjectAnimationUsingKeyFrames>
									</Storyboard>
								</VisualState>
								<VisualState x:Name="Normal"/>
								<VisualState x:Name="PointerOver">
									<Storyboard>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="GoldenRod"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BorderElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundPointerOver}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundPointerOver}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundPointerOver}"/>
										</ObjectAnimationUsingKeyFrames>
									</Storyboard>
								</VisualState>
								<VisualState x:Name="Focused">
									<Storyboard>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundFocused}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BorderElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocused}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="Gold"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundFocused}"/>
										</ObjectAnimationUsingKeyFrames>
										<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="RequestedTheme" Storyboard.TargetName="ContentElement">
											<DiscreteObjectKeyFrame KeyTime="0" Value="Light"/>
										</ObjectAnimationUsingKeyFrames>
									</Storyboard>
								</VisualState>
							</VisualStateGroup>
						</VisualStateManager.VisualStateGroups>
						<Border x:Name="BorderElement" BorderBrush="Salmon" BorderThickness="{TemplateBinding BorderThickness}" Background="LightSalmon" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="1" CornerRadius="15"/>
						<ScrollViewer x:Name="ContentElement" AutomationProperties.AccessibilityView="Raw" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
						HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
						IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Margin="{TemplateBinding BorderThickness}"
						Padding="{TemplateBinding Padding}" Grid.Row="1" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
						ZoomMode="Disabled"/>
						<ContentPresenter x:Name="PlaceholderTextContentPresenter" Grid.ColumnSpan="2" Content="{TemplateBinding PlaceholderText}" Foreground="Gold" IsHitTestVisible="False" Margin="{TemplateBinding BorderThickness}"
						Padding="{TemplateBinding Padding}" Grid.Row="1" TextWrapping="{TemplateBinding TextWrapping}"/>
					</Grid>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Application.Resources>

Within the App.xaml is defined an Application.Resources with a Style of “CustomTextBoxStyle” and a TargetType of TextBox – this example takes a copy of the style for the standard TextBox and customises many of the properties including Foreground set to “Gold”, during the VisualState of PointerOver a BorderBrush has been set to “GoldenRod” and the VisualState of Focused has the BorderBrush set to “Gold”.

The Border has the default BorderBrush set to “Salmon” and the Background to “LightSalmon” with a CornerRadius set to “15” and the ContentPresenter has the Foreground set to “Gold” – some other elements including the Header and DeleteButton have been removed to simplify the TextBox.

Step 8

In the Solution Explorer select MainPage.xaml

vs2017-mainpage

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:

<TextBox Text="TextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource CustomTextBox}"/>

The block of XAML represents the TextBox Control with the Style of the the CustomTextbox.

Step 11

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 12

After the Application has started running you can then select TextBox if not already and then type in some Text then you can deselect the TextBox once finished

ran-custom-checkbox

Step 13

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

vs2017-close

For this example Expression Blend was used to create a copy of the standard Style for a TextBox which was then customised with a look-and-feel that’s been used in previous tutorials just to demonstrate how different a standard input control can be modified, more sophisticated customisation is possible – the example is just the start of the idea of creating a completely custom look to an application by modifying controls in this way.

Creative Commons License

Advertisements

Universal Windows Platform – Contacts App

Contacts App demonstrates how to create an application which allows Contacts to be added, viewed, edited or deleted from an in-app Windows 10 Contacts List

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.Contacts;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

public class Item
{
    public string Id { get; set; }
    public string Address { get; set; }
    public string DisplayName { get; set; }
}

public class Library
{
    private const string app_title = "Contacts App";

    private async Task Store()
    {
        return await ContactManager.RequestStoreAsync(ContactStoreAccessType.AppContactsReadWrite);
    }

    private InputScope Scope(InputScopeNameValue value)
    {
        InputScope scope = new InputScope();
        InputScopeName name = new InputScopeName()
        {
            NameValue = value
        };
        scope.Names.Add(name);
        return scope;
    }

    private async Task Dialog(Contact contact)
    {
        Thickness margin = new Thickness(5);
        TextBox firstname = new TextBox()
        {
            Text = contact.FirstName,
            Margin = margin,
            PlaceholderText = "First Name"
        };
        TextBox lastname = new TextBox()
        {
            Text = contact.LastName,
            Margin = margin,
            PlaceholderText = "Last Name"
        };
        TextBox email = new TextBox()
        {
            Text = contact?.Emails?.FirstOrDefault()?.Address ?? string.Empty,
            Margin = margin,
            PlaceholderText = "Email Address",
            InputScope = Scope(InputScopeNameValue.EmailSmtpAddress)
        };
        StackPanel panel = new StackPanel()
        {
            Orientation = Orientation.Vertical
        };
        panel.Children.Add(firstname);
        panel.Children.Add(lastname);
        panel.Children.Add(email);
        ContentDialog dialog = new ContentDialog()
        {
            Title = "Contact",
            PrimaryButtonText = "Save",
            CloseButtonText = "Cancel",
            Content = panel
        };
        ContentDialogResult result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            contact.FirstName = firstname.Text;
            contact.LastName = lastname.Text;
            contact.Emails.Add(new ContactEmail() { Address = email.Text });
            return contact;
        }
        return null;
    }

    private async Task GetAsync()
    {
        ContactList result = null;
        ContactStore store = await Store();
        if (store != null)
        {
            IReadOnlyList list = await store.FindContactListsAsync();
            if (list.Count == 0)
            {
                result = await store.CreateContactListAsync(app_title);
            }
            else
            {
                result = list.FirstOrDefault(s => s.DisplayName == app_title);
            }
        }
        return result;
    }

    private async Task<IReadOnlyList> ListContactsAsync()
    {
        ContactStore store = await Store();
        if (store != null)
        {
            ContactList list = await GetAsync();
            if (list != null)
            {
                ContactReader reader = list.GetContactReader();
                if (reader != null)
                {
                    ContactBatch batch = await reader.ReadBatchAsync();
                    if (batch != null)
                    {
                        return batch.Contacts;
                    }
                }
            }
        }
        return null;
    }

    private async Task GetContactAsync(string id)
    {
        ContactList list = await GetAsync();
        if (list != null)
        {
            return await list.GetContactAsync(id);
        }
        return null;
    }

    public async Task<List> ListAsync()
    {
        List results = new List();
        IReadOnlyList contacts = await ListContactsAsync();
        foreach (Contact contact in contacts)
        {
            results.Add(new Item
            {
                Id = contact.Id,
                DisplayName = contact.DisplayName,
                Address = contact?.Emails?.FirstOrDefault()?.Address
            });
        }
        return results;
    }

    public async Task AddAsync(AppBarButton button)
    {
        Contact contact = await Dialog(new Contact());
        if (contact != null)
        {
            ContactList list = await GetAsync();
            if (list != null)
            {
                await list.SaveContactAsync(contact);
                return true;
            }
        }
        return false;
    }

    public async Task EditAsync(AppBarButton button)
    {
        Item item = (Item)button.Tag;
        Contact contact = await GetContactAsync(item.Id);
        if (contact != null)
        {
            contact = await Dialog(contact);
            if (contact != null)
            {
                ContactList list = await GetAsync();
                if (list != null)
                {
                    await list.SaveContactAsync(contact);
                    return true;
                }
            }
        }
        return false;
    }

    public async Task DeleteAsync(AppBarButton button)
    {
        Item item = (Item)button.Tag;
        Contact contact = await GetContactAsync(item.Id);
        if (contact != null)
        {
            ContactList list = await GetAsync();
            if (list != null)
            {
                await list.DeleteContactAsync(contact);
                return true;
            }
        }
        return false;
    }
}

There’s an Item class to store a string Id plus a string to store an Address and DisplayName for a Contact. The Library class has a const for the name of Contacts List, then there’s the ContactStore which is specific to the Application, there’s also a method Scope which returns InputScope based on a given InputScopeNameValue. The Dialog method has a Contact passed in and creates a ContentDialog with a given layout to include the First Name, Last Name and Email Address of a Contact object, it also returns the values that have been entered as a Contact when the Save button is selected.

The GetAsync method uses the ContactStore to get the ContactList for the application with FindContactListsAsync and creates one if it doesn’t exist with CreateContactListAsync, ListContactsAsync gets the a list of Contact from the ContactList via ContactReader with GetContactReader and ContactBatch with ReadBatchAsync. GetContactAsync gets an Contact from the ContactList with the GetContactAsync method. The ListAsync is used to populate the list of Item which is based from a list of Contact from the ListContactsAsync method. The Add method uses Dialog to create a new Contact and writes it to the ContactList with SaveContactAsync, Edit uses Dialog with an existing Contact from the list in the UI to make changes and then save this with SaveContactAsync and Delete will remove an existing Contact from the ContactList with the DeleteContactAsync method.

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:

<Grid Margin="50">
	<ListBox Name="Display" Loaded="Display_Loaded">
		<ListBox.ItemContainerStyle>
			<Style TargetType="ListBoxItem">
				<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
			</Style>
		</ListBox.ItemContainerStyle>
		<ListBox.ItemTemplate>
			<DataTemplate>
				<Grid>
					<Grid.ColumnDefinitions>
						<ColumnDefinition Width="40*"/>
						<ColumnDefinition Width="40*"/>
						<ColumnDefinition Width="Auto"/>
					</Grid.ColumnDefinitions>
					<Grid Padding="5" Grid.Column="0" Background="{ThemeResource AccentButtonBackground}">
						<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonForeground}"/>
					</Grid>
					<Grid Padding="5" Grid.Column="1" Background="{ThemeResource AccentButtonForeground}">
						<TextBlock Text="{Binding Address}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonBackground}"/>
					</Grid>
					<StackPanel Grid.Column="3" 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>
</Grid>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Name="Add" Icon="Add" Label="New" Click="Add_Click"/>
</CommandBar>

The MainPage has a Listbox to display Contacts with an ItemTemplate to define how this looks. The second block of XAML is is the CommandBar which contains Add – to add a Contact.

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 Display_Loaded(object sender, RoutedEventArgs e)
{
	Display.ItemsSource = await library.ListAsync();
}

private async void Add_Click(object sender, RoutedEventArgs e)
{
	if (await library.AddAsync(Add))
	{
		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, then Display_Loaded is used to set the ListBox to show Contacts, Add_Click is used to create Contacts then updates the ListBox which is also done by Edit_Click to amend an existing Contact and Delete_Click is used to remove a Contact.

Step 13

In the Solution Explorer select Package.appxmanifest

vs2017-mainpage

Step 14

From the Menu choose View and then Designer

vs2017-view-designer

Step 15

Finally in the Package.appxmanifest select Capabilities and then make sure the Contacts option is checked

vs2017-manifest-contacts-app

Step 16

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 17

After the Application has started running you can then select Add to create a new Contact, this will display a Dialog where you can enter the First Name, Last Name and Email Address for a Contact. Contacts added will be displayed in the List where you can Edit or Delete them.

ran-contacts-app

Step 18

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

vs2017-close

This example shows how easy it is to integrate with the built-in Contacts functionality of Windows 10 – you always need to provide your own UI to add / edit or view any Contacts but it’s quite straightforward to implement and is very similar to how Appointment works with Calendars. You can set many more properties of a Contact beyond those shown to add items such as multiple Email Address types and Telephone Numbers.

Creative Commons License

Universal Windows Platform – Calendar App

Calendar App demonstrates how to create an application which allows Appointments to be added, viewed, edited or deleted from an in-app Windows 10 Calendar.

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.Appointments;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

public class Item
{
    public string Id { get; set; }
    public DateTimeOffset StartTime { get; set; }
    public string When { get { return StartTime.ToString("dd MMMM yyyy HH:mm:ss"); } }
    public string Subject { get; set; }
    public string Details { get; set; }
}

public class Library
{
    private const string app_title = "Calendar App";

    private async Task Store()
    {
        return await AppointmentManager.RequestStoreAsync(AppointmentStoreAccessType.AppCalendarsReadWrite);
    }

    private DateTime GetDateTime(DateTimeOffset date, TimeSpan time)
    {
        return new DateTime(date.Year, date.Month, date.Day, time.Hours, time.Minutes, time.Seconds);
    }

    private async Task Dialog(Appointment appointment, ResourceDictionary resources)
    {
        Thickness margin = new Thickness(5);
        DatePicker date = new DatePicker()
        {
            Date = appointment.StartTime,
            Margin = margin,
            HorizontalAlignment = HorizontalAlignment.Stretch
        };
        TimePicker time = new TimePicker()
        {
            Time = appointment.StartTime.TimeOfDay,
            Margin = margin,
            HorizontalAlignment = HorizontalAlignment.Stretch
        };
        TextBox subject = new TextBox()
        {
            Text = appointment.Subject,
            Margin = margin,
            PlaceholderText = "Subject"
        };
        TextBox details = new TextBox()
        {
            Text = appointment.Details,
            Margin = margin,
            PlaceholderText = "Details",
            AcceptsReturn = true,
            TextWrapping = TextWrapping.Wrap,
            Height = (double)resources["SearchBoxSuggestionPopupThemeMaxHeight"]
        };
        StackPanel panel = new StackPanel()
        {
            Orientation = Orientation.Vertical
        };
        panel.Children.Add(date);
        panel.Children.Add(time);
        panel.Children.Add(subject);
        panel.Children.Add(details);
        ContentDialog dialog = new ContentDialog()
        {
            Title = "Appointment",
            PrimaryButtonText = "Save",
            CloseButtonText = "Cancel",
            Content = panel
        };
        ContentDialogResult result = await dialog.ShowAsync();
        if (result == ContentDialogResult.Primary)
        {
            appointment.StartTime = GetDateTime(date.Date, time.Time);
            appointment.Subject = subject.Text;
            appointment.Details = details.Text;
            return appointment;
        }
        return null;
    }

    private async Task GetAsync()
    {
        AppointmentCalendar result = null;
        AppointmentStore store = await Store();
        if (store != null)
        {
            IReadOnlyList list = await store.FindAppointmentCalendarsAsync();
            if (list.Count == 0)
            {
                result = await store.CreateAppointmentCalendarAsync(app_title);
            }
            else
            {
                result = list.FirstOrDefault(s => s.DisplayName == app_title);
            }
        }
        return result;
    }

    private async Task<IReadOnlyList> ListAppointmentsAsync(DateTimeOffset start, TimeSpan range)
    {
        AppointmentStore store = await Store();
        if (store != null)
        {
            AppointmentCalendar calendar = await GetAsync();
            if (calendar != null)
            {
                return await calendar.FindAppointmentsAsync(start, range);
            }
        }
        return null;
    }

    private async Task GetAppointmentAsync(string id)
    {
        AppointmentCalendar calendar = await GetAsync();
        if (calendar != null)
        {
            return await calendar.GetAppointmentAsync(id);
        }
        return null;
    }

    public void Start(ref CalendarDatePicker picker)
    {
        DateTime now = DateTime.Now;
        if (picker.Date == null)
        {
            picker.Date = GetDateTime(DateTime.Now, new TimeSpan(0, 0, 0));
        }
    }

    public async Task<List> ListAsync(DateTimeOffset start)
    {
        start = start.AddDays(-1);
        DateTimeOffset finish = start.AddMonths(1);
        TimeSpan range = finish - start;
        List results = new List();
        IReadOnlyList appointments = await ListAppointmentsAsync(start, range);
        foreach (Appointment appointment in appointments)
        {
            results.Add(new Item()
            {
                Id = appointment.LocalId,
                StartTime = appointment.StartTime,
                Subject = appointment.Subject,
                Details = appointment.Details
            });
        }
        return results;
    }

    public async Task AddAsync(AppBarButton button, ResourceDictionary resources)
    {
        Appointment appointment = await Dialog(new Appointment(), resources);
        if (appointment != null)
        {
            AppointmentCalendar calendar = await GetAsync();
            if (calendar != null)
            {
                await calendar.SaveAppointmentAsync(appointment);
                return true;
            }
        }
        return false;
    }

    public async Task EditAsync(AppBarButton button, ResourceDictionary resources)
    {
        Item item = (Item)button.Tag;
        Appointment appointment = await GetAppointmentAsync(item.Id);
        if (appointment != null)
        {
            appointment = await Dialog(appointment, resources);
            if (appointment != null)
            {
                AppointmentCalendar calendar = await GetAsync();
                if (calendar != null)
                {
                    await calendar.SaveAppointmentAsync(appointment);
                    return true;
                }
            }
        }
        return false;
    }

    public async Task DeleteAsync(AppBarButton button)
    {
        Item item = (Item)button.Tag;
        Appointment appointment = await GetAppointmentAsync(item.Id);
        if (appointment != null)
        {
            AppointmentCalendar calendar = await GetAsync();
            if (calendar != null)
            {
                await calendar.DeleteAppointmentAsync(item.Id);
                return true;
            }
        }
        return false;
    }
}

There’s an Item class to store a string Id plus a DateTimeOffset and string to store when appointment is for plus the Subject and Details as a string. The Library class has a const for the name of Appointment Calendar, then there’s the AppointmentStore which is specific to the Application, there’s also a method GetDateTime to get the Date and Time from a DateTimeOffset and TimeSpan. The Dialog method has an Appointment and ResourceDictionary passed in and creates a ContentDialog with a given layout to include the Date, Time, Subject and Details of an Appointment object, it also returns the values that have been entered as an Appointment when the Save button is selected.

The GetAsync method uses the AppointmentStore to get the AppointmentCalendar for the application with FindAppointmentCalendarsAsync and creates one if it doesn’t exist with CreateAppointmentCalendarAsync, ListAppointmentsAsync gets the a list of Appointment from the AppointmentCalendar within a given period from DateTimeOffsetStart to a TimeSpan range with FindAppointmentsAsync. GetAppointmentAsync gets an Appointment from the AppointmentCalendar with the GetAppointmentAsync method. Start is used to get the initial CalendarDatePicker date used by the UI to define the start date to display appointments from to be from today’s day – with DateTime.Now. ListAsync is used to populate the list of Item which is based from a list of Appointment from the ListAppointmentsAsync method. The Add method uses Dialog to create a new Appointment and writes it to the AppointmentCalendar with SaveAppointmentAsync, Edit uses Dialog with an existing Appointment from the list in the UI to make changes and then save this with SaveAppointmentAsync and Delete will remove an existing Appointment from the AppointmentCalendar with the DeleteAppointmentAsync method.

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:

<Grid Margin="50">
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="*"/>
	</Grid.RowDefinitions>
	<CalendarDatePicker Grid.Row="0" Name="Picker" HorizontalAlignment="Stretch"
	PlaceholderText="Display Appointments From" DateChanged="Picker_DateChanged"/>
	<ListBox Grid.Row="1" Name="Display" Loaded="Display_Loaded">
		<ListBox.ItemContainerStyle>
			<Style TargetType="ListBoxItem">
				<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
			</Style>
		</ListBox.ItemContainerStyle>
		<ListBox.ItemTemplate>
			<DataTemplate>
				<Grid>
					<Grid.ColumnDefinitions>
						<ColumnDefinition Width="40*"/>
						<ColumnDefinition Width="40*"/>
						<ColumnDefinition Width="Auto"/>
					</Grid.ColumnDefinitions>
					<Grid Padding="5" Grid.Column="0" Background="{ThemeResource AccentButtonBackground}">
						<TextBlock Text="{Binding When}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonForeground}"/>
					</Grid>
					<Grid Padding="5" Grid.Column="1" Background="{ThemeResource AccentButtonForeground}">
						<TextBlock Text="{Binding Subject}" VerticalAlignment="Center"
					Foreground="{ThemeResource AccentButtonBackground}"/>
					</Grid>
					<StackPanel Grid.Column="3" 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>
</Grid>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Name="Add" Icon="Add" Label="New" Click="Add_Click"/>
</CommandBar>

The MainPage has a Grid with two rows – the first is a CalendarDatePicker and the second is a Listbox to display Appointments with an ItemTemplate to define how this looks. The second block of XAML is is the CommandBar which contains Add – to add an Appointment.

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 Display_Loaded(object sender, RoutedEventArgs e)
{
	library.Start(ref Picker);
	Display.ItemsSource = await library.ListAsync((DateTimeOffset)Picker.Date);
}

private async void Picker_DateChanged(CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs args)
{
	Display.ItemsSource = await library.ListAsync((DateTimeOffset)Picker.Date);
}

private async void Add_Click(object sender, RoutedEventArgs e)
{
	if (await library.AddAsync(Add, App.Current.Resources))
	{
		Display.ItemsSource = await library.ListAsync((DateTimeOffset)Picker.Date);
	}
}

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

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

Below the MainPage() Method an instance of the Library Class is created, then Display_Loaded is used to set the ListBox to show Appointments, Picker_DateChanged is used to set the Appointments to show in the ListBox, Add_Click is used to create Appointments then updates the ListBox which is also done by Edit_Click to amend an existing Appointment and Delete_Click is used to remove an Appointment.

Step 13

In the Solution Explorer select Package.appxmanifest

vs2017-manifest-library

Step 14

From the Menu choose View and then Designer

vs2017-view-designer

Step 15

Finally in the Package.appxmanifest select Capabilities and then make sure the Appointments option is checked

vs2017-manifest-calendar-app

Step 16

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 17

After the Application has started running you can then select Add to create a new Appointment, this will display a Dialog where you can enter the Date, Time, Subject and Details for an Appointment. Appointments added will be displayed in the List where you can Edit or Delete them and you can control the date range to start showing Appointments from with the CalendarDatePicker at the top.

ran-calendar-app

Step 18

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

vs2017-close

This example shows how to integrate Appointments with the Windows 10 Calendars – any Appointment added will show up in the system calendars under the name of “Calendar App” – it’s also important that this is an extended Capability which is why the option for allowing access to Appointments in the Application Manifest is important otherwise the functionality won’t work.

Creative Commons License

Universal Windows Platform – Speaking App

Speaking App demonstrates how to create an application which allows text files to be opened then read out in different Voices using text-to-speech – they can also be saved back as a Text file or the spoken version as an Audio file.

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.Media.SpeechSynthesis;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

public class Library
{
    private const string extension_txt = ".txt";
    private const string extension_wav = ".wav";

    private SpeechSynthesizer synth = new SpeechSynthesizer();

    private async Task OpenAsync()
    {
        try
        {
            FileOpenPicker picker = new FileOpenPicker()
            {
                SuggestedStartLocation = PickerLocationId.ComputerFolder
            };
            picker.FileTypeFilter.Add(extension_txt);
            StorageFile open = await picker.PickSingleFileAsync();
            if (open != null)
            {
                return await FileIO.ReadTextAsync(open);
            }
        }
        finally
        {
        }
        return null;
    }

    private async void SaveAsync(string contents)
    {
        try
        {
            FileSavePicker picker = new FileSavePicker()
            {
                SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
                DefaultFileExtension = extension_txt,
                SuggestedFileName = "Document"
            };
            picker.FileTypeChoices.Add("Text File", new List() { extension_txt });
            picker.FileTypeChoices.Add("Wave File", new List() { extension_wav });
            StorageFile save = await picker.PickSaveFileAsync();
            if (save != null)
            {
                if (save.FileType == extension_txt)
                {
                    await FileIO.WriteTextAsync(save, contents);
                }
                else if (save.FileType == extension_wav)
                {
                    using (SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(contents))
                    {
                        using (DataReader reader = new DataReader(stream))
                        {
                            await reader.LoadAsync((uint)stream.Size);
                            IBuffer buffer = reader.ReadBuffer((uint)stream.Size);
                            await FileIO.WriteBufferAsync(save, buffer);
                        }
                    }
                }
            }
        }
        finally
        {
        }
    }

    private async void Speak(string text, MediaElement media)
    {
        try
        {
            if (media.CurrentState == MediaElementState.Playing)
            {
                media.Stop();
            }
            else
            {
                SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(text);
                media.AutoPlay = true;
                media.SetSource(stream, stream.ContentType);
                media.Play();
            }
        }
        finally
        {
        }
    }

    public Dictionary Voices()
    {
        Dictionary results = new Dictionary();
        foreach (VoiceInformation voice in SpeechSynthesizer.AllVoices.OrderBy(o => o.DisplayName))
        {
            results.Add(voice.Id, voice.DisplayName);
        }
        return results;
    }

    public void Voice(string id)
    {
        synth.Voice = SpeechSynthesizer.AllVoices.First(f => f.Id == id);
    }

    public void New(ref TextBox text, ref MediaElement media)
    {
        media.Source = null;
        text.Text = string.Empty;
    }

    public async void Open(TextBox text)
    {
        string content = await OpenAsync();
        if (content != null)
        {
            text.Text = content;
        }
    }

    public void Save(ref TextBox text)
    {
        SaveAsync(text.Text);
    }

    public void Play(ref TextBox text, ref MediaElement media)
    {
        Speak(text.Text, media);
    }
}

The Library class defines two const for file extensions for “.txt” and “.wav” then there’s a SpeechSynthesizer which is the core of the text-to-speak functionality. The OpenAsync method uses a FileOpenPicker to select a file with the “.txt” extension and returns a string using PickSingleFileAsync and ReadTextAsync to get the contents of the Text file. The SaveAsync takes in contexts for a Text file as a string and uses a FileSavePicker with a default extension as “.txt” but also there’s two file type choices – one is the “.txt” and the other is the “.wav” extension to get the StorageFile with PickSaveFileAsync, then if the extension is “.txt” then the file is saved with WriteTextAsync, it the extension is “.wav” then a SpeechSynthesisStream is used with a DataReader and LoadAsync to get the contents of the SpeechSynthesisStream as a IBuffer which is then written using WriteBufferAsync.

The Speak method takes in string text to read and a MediaElement to use for playback – if the this is Playing then Stop is called otherwise a SpeechSynthesisStream is obtained from SynthesizeTextToStreamAsync using the text and then the MediaElement is set to have AutoPlay to true and the SetSource set from the SpeechSynthesisStream. Then Voices is used to get a list of all the voices that the SpeechSynthesizer supports and Voice gets a Voice by an Id, New is used to reset the TextBox and MediaElement, Open reads in a Text file, Save writes to a Text File or Wave File and Play reads the Text contents using text-to-speech.

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:

<Grid Margin="50" Name="Display" Loaded="Display_Loaded">
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="*"/>
	</Grid.RowDefinitions>
	<ComboBox Grid.Row="0" Name="Voice" HorizontalAlignment="Stretch"
		SelectedValuePath="Key" DisplayMemberPath="Value"
		SelectionChanged="Voice_SelectionChanged"/>
	<TextBox Grid.Row="1" Name="Input" AcceptsReturn="True" TextWrapping="Wrap"/>
	<MediaElement Name="Media" AutoPlay="False"/>
</Grid>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Page2" Label="New" Click="New_Click"/>
	<AppBarButton Icon="OpenFile" Label="Open" Click="Open_Click"/>
	<AppBarButton Icon="Save" Label="Save" Click="Save_Click"/>
	<AppBarButton Icon="Play" Label="Play" Click="Play_Click"/>
</CommandBar>

The MainPage has a Grid with two rows – the first represents the ComboBox for selecting Voices from then the second row has a TextBox for entering text to be read out with text-to-speech and there’s also a MediaElement. The second block of XAML is is the CommandBar which contains New – to start a new Document, Open – to get a Document, Save – to store a Document and Play to initiate the text-to-speech.

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 Display_Loaded(object sender, RoutedEventArgs e)
{
	Voice.ItemsSource = library.Voices();
	Voice.SelectedIndex = 0;
}

private void Voice_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
	library.Voice((string)Voice.SelectedValue);
}

private void New_Click(object sender, RoutedEventArgs e)
{
	library.New(ref Input, ref Media);
}

private void Open_Click(object sender, RoutedEventArgs e)
{
	library.Open(Input);
}

private void Save_Click(object sender, RoutedEventArgs e)
{
	library.Save(ref Input);
}

private void Play_Click(object sender, RoutedEventArgs e)
{
	library.Play(ref Input, ref Media);
}

Below the MainPage() Method an instance of the Library Class is created, then Display_Loaded is used to set the ComboBox to the Voices to use for the text-to-speech, Voice_SelectionChanged to use the selected Voice, New_Click to call the New Method in the Library Class, Open_Click, Save_Click and Play_Click to call the related Methods in 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 New to reset the TextBox or use Open to set the content to a Text Document or Save contents to a Text Document or Speech to a Wave File and use Play to convert content from text-to-speech – you can choose the Voice to speak with from the ComboBox.

ran-speaking-app

Step 15

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

vs2017-close

Text-to-speech is an interesting technology to use as it enables additional options and functionality when thinking about text beyond what can be done visually by building in the functionality you can have dictation features within any application with just a few lines of code to turn text into speech. This example shows how easy it is to use the SpeechSynthesizer to translate simple text into speech, it also supports Speech Synthesis Markup Language (SSML) which allows more finer control over how the context is spoken if needed.

Creative Commons License

Universal Windows Platform – Operator App

Operator App demonstrates how to create a basic Calculator based on some common C# Operators for addition, subtraction, multiplication and division.

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.Windows.Input;
using Windows.UI.Xaml.Controls;

public class CommandHandler : ICommand
{
    public event EventHandler CanExecuteChanged = null;
    private Action _action;

    public CommandHandler(Action action)
    {
        _action = action;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        _action();
    }
}

public class Item
{
    public enum ItemMode
    {
        Operand = 1,
        Operator = 2
    }

    public ItemMode Mode { get; set; }
    public Func Action { get; set; }
    public ICommand Command { get { return new CommandHandler(() => this.Action(this)); } }
    public object Value { get; set; }
}

public class Library
{
    private static double first_operand;
    private static double second_operand;
    private static string operation = null;

    private static TextBlock _output;

    private static Func action = (Item item) =>
    {
        switch (item.Mode)
        {
            case Item.ItemMode.Operand:
                _output.Text += (int)item.Value;
                break;
            case Item.ItemMode.Operator:
                string selected = (string)item.Value;
                if (selected == "=")
                {
                    double result = 0.0;
                    if (_output.Text.Length > 0)
                    {
                        second_operand = double.Parse(_output.Text);
                        switch (operation)
                        {
                            case "/":
                                if (second_operand > 0)
                                {
                                    result = first_operand / second_operand;
                                }
                                break;
                            case "*":
                                result = first_operand * second_operand;
                                break;
                            case "-":
                                result = first_operand - second_operand;
                                break;
                            case "+":
                                result = first_operand + second_operand;
                                break;
                        }
                        _output.Text = result.ToString();
                    }
                }
                else if (selected == " 0)
                    {
                        _output.Text = _output.Text.Substring(0, _output.Text.Length - 1);
                    }
                }
                else
                {
                    if (_output.Text.Length > 0)
                    {
                        first_operand = int.Parse(_output.Text);
                        _output.Text = string.Empty;
                        operation = item.Value.ToString();
                    }
                }
                break;
        }
        return 0;
    };

    private List list = new List
    {
        new Item { Mode = Item.ItemMode.Operand, Value = 7, Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 8, Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 9, Action = action },
        new Item { Mode = Item.ItemMode.Operator, Value = "/", Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 4, Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 5, Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 6, Action = action },
        new Item { Mode = Item.ItemMode.Operator, Value = "*", Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 1, Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 2, Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 3, Action = action },
        new Item { Mode = Item.ItemMode.Operator, Value = "-", Action = action },
        new Item { Mode = Item.ItemMode.Operator, Value = "<", Action = action },
        new Item { Mode = Item.ItemMode.Operand, Value = 0, Action = action },
        new Item { Mode = Item.ItemMode.Operator, Value = "=", Action = action },
        new Item { Mode = Item.ItemMode.Operator, Value = "+", Action = action },
    };

    public List New(ref TextBlock text)
    {
        _output = text;
        return list;
    }
}

There’s a CommandHandler Class that will help handle any commanding events and actions from the Library Class. There’s also a Item Class with an ItemMode for either Operand or Operator, an Action to represent what happens during commanding and an ICommand value that uses the CommandHandler and defines what’s passed into the Action and there’s a Value for storing content for the Item.

The Library Class defines two double variables to store the operands used in a Calculation and there’s a string for the kind of Calculation operation to be performed and a variable for a TextBlock for Output. A lambda function is defined which defines what an Action will do during commanding and has a switch statement which will if the ItemMode is Operand will append the TextBlock with the Value from an Item Object, if the ItemMode is Operator then it will check if that is an = which will product the result of a Calculation or if not then will use another switch statement to determine if it is /, *, or + to perform the selected kind of Calculation – there’s also check to see if the Operator is < which will remove numbers from the Output to be used if any mistakes entered. There’s then a List of Item which defined all the Operand and Operator items supported and sets the Action to be the same for each one and then a New method which sets a passed in TextBlock for Output and returns the list of Item.

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:

<Viewbox Margin="50">
	<Grid>
		<Grid.RowDefinitions>
			<RowDefinition Height="Auto"/>
			<RowDefinition Height="*"/>
		</Grid.RowDefinitions>
		<TextBlock Grid.Row="0" Name="Output" TextAlignment="Right" FontSize="30"
		HorizontalAlignment="Stretch" Foreground="{ThemeResource AccentButtonBackground}"/>
		<ItemsControl Grid.Row="1" Name="Display" Loaded="Display_Loaded">
			<ItemsControl.ItemTemplate>
				<DataTemplate>
					<Button Margin="5" Height="50" Width="50"
				Background="{ThemeResource AccentButtonBackground}" Command="{Binding Command}">
						<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20"
						Foreground="{ThemeResource AccentButtonForeground}" Text="{Binding Value}"/>
					</Button>
				</DataTemplate>
			</ItemsControl.ItemTemplate>
			<ItemsControl.ItemsPanel>
				<ItemsPanelTemplate>
					<ItemsWrapGrid MaximumRowsOrColumns="4" Orientation="Horizontal"/>
				</ItemsPanelTemplate>
			</ItemsControl.ItemsPanel>
		</ItemsControl>
	</Grid>
</Viewbox>

The MainPage has a Grid with two rows – the first represents the TextBlock for output and sets the Foreground and Background properties amongst others. Then there’s an ItemsControl which has it’s ItemsSource set to the New method from the Library Class in the Display_Loaded Event, within this is a DataTemplate defining the Button and also has the Foreground and Background properties set plus the Command for commanding to trigger the appropriate Action – to make sure the layout appears correctly the ItemsPanelTemplate is set to be a ItemsWrapGrid with MaximumRowsOrColumns of 4 and the Orientation set to Horizontal.

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 Display_Loaded(object sender, RoutedEventArgs e)
{
	Display.ItemsSource = library.New(ref Output);
}

Below the MainPage() Method an instance of the Library Class is created, then Display_Loaded is used to set the ItemsSource of the ItemsControl to display the look-and-feel of the application.

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 any of the Button controls and select either an Operator such as *, +, /, or < to delete a number from the display or any number from 0 to 9 then you can use = to get the answer.

ran-operator-app

Step 15

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

vs2017-close

This is by no means a fully featured calculator – for example there’s no . but it could be extended to support other Operators from C# such as % for Modulus, the main point of the example was to show the flexability of combining commanding with a list of items to product the necessary functionality of an application and to implement the layout.

Creative Commons License

Universal Windows Platform – ZipFile App

ZipFile App demonstrates how to create New and Open Zip archives plus Add, Remove and Extract files.

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.IO;
using System.IO.Compression;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;

public class ZipItem
{
    public string Name { get; set; }
    public string ActualBytes { get; set; }
    public string CompressedBytes { get; set; }
}

public class Library
{
    public const string extension_all = "*";
    public const string extension_zip = ".zip";
    public const string desc_archive = "Archive";
    public const string desc_file = "File";

    private string _token = string.Empty;
    StorageItemAccessList _access = StorageApplicationPermissions.FutureAccessList;

    public string Name { get; set; }

    private async Task GetByteFromFile(StorageFile storageFile)
    {
        using (IRandomAccessStream stream = await storageFile.OpenReadAsync())
        {
            using (DataReader dataReader = new DataReader(stream))
            {
                byte[] bytes = new byte[stream.Size];
                await dataReader.LoadAsync((uint)stream.Size);
                dataReader.ReadBytes(bytes);
                return bytes;
            }
        }
    }

    private async Task OpenFileAsync(string extension)
    {
        try
        {
            FileOpenPicker picker = new FileOpenPicker()
            {
                SuggestedStartLocation = PickerLocationId.ComputerFolder
            };
            picker.FileTypeFilter.Add(extension);
            StorageFile open = await picker.PickSingleFileAsync();
            if (open != null)
            {
                return open;
            }
        }
        finally
        {
        }
        return null;
    }

    private async Task SaveFileAsync(string filename, string extension, string description)
    {
        try
        {
            FileSavePicker picker = new FileSavePicker()
            {
                SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
                DefaultFileExtension = extension,
                SuggestedFileName = filename
            };
            picker.FileTypeChoices.Add(description, new List() { extension });
            StorageFile save = await picker.PickSaveFileAsync();
            if (save != null)
            {
                return save;
            }
        }
        finally
        {
        }
        return null;
    }

    public async Task<List> List()
    {
        List results = null;
        StorageFile file = await _access.GetFileAsync(_token);
        if (file != null)
        {
            using (Stream stream = await file.OpenStreamForReadAsync())
            {
                using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read))
                {
                    results = new List();
                    foreach (ZipArchiveEntry entry in archive.Entries)
                    {
                        if (entry.Name != string.Empty)
                        {
                            results.Add(new ZipItem()
                            {
                                Name = entry.Name,
                                CompressedBytes = $"Compressed Size {entry.CompressedLength}",
                                ActualBytes = $"Actual Size {entry.Length}"
                            });
                        }
                    }
                }
            }
        }
        return results;
    }

    public async Task NewAsync()
    {
        StorageFile file = await SaveFileAsync(desc_archive, extension_zip, desc_archive);
        if (file != null)
        {
            _token = _access.Add(file);
            Name = file.Name;
            using (Stream stream = await file.OpenStreamForWriteAsync())
            {
                new ZipArchive(stream, ZipArchiveMode.Create);
            }
            return true;
        }
        return false;
    }

    public async Task<List> OpenAsync()
    {
        StorageFile file = await OpenFileAsync(extension_zip);
        if (file != null)
        {
            Name = file.Name;
            _token = _access.Add(file);
        }
        return await List();
    }

    public async Task<List> AddAsync()
    {
        if (!string.IsNullOrEmpty(_token))
        {
            StorageFile file = await _access.GetFileAsync(_token);
            if (file != null)
            {
                StorageFile source = await OpenFileAsync(extension_all);
                if (source != null)
                {
                    using (Stream stream = await file.OpenStreamForWriteAsync())
                    {
                        using (ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Update))
                        {
                            ZipArchiveEntry existing = zipArchive.GetEntry(source.Name);
                            if (existing != null)
                            {
                                existing.Delete();
                            }
                            ZipArchiveEntry entry = zipArchive.CreateEntry(source.Name);
                            using (Stream entryStream = entry.Open())
                            {
                                byte[] data = await GetByteFromFile(source);
                                entryStream.Write(data, 0, data.Length);
                            }
                        }
                    }
                }
            }
            return await List();
        }
        return null;
    }

    public async void Extract(ZipItem item)
    {
        if (!string.IsNullOrEmpty(_token))
        {
            StorageFile file = await _access.GetFileAsync(_token);
            if (file != null)
            {
                using (Stream stream = await file.OpenStreamForReadAsync())
                {
                    using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read))
                    {
                        ZipArchiveEntry entry = archive.GetEntry(item.Name);
                        if (entry != null)
                        {
                            StorageFile source = await SaveFileAsync(entry.Name, Path.GetExtension(entry.Name), desc_file);
                            if (source != null)
                            {
                                using (Stream output = await source.OpenStreamForWriteAsync())
                                {
                                    await entry.Open().CopyToAsync(output);
                                    await output.FlushAsync();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public async Task<List> RemoveAsync(ZipItem item)
    {
        if (!string.IsNullOrEmpty(_token))
        {
            StorageFile file = await _access.GetFileAsync(_token);
            if (file != null)
            {
                using (Stream stream = await file.OpenStreamForWriteAsync())
                {
                    using (ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Update))
                    {
                        ZipArchiveEntry entry = zipArchive.GetEntry(item.Name);
                        if (entry != null)
                        {
                            entry.Delete();
                        }
                    }
                }
                return await List();
            }
        }
        return null;
    }
}

There’s a ZipItem Class to represent each item within the Archive then in the Library Class there are const values to set file extensions and descriptions plus variables for a “token” and StorageItemAccessList. There’s a GetByteFromFile method that converts a StorageFile into a byte[] with the use of a IRandomAccessStream plus a DataReader. The OpenFileAsync method uses a FileOpenPicker to select a file with the passed in extension and returns a StorageFile and SaveFileAsync uses a FileSavePicker to return a StorageFile that will be created and written to with the passed in filename, extension and description, and there’s a string property to store the name of the archive.

Also in the Library Class there’s a List method that uses a StorageFile from the StorageItemAccessList using the “token” – if this file is present then a Stream is used to then get the ZipArchive from and then each ZipArchiveEntry in the archive is looped through to create a list of ZipItem and is returned my that method. The NewAsync method uses the SaveFileAsync to create the StorageFile to create a new archive and returns true if successful or false if not. The OpenAsync method uses the OpenFileAsync to open an archive from the StorageFile and returns the list of ZipItem.

Again also in the Library Class is an AddAsync method uses a StorageFile from the StorageItemAccessList using the “token”. It then uses the OpenFileAsync to get the file to add to the archive – if the archive file is present then a Stream is used to then get the ZipArchive and then it checks for an existing entry – if there is one then it is deleted with Delete if not then a new entry is created with CreateEntry using the GetByteFromFile to insert the file into the archive. The Extract method is used to retrieve a file from an archive and uses a StorageFile from the StorageItemAccessList using the “token” and if this file is present then a Stream is used to then get the ZipArchive and then an entry is retrieved by name with the GetEntry method and then if present the SaveFileAsync method is used to get a StorageFile to write the file Stream to, then there’s a RemoveAsync method to remove a given item from the archive.

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:

<Grid Margin="50">
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="*"/>
	</Grid.RowDefinitions>
	<TextBlock Grid.Row="0" Name="Label" Margin="5" Style="{StaticResource SubtitleTextBlockStyle}"/>
	<ListBox Grid.Row="1" Name="Display">
		<ListBox.ItemContainerStyle>
			<Style TargetType="ListBoxItem">
				<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
			</Style>
		</ListBox.ItemContainerStyle>
		<ListBox.ItemTemplate>
			<DataTemplate>
				<Grid>
					<Grid.ColumnDefinitions>
						<ColumnDefinition Width="40*"/>
						<ColumnDefinition Width="20*"/>
						<ColumnDefinition Width="20*"/>
						<ColumnDefinition Width="Auto"/>
					</Grid.ColumnDefinitions>
					<Grid Padding="5" Grid.Column="0" Background="{ThemeResource AccentButtonBackground}">
						<TextBlock Text="{Binding Name}" VerticalAlignment="Center"
						Foreground="{ThemeResource AccentButtonForeground}"/>
					</Grid>
					<Grid Padding="5" Grid.Column="1" Background="{ThemeResource AccentButtonForeground}">
						<TextBlock Text="{Binding ActualBytes}" VerticalAlignment="Center"
						Foreground="{ThemeResource AccentButtonBackground}"/>
					</Grid>
					<Grid Padding="5" Grid.Column="2" Background="{ThemeResource AccentButtonForeground}">
						<TextBlock Text="{Binding CompressedBytes}" VerticalAlignment="Center"
						Foreground="{ThemeResource AccentButtonBackground}"/>
					</Grid>
					<StackPanel Grid.Column="3" Orientation="Horizontal">
						<AppBarButton Name="Extract" Icon="SaveLocal" Label="Extract" Tag="{Binding}" Click="Extract_Click"/>
						<AppBarButton Name="Remove" Icon="Remove" Label="Remove" Tag="{Binding}" Click="Remove_Click"/>
					</StackPanel>
				</Grid>
			</DataTemplate>
		</ListBox.ItemTemplate>
	</ListBox>
</Grid>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Page2" Label="Open" Click="New_Click"/>
	<AppBarButton Icon="OpenFile" Label="Open" Click="Open_Click"/>
	<AppBarButton Icon="Add" Label="Add" Click="Add_Click"/>
</CommandBar>

The MainPage has an AppBarButton for New, Open and Add. Then theres a ListBox that will have a list of ZipItem set to it’s DataSource and has a DataTemplate that displays a list of Name, Actual Size and Compressed Size for each entry in an archive plus an AppBarButton for Extract and Remove for each archive entry item displayed.

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 New_Click(object sender, RoutedEventArgs e)
{
	if (await library.NewAsync())
	{
		Label.Text = library.Name;
	}
}

private async void Open_Click(object sender, RoutedEventArgs e)
{
	Display.ItemsSource = await library.OpenAsync();
	Label.Text = library.Name;
}

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

private void Extract_Click(object sender, RoutedEventArgs e)
{
	ZipItem item = (ZipItem)((AppBarButton)sender).Tag;
	library.Extract(item);
}

private async void Remove_Click(object sender, RoutedEventArgs e)
{
	ZipItem item = (ZipItem)((AppBarButton)sender).Tag;
	Display.ItemsSource = await library.RemoveAsync(item);
}

Below the MainPage() Method an instance of the Library Class is created, then New_Click is used to create a new Zip File, Open_Click will call OpenAsync to open a Zip File and then you can use Add_Click to add to the Archive, Extract_Click to Extract a file and Remove_Click to remove a file from the Archive.

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 New to create a Zip archive using a FileSavePicker then you need to use Add to add to the archive using the FileOpenPicker. You can view any files in the archive in the ListBox plus you can Extract a file using a FileSavePicker or Remove a file from the archive.

ran-zipfile-app

Step 15

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

vs2017-close

This example shows how you can use the ZipArchive compression features in System.IO.Compression and use this within a Universal Windows Platform application – usually this is used directly with paths but due to the sandboxed nature of UWP apps the lesser seen methods demonstrated in the example are used instead. This example demonstrates all the key features of dealing with a zip archive and is pretty close to the functionality within Windows 10 itself for dealing with Zip files.

Creative Commons License

Universal Windows Platform – JpgInfo App

JpgInfo App demonstrates how to create an application which will allow you to Open then view metadata details of a JPG picture.

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.Reflection;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.FileProperties;
using Windows.Storage.Pickers;

public class Library
{
    private async Task<Dictionary> GetProperties(StorageFile file)
    {
        Dictionary results = new Dictionary();
        ImageProperties properties = await file.Properties.GetImagePropertiesAsync();
        results.Add("Name", file.Name);
        foreach (PropertyInfo property in properties.GetType().GetProperties())
        {
            results.Add(property.Name, property.GetValue(properties)?.ToString());
        }
        results.Remove("PeopleNames");
        results.Remove("Keywords");
        return results;
    }

    public async Task<Dictionary> OpenAsync()
    {
        try
        {
            FileOpenPicker picker = new FileOpenPicker()
            {
                SuggestedStartLocation = PickerLocationId.PicturesLibrary
            };
            picker.FileTypeFilter.Add(".jpg");
            StorageFile open = await picker.PickSingleFileAsync();
            if (open != null)
            {
                return await GetProperties(open);
            }
        }
        finally
        {

        }
        return null;
    }
}

The Library Class contains a GetProperties method which returns a Dictionary – this uses the GetImagePropertiesAsync method on the Properties of a StorageFile passed into the method, it then uses Reflection to get all the properties with the GetProperties on the PropertyInfo type from the ImageProperties and this is added to the Dictionary Dictionary with the Key as a Label then the Value as the contents of that Property. The OpenAsync method uses a FileOpenPicker to open a “.jpg” file and then selected file is passed into the GetProperties method to return the Dictionary.

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:

<Grid Margin="50">
	<Grid.RowDefinitions>
		<RowDefinition Height="*"/>
		<RowDefinition Height="Auto"/>
	</Grid.RowDefinitions>
	<ListBox Grid.Row="0" Name="Display">
		<ListBox.ItemContainerStyle>
			<Style TargetType="ListBoxItem">
				<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
			</Style>
		</ListBox.ItemContainerStyle>
		<ListBox.ItemTemplate>
			<DataTemplate>
				<Grid>
					<Grid.ColumnDefinitions>
						<ColumnDefinition Width="30*"/>
						<ColumnDefinition Width="70*"/>
					</Grid.ColumnDefinitions>
					<Grid Padding="5" Grid.Column="0" Background="{ThemeResource AccentButtonBackground}">
						<TextBlock Text="{Binding Key}" Foreground="{ThemeResource AccentButtonForeground}"/>
					</Grid>
					<Grid Padding="5" Grid.Column="1" Background="{ThemeResource AccentButtonForeground}">
						<TextBlock Text="{Binding Value}" Foreground="{ThemeResource AccentButtonBackground}"/>
					</Grid>
				</Grid>
			</DataTemplate>
		</ListBox.ItemTemplate>
	</ListBox>
</Grid>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="OpenFile" Label="Open" Click="Open_Click"/>
</CommandBar>

The MainPage contains the Open button to allow a JPG Picture to be opened and there’s a ListBox which is populated with image properties by setting the ItemsSource and is a list of the Key and Value from the Dictionary and with a Foreground and Background set in the DataTemplate for the ListBox.

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 Open_Click(object sender, RoutedEventArgs e)
{
	Display.ItemsSource = await library.OpenAsync();
}

Below the MainPage() Method an instance of the Library Class is created, then Open_Click is used to call the OpenAsync Method which will set the ListBox contents to various MetaData of the JPG File.

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 Open then you need to select a jpg photo to open. Once done then you can view various properties of the image in the ListBox.

ran-lucky-roulette

You can use the following sample JPG

Big Buck Bunny

Step 15

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

vs2017-close

This example was inspired from the Microsoft Universal Windows Platform (UWP) app samples and in particular the Simple imaging example, the purpose of this example was to show how you can extract the Image Properties for a JPG image including the Date Taken and Orientation of the Image this may also contain EXIF information used by many digital cameras, the ideal example to use is a photo taken from a Phone or Camera to see what properties are stored along with the image although there was a single sample provided which is a screenshot from the Big Buck Bunny video from the Blender Foundation.

Creative Commons License

Universal Windows Platform – PdfView App

PdfView App demonstrates how to create an application which will allow you to read and navigate through PDF Documents and its pages.

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.Pdf;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
using Windows.UI.Popups;
using Windows.UI.Xaml.Media.Imaging;

public class Library
{
    private const string app_title = "PdfView App";

    private PdfDocument _document = null;

    public void Show(string content, string title)
    {
        IAsyncOperation command = new MessageDialog(content, title).ShowAsync();
    }

    public async Task OpenAsync()
    {
        uint pages = 0;
        try
        {
            _document = null;
            FileOpenPicker picker = new FileOpenPicker()
            {
                SuggestedStartLocation = PickerLocationId.DocumentsLibrary
            };
            picker.FileTypeFilter.Add(".pdf");
            StorageFile open = await picker.PickSingleFileAsync();
            if (open != null)
            {
                _document = await PdfDocument.LoadFromFileAsync(open);
            }
            if (_document != null)
            {
                if (_document.IsPasswordProtected)
                {
                    Show("Password Protected PDF Document", app_title);
                }
                pages = _document.PageCount;
            }
        }
        catch (Exception ex)
        {
            if (ex.HResult == unchecked((int)0x80004005))
            {
                Show("Invalid PDF Document", app_title);
            }
            else
            {
                Show(ex.Message, app_title);
            }
        }
        return pages;
    }

    public async Task ViewAsync(uint number)
    {
        BitmapImage source = new BitmapImage();
        if (!(number  _document.PageCount))
        {
            uint index = number - 1;
            using (PdfPage page = _document.GetPage(index))
            {
                using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
                {
                    await page.RenderToStreamAsync(stream);
                    await source.SetSourceAsync(stream);
                }
            }
        }
        return source;
    }

    public List Numbers(int total)
    {
        return Enumerable.Range(1, total).ToList();
    }
}

The Library Class defines the PdfDocument that can be opened later then there’s a Show method for displaying messages on-screen. The OpenAsync method uses the FileOpenPicker set to open a “.pdf” file and then sets the PdfDocument to be the opened file using PickSingleFileAsync with the LoadFromFileAsync method – if the document has been opened if it is password protected a message will be displayed to say that the example won’t open those, otherwise there’s an Exception handler to detect a PDF document that has failed to open due to being invalid or some other error during opening and this method also returns the number of pages in the PDF document as uint.

There’s a ViewAsync which takes a uint as a parameter and then gets a PdfPage from the document using this and then this is rendered to a BitmapImage using the RenderToStreamAsync to set an InMemoryRandomAccessStream which is used to set the source of the BitmapImage with that page’s contents using SetSourceAsync. Theres also a Numbers method which helps generate a list of page numbers to be used.

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:

<Grid Margin="50">
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto"/>
		<RowDefinition Height="*"/>
	</Grid.RowDefinitions>
	<ComboBox Name="Page" Grid.Row="0" HorizontalAlignment="Stretch" SelectionChanged="Page_SelectionChanged"/>
	<ScrollViewer Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
		<Image Name="Display" Stretch="None"/>
	</ScrollViewer>
</Grid>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="OpenFile" Label="Open" Click="Open_Click"/>
</CommandBar>

MainPage.xaml contains the Open button to allow a PDF Document to be opened and there’s a ComboBox that is populated with all possible page numbers based on the number of pages in the document – when a number is selected that uses the ViewAsync method to get that page. Finally there’s an Image control which is used to display the page and this is contained within a ScrollViewer so if the page is too wide or long it can be scrolled around to view all that page’s contents.

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 Open_Click(object sender, RoutedEventArgs e)
{
	uint pages = await library.OpenAsync();
	if (pages > 0)
	{
		Page.ItemsSource = library.Numbers(Convert.ToInt32(pages));
		Page.SelectedIndex = 0;
	}
}

private async void Page_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
	uint.TryParse(Page.SelectedItem.ToString(), out uint page);
	Display.Source = await library.ViewAsync(page);
}

Below the MainPage() Method an instance of the Library Class is created, then Open_Click is used to call the OpenAsync Method which returns a uint stating how many pages there are and then populates the ComboBox with values up to that number using the Numbers Method from the Library Class. The Page_SelectionChanged Event responds to selections from the ComboBox and will get the SelectedItem and convert this back to a uint then pass this to the ViewAsync Method of the Library Class and view that page.

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 Open then you need to select a pdf document, Once done then you can select the ComboBox to choose which page of the document to display but it will start with the first.

ran-pdfview-app

Step 15

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

vs2017-close

This example was inspired from the Microsoft Universal Windows Platform (UWP) app samples and in particular the PDF document example, the main purpose of this example was to show how easy it is to open and navigate through a PDF Document – although password protected documents aren’t fully supported in the example it would be possible to open these if the correct password was provided to the LoadFromFileAsync method from a TextBox or value. It’s quite easy to support PDF documents this way and could be a useful way of integrating PDF documents into any application using this example as the start of that – you could even have it scroll through all the pages by using multiple Image controls and setting their sources accordingly to each page in the PDF document.

Creative Commons License

Universal Windows Platform – GifView App

GifView App demonstrates how to create an application which will allow you to Open and Play an Animated Gif – plus you can also Stop the playback of the animation.

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 Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml.Media.Imaging;

public class Library
{
    public async void Open(BitmapImage display)
    {
        try
        {
            FileOpenPicker picker = new FileOpenPicker()
            {
                SuggestedStartLocation = PickerLocationId.PicturesLibrary
            };
            picker.FileTypeFilter.Add(".gif");
            StorageFile open = await picker.PickSingleFileAsync();
            if (open != null)
            {
                display.AutoPlay = false;
                await display.SetSourceAsync(await open.OpenReadAsync());
            }
        }
        finally
        {
            // Ignore Exceptions
        }
    }
}

The Library Class is quite simple with just one method called Open which contains a FileOpenPicker set to open a “.gif” file and then sets the passed in BitmapImage to be the opened file using PickSingleFileAsync to get the file and SetSourceAsync to set the image from the file with OpenReadAsync

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:

<Image VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="None">
	<Image.Source>
		<BitmapImage x:Name="Display"/>
	</Image.Source>
</Image>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="OpenFile" Label="Open" Click="Open_Click"/>
	<AppBarButton Icon="Play" Label="Play" Click="{x:Bind Display.Play}"/>
	<AppBarButton Icon="Stop" Label="Stop" Click="{x:Bind Display.Stop}"/>
</CommandBar>

MainPage.xaml has three AppBarButton controls; Open – to trigger an event, Play which uses the Click event to trigger a bound expression to call Play on the BitmapImage and Stop to trigger a bound expression to call Stop on the BitmapImage. Plus there’s the Display itself which is the BitmapImage

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 Open_Click(object sender, RoutedEventArgs e)
{
	library.Open(Display);
}

Below the MainPage() Method an instance of the Library Class is created, then Open_Click is used to call the Open Method to load an animated .gif file.

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 Open then you need to select an animated gif file then once done then you can select Play to start the image animating and to end this animation select Stop

ran-gifview-app

You can use the following sample Animated Gif

animation

Step 15

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

vs2017-close

This example was inspired from the Microsoft Universal Windows Platform (UWP) app samples and in particular the Animated GIF Playback example – the goal was to create a simpler implementation of this and found that the bound expressions made it really simple anyway, so the way the animated GIF is played or stopped is the same and demonnstrated a really great technique to trigger events in another object. Also provided was a sample animated GIF which is an extract from the Big Buck Bunny video from the Blender Foundation.

Creative Commons License

Universal Windows Platform – Slide Game

Slide Game demonstrates how to create a game which is based on those sliding fifteen-piece puzzle games but where you tap on a piece to move it rather than slide it to solve the puzzle put all the numbers in descending numerical order.

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 Windows.Foundation;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

public class Piece : Grid
{
    public Piece(int index)
    {
        this.Background = new SolidColorBrush(Colors.Black);
        Rectangle rect = new Rectangle()
        {
            Stroke = new SolidColorBrush(Colors.Gray),
        };
        TextBlock text = new TextBlock()
        {
            FontSize = 30,
            Text = index.ToString(),
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center,
            Foreground = new SolidColorBrush(Colors.White)
        };
        this.Children.Add(rect);
        this.Children.Add(text);
    }

    public int Row { get; set; }
    public int Column { get; set; }
}

public class Library
{
    private const string app_title = "Slide Game";
    private const int size = 4;

    private int _moves = 0;
    private int[,] _board = new int[size, size];
    private List _values;
    private Random _random = new Random((int)DateTime.Now.Ticks);

    private List Shuffle(int start, int total)
    {
        return Enumerable.Range(start, total).OrderBy(r => _random.Next(start, total)).ToList();
    }

    public void Show(string content, string title)
    {
        IAsyncOperation command = new MessageDialog(content, title).ShowAsync();
    }

    private bool Valid(int row, int column)
    {
        if (row < 0 || column  3 || column > 3)
        {
            return false;
        }
        return (_board[row, column] == 0);
    }

    private bool Check()
    {
        int previous = _board[0, 0];
        for (int row = 0; row < size; row++)
        {
            for (int column = 0; column < size; column++)
            {
                if (_board[row, column] < previous)
                {
                    return false;
                }
                previous = _board[row, column];
            }
        }
        return true;
    }

    private void Move(Canvas canvas, Piece piece, int row, int column)
    {
        _moves++;
        _board[row, column] = _board[piece.Row, piece.Column];
        _board[piece.Row, piece.Column] = 0;
        piece.Row = row;
        piece.Column = column;
        Layout(canvas);
        if (Check())
        {
            Show($"Correct In {_moves} Moves", app_title);
        }
    }

    private void Layout(Canvas canvas)
    {
        canvas.Children.Clear();
        for (int row = 0; row < size; row++)
        {
            for (int column = 0; column  0)
                {
                    int index = _board[row, column];
                    Piece piece = new Piece(index)
                    {
                        Width = canvas.Width / size,
                        Height = canvas.Height / size,
                        Row = row,
                        Column = column
                    };
                    Canvas.SetTop(piece, row * (canvas.Width / size));
                    Canvas.SetLeft(piece, column * (canvas.Width / size));
                    piece.PointerReleased += (object sender, PointerRoutedEventArgs e) =>
                    {
                        piece = (Piece)sender;
                        if (Valid(piece.Row - 1, piece.Column))
                        {
                            Move(canvas, piece, piece.Row - 1, piece.Column);
                        }
                        else if (Valid(piece.Row, piece.Column + 1))
                        {
                            Move(canvas, piece, piece.Row, piece.Column + 1);
                        }
                        else if (Valid(piece.Row + 1, piece.Column))
                        {
                            Move(canvas, piece, piece.Row + 1, piece.Column);
                        }
                        else if (Valid(piece.Row, piece.Column - 1))
                        {
                            Move(canvas, piece, piece.Row, piece.Column - 1);
                        }
                    };
                    canvas.Children.Add(piece);
                }
            }
        }
    }

    public void New(ref Canvas canvas)
    {
        int index = 1;
        _values = Shuffle(1, _board.Length);
        _values.Insert(0, 0);
        for (int row = 0; row < size; row++)
        {
            for (int column = 0; column < size; column++)
            {
                _board[row, column] = _values[index++];
                if (index == size * size) index = 0;
            }
        }
        Layout(canvas);
    }
}

The Piece Class that represents each item that will be displayed on the screen and extends the Grid – it is a Rectangle with a TextBlock on it plus properties to indicate the Row and Column. The main Library Class has an const int to set the size of the game layout plus an int[,] for this set to that size plus a list of values and a random number generator, there’s a Shuffle method to use the random number generator and a Show method to display a message on screen.

The Valid method checkes to see if a move is valid or contains an empty square to move into, Check validates if the board contains a decending sequence of numbers to indicate that the puzzle is complete if that’s the case and is used by the Move method which will use Piece to set the appropriate Row and Column value. Layout is used to set up the game layout and declare each Piece and set it’s initial position with the PointerReleased event on a Piece which will use Valid to verify a move is valid then use Move to before the movement with each possible direction this can be – Up, Right, Down and Left. Then there’s the New method to create a new game and set up the game ready to be played.

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:

<Viewbox Margin="50">
	<Canvas Name="Display" HorizontalAlignment="Center" Height="400" Width="400"/>
</Viewbox>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Page2" Label="New" Click="New_Click"/>
</CommandBar>

The first block of XAML the main user interface of the Game, this features a ViewBox containing a Canvas to display the game itself within. The second block of XAML is is the CommandBar which contains New to start a Game

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 New_Click(object sender, RoutedEventArgs e)
{
	library.New(ref Display);
}

Below the MainPage() Method an instance of the Library Class is created, then New_Click is used to call the New Method to setup the game and start playing.

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 New to start the game then you need to select a Piece nearest the empty slot to move it into that slot and then continue until all the Numbers are in the correct order from Left to Right from 1 to 15 to then complete the game.

ran-slide-game

Step 15

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

vs2017-close

This game is based on the fifteen piece puzzle and could be extended to actually allow the pieces to be slid but it shows off ability to obey the correct rules for this puzzle as well as checking for a win condition – the pieces don’t just have to be numbers it could be made to display a picture just like the puzzle the example is based on and then more complex functionality can be added to fine tune it to be more like a real fifteen-piece sliding puzzle.

Creative Commons License