Start programming your own app in Uno Platform ???
We already learned how to create our first app in UnoPlatform, here at idiWork’s blog, the framework that makes possible create apps for Windows, Android, iOS and web with the same code. In this post we are going to program in C# and XAML to create an app to register a to-do list. Let’s create a to-do app!
With these steps we will have the same app in all the platforms we mentioned before, and we will see how fast and simple is to obtain results with UnoPlatform. Knowledge of UWP development or XAML is appreciated, but is never late to learn something new!
First steps
If we open our UnoPlatform solution, we will see five projects within the Solution Explorer, each one with platform specific name and code. The last one is called Shared, this one will be our main workspace. UnoPlatform development team recommends to code as much as you can in this project, so you can share as much code as possible.
Open the MainPage.xaml file . You will see the XAML code that defines the interface and design of the first page. It has a C# Class associated, called MainPage.xaml.cs, where the code-behind of the XAML is.
A service of status
A to-do list usually contains a list with items with a title, a description of the task, a status… So we can follow this model to create a Class that represents that item.
Create a folder called Services, and within you can create a C# Class called StatusesProvider.cs. In this file, create a enum with all the possible task statuses.
public class StatusesProvider { public enum StatusEnum { New, Finished, Abandoned } }
Once they are created, this Class will offer a list with all these possible statuses:
public class StatusesProvider { public StatusesProvider() { Statuses = new ObservableCollection<StatusEnum> { StatusEnum.New, StatusEnum.Finished, StatusEnum.Abandoned }; } public ObservableCollection<StatusEnum> Statuses { get; set; } public enum StatusEnum { New, Finished, Abandoned } }
Create the model
Now we can start creating the model for our items in the to-do list.
Create a new folder called Models. Here will be our main Class that we will be working with, an item of the to-do list. Let’s call it ProjectItem, so it represents a single item of the list. We can create three properties: title, description and current status for the item. Plus the list of the possible statuses the item can show.
public class ProjectItem { public string Title { get; set; } public string Description { get; set; } public StatusEnum Status { get; set; } public ObservableCollection<StatusEnum> StatusList { get; set; } }
Code in MVVM
The Model-View-ViewModel (MVVM) is the pattern that helps to separate the business and presentation logic of an application from its user interface, making it easy to create clean and maintainable code. Keep reading about MVVM in the Microsoft documentation.
Let’s create a Class called MainViewModel, that will be the ViewModel for our view MainPage, and control everything from there.
We will need a constructor that receives an object of the StatusProvider Class, so we can access all the statuses every time we need. It will contain our to-do tasks list.
public class MainViewModel { private readonly StatusesProvider _provider; public MainViewModel(StatusesProvider provider) { _provider = provider; PossibleStatus = _provider.Statuses; Projects = new ObservableCollection<ProjectItem>(); } public ObservableCollection<ProjectItem> Projects { get; set; } public ObservableCollection<StatusEnum> PossibleStatus { get; set; } }
Creating the view
Now we will access the view, but not the XAML yet! Let’s go to the C# Class. We have created a ViewModel object with which the view communicates, but the view doesn’t know about it yet. So we create a variable for that ViewModel, and overwriting the OnNavigatedTo method that represents the moment in which we navigate on this page, instantiate the ViewModel, passing a new StatusProvider object.
public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } MainViewModel viewModel; protected override void OnNavigatedTo(NavigationEventArgs e) { viewModel = new MainViewModel(new StatusesProvider()); } }
Now we can edit the XAML file to edit the view. For now, we have a Grid with a TextBlock inside, to show a simple text. Delete the TextBlock to add our code, so the Grid is empty.
Add RowDefinitions to the Grid, to create the rows were our controls will be placed.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" > <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> </Grid>
In the first row, we will ad a button. The function of this button will be add new elements to our list. Set the background and foreground color, also the font size… all to customize your new button!
<Button Content="Add new project" Margin="10" FontSize="15" Background="CornflowerBlue" Foreground="White" Grid.Row="0"/>
Now, how and where will be located our task list? Let’s keep editing the view to add a ListView, that will be located in the second row of the Grid. In the ItemsSource property we will stipulate where are the elements, the Projects, that are located in the ViewModel we created.
We can also customize the way that our items are shown, thanks to ItemTemplate element. The ItemTemplate needs a DataTemplate element, where we can set what data type we are working with. Let’s point to our ProjectItem class, that will be imported in the XAML namespace list:
<Page ... more XAML imports ... xmlns:Models="using:idiTasks.Shared.Models">
Every item will be set in a horizontal StackPanel. Inside the StackPanel, we have two TextBlocks and a ComboBox. That elements contains a ProjectItem property that we specify thanks to the x:Bind code:
<Grid> <!-- More code: RowDefintions and Button --> <ListView ItemsSource="{x:Bind viewModel.Projects}" SelectionMode="Single" Grid.Row="1"> <ListView.ItemTemplate> <DataTemplate x:DataType="Models:ProjectItem"> <StackPanel Grid.Row="1" Orientation="Horizontal" Padding="5"> <TextBox Header="Title" PlaceholderText="Insert title here" Text="{x:Bind Title, Mode=TwoWay}" Width="200" Height="70" AcceptsReturn="False" TextWrapping="NoWrap" Margin="5"/> <ComboBox Header="Type" ItemsSource="{x:Bind StatusList}" SelectedItem="{x:Bind Status, Mode=TwoWay}" Width="150" Margin="5, 20"/> <TextBox Header="Description" PlaceholderText="Enter text here" Text="{x:Bind Description, Mode=TwoWay}" AcceptsReturn="True" Height="100" Width="200" Margin="5"/> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> <Grid>
Adding new elements
If we execute the app, our list is empty! It’s time to add some elements with our button. Let’s capture the Click event in our button.
<Button Content="Add new project" Click="AddNewItem_Click" Margin="10" FontSize="15" Background="CornflowerBlue" Foreground="White" Grid.Row="0"/>
Right now, this click event does nothing. We need to create a method in the ViewModel Class that adds an ‘empty’ item to the list.
public class MainViewModel { // Previous code public void AddNewProject() { Projects.Add( new ProjectItem { Title = "No title", Description = "Empty description", Status = StatusEnum.New, StatusList = PossibleStatus }); } }
Now, let’s call the method through the Click event:
public sealed partial class MainPage : Page { // Previous code private void AddNewItem_Click(object sender, RoutedEventArgs e) { viewModel.AddNewProject(); } }
Now execute again the application! Try to add new elements clicking in the button to see the magic!
Improving the view: UserControls
As you can see, the view is changing in the XAML previewer while we are coding It would be great to see every item of the ListView as we add them, right? It is possible thanks to UserControls, that allows to create individual elements as templates.
Let’s start by creating a folder called Controls. Add a new UserControl item from the Solution Explorer, and call it ProjectItemControl. You will see a XAML file with a C# code-behind Class.
There’s nothing to see except a Grid, so let’s edit the XAMl code to insert the code we have in the MainPage.xaml. Get the code that is inside of DataTemplate, and modify until you get the desired result:
<UserControl ... d:DesignHeight="100" d:DesignWidth="400"> <Grid Background="White"> <Grid.RowDefinitions> <RowDefinition/> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Orientation="Horizontal" Padding="5" MaxHeight="100"> <TextBox Header="Title" PlaceholderText="Insert title here" Text="{Binding Title, Mode=TwoWay}" Width="200" Height="70" AcceptsReturn="False" TextWrapping="NoWrap" Margin="5"/> <ComboBox Header="Type" ItemsSource="{Binding StatusList}" SelectedItem="{Binding Status, Mode=TwoWay}" Width="150" Margin="5"/> <TextBox Header="Description" PlaceholderText="Enter text here" Text="{Binding Description, Mode=TwoWay}" AcceptsReturn="True" Width="200" Margin="5"/> </StackPanel> </Grid> </UserControl>
Now let’s edit the MainPage.xaml code to use the Control we just created:
<ListView.ItemTemplate> <DataTemplate x:DataType="Models:ProjectItem"> <Controls:ProjectItemControl/> </DataTemplate> </ListView.ItemTemplate>
Don’t forget to import the Controls namespace in the XAML code:
<Page ... more XAML imports ... xmlns:Controls="using:idiTasks.Shared.Controls">
This is it!
Do you want carry on in experimenting? Don’t hesitate to visit our repository at idiWork’s organization to see the code, clone it and keep creating!
Happy coding!