Scope

This article aims to create a BackOffice App for the Menu App created by Windows AppStudio in the article

Microsoft’sWindows App Studio Beta: Connecting a Menu App to Azure Mobile Service

How to create a BackOffice App

The MyMenuApp Azure Mobile Service was defined and the Menu App consumes the data from the service, now we will create the BackOffice App for change that data.

For help in creating the BackOffice App, we will use the Empty Template from Windows AppStudio for create the start point of this app, that will contain

  • A start menu with the following chooses: Starters, Mains, Desserts, Beverages and Special offers
  • Clicking in each menu item will show a page with list of the items
  • Clicking in one item in the list will show a page for edit the item

Creating the BackOffice App using Empty Template

Go to the Windows AppStudio, do the login and then click in “Start new project”

In the next screen, click in Empty App Template

Like the name says, this app is empty app and we will define all structure for the BackOffice.

Here is the start point

Changing the app’s name

Start by changing the name to BackOffice, in the App Title field at the top

Creating the menu

The first page of the app will have a menu, for it, click in the Menu option and then fill the name of the menu

Click in the arrow in the menu created, for expand it

With this, we will have more option available, more specific the menu action. For create the menu we want, we will use the collection option, because we want to show a list of items.

Adding collections

Click in the collection menu for create the first menu item

Collection using default columns

Define the name of the collection and click in the option “Add default columns”

That will create the following structure

Here we can define if we want dynamic or static data, that it is not important in our case, because we will use the data from the Azure Mobile Service, like we did in Menu App.

After create each collection is recommended to save the definitions, using the button “Save” in the right.

Do the same process for Mains, Desserts and Beverages.

Collection using specific columns

For Special Offers we need to add the columns manually, because it has a structure different from the default, for it click in “Create new” as following

It will create a row as following

For each field insert the respective information: field’s name, type and if is multiline.

At the end we will have something like it

Note: Each field name should start with upper case.

After all collection are defined, we will have the following definition

These collection can be ordered, deleted, edited, but they cannot be more than six. In code is possible to added more or create another menu and add the missed collections. In source code change it for have only one section.

Editing a collection

Is possible to edit the Starters by clicking in “Edit Item”, that will show the follow screen

For each collection we need to do the following:

  • Define the Layout & Bindings for the windows with the list of items
  • Define the Layout & Bindings & Page Extras for the detail of the item
  • Edit the data for add one dummy starter

Editing Layout & Bindings

We can choose we want, for the sample we will define the following

And for the detail page

Editing default data

Now, we will edit the default data, by clicking in “Data” separator and then in “Edit Data”

Click in “Create new” and fill the item with dummy values like following

Here, is not important what we will fill, it only allow to see data until we change the BackOffice to consume the Azure Mobile Service. Insert a similar dummy data for the others collection.

At this moment, we have a start point for the BackOffice App, is possible to define the theme, the tiles, the publish info, but this article will not cover it. For see in more depth how to define each one, see the article Creating Windows Phone and Window 8.1 applications using Microsoft App Studio.

 Generating the BackOffice app

Now we will click in “Finnish” button for generate the BackOffice App

The following screen will be showed

Click in “Generate” button for generate the source code

For generate the app for Windows 8.1 and Windows Phone 8.1 we should click in that option, that will be a Universal App, like the Menu App.

Click in the link for download the source code

Code

See the source code for the BackOffice App, here

Step 6: Add default BackOffice App generated by AppStudio

 

Changing the source code generated

Now we have a start point for the BackOffice, we will change the code for support editing the data consumed by the Azure Mobile Service

For add the MyMenuApp Azure Mobile Service to the BackOffice App, see the topic How to consume the Azure Mobile Services in Menu App . The changes in BackOffice are the same.

Note:

  1. The default columns added the “ImageUrl” in each collection, and each dto from the service uses the name “Image“. There are two option for fix this difference: rename the property “ImageUrl” for each collection and in the UI or using Json attributes for the property “ImageUrl” that will define the name as “Image“.

In the Azure Mobile Service we added the static data from Menu App, for this reason when we run the BackOffice App using the Azure Mobile Service it will not show the images, because the BackOffice App don´t have these images. For solve it for now, do a copy & paste of these images (it will be temporary!)

Running the app

Running the app we will get the following screens

The main view

The main view is the start page when the app launch, in this case, will be MainPage.xaml.

The collection view

The collection view will be the page that show a list of objects, in this case, will be

BeveragesPage.xamlDessertsPage.xamlMain1Page.xamlSpecialOffersPage.xaml andStartersPage.xaml.

The item view

The item view will be the page that show a specific item, in this case, will beBeveragesDetailPage.xamlDessertsDetailPage.xamlMain1DetailPage.xaml,
SpecialOffersDetailPage.xaml and StartersDetailPage.xaml.

The others collection has a similar views.

For now the BackOffice app, is only in read mode similar to the Menu App.

Add support for edit data

Here are the main changes we need to do

  • Change the item view for edit data
  • Add an AppBarButton for “Add” a new item in the collection view
  • Add two AppBarButton for “Save” & “Delete” the current item in the item view

    Note: We will only focus in Windows 8.1 App, for the Windows Phone 8.1 the changes are similar and in some cases the changes are shared.

 

Changing the UI (XAML)

 

Changing the data templates

For add the support for edit data, we need to change the item view. We should change the following views that can be found in the DataTemplate folder

Each one contains the DataTemplates used in each page.

For find which template should be changed open the BeveragesDetailPage.xaml, that it the page for see a selected Beverage. We will find the FlipView that contains the aItemTemplate defined, called Beverages1DetailDetail

With the cursor under the string “Beverages1DetailDetail” press F12 and theBeveragesViews.xaml will be opened, with focus in

<DataTemplate x:Key="Beverages1DetailDetail">

Change this template for something like

<DataTemplate x:Key="Beverages1DetailDetail">
        <StackPanel Margin="120,0,0,0">
            <TextBlock Text="Title:"
                     Style="{StaticResource ItemHeaderTextSnapped}" />
            <TextBox Grid.Row="0" Margin="0,20,0,0"  Grid.Column="1"
                     Text="{Binding Title, Mode=TwoWay}" Width="400" HorizontalAlignment="Left"/>
            <TextBlock Text="Subtitle:" Margin="0,20,0,0"
                     Style="{StaticResource ItemHeaderTextSnapped}" />
            <TextBox Grid.Row="0" Grid.Column="1"
                     Text="{Binding Subtitle, Mode=TwoWay}" Margin="0,20,0,0"  Width="400" HorizontalAlignment="Left"/>
            <TextBlock Text="Image:" Margin="0,20,0,0"
                     Style="{StaticResource ItemHeaderTextSnapped}" />
            <TextBox Grid.Row="0" Grid.Column="1" Margin="0,20,0,0"
                     Text="{Binding Image, Mode=TwoWay}" Width="400" HorizontalAlignment="Left"/>
            <Image Grid.RowSpan="2"
                   Source="{Binding Image}" Margin="0,20,0,0"
                   Width="200" Height="200"
                   HorizontalAlignment="Left" Stretch="UniformToFill" />
            <TextBlock Text="Description:" Margin="0,20,0,0"
                     Style="{StaticResource ItemHeaderTextSnapped}" />
            <TextBox Grid.Row="1" Grid.Column="1"
                     Margin="0,20,0,0" ScrollViewer.HorizontalScrollBarVisibility="Auto"
                     ScrollViewer.VerticalScrollBarVisibility="Auto"
                     AcceptsReturn="true" HorizontalAlignment="Left"
                     Height="200" MaxHeight="200" Width="800" MaxWidth="800"
                     Text="{Binding Description, Mode=TwoWay}" />
        </StackPanel>
</DataTemplate>


It will result in something like it

Do the same changes for Starters, Mains and Desserts. For Special Offers change the data template for something like it


<DataTemplate x:Key="SpecialOffers1DetailDetail">
    <StackPanel Margin="120,0,0,0">
        <TextBlock Text="Title:"
                 Style="{StaticResource ItemHeaderTextSnapped}" />
        <TextBox Grid.Row="0" Margin="0,20,0,0"  Grid.Column="1"
                 Text="{Binding Title, Mode=TwoWay}" Width="400" HorizontalAlignment="Left"/>
        <TextBlock Text="Subtitle:" Margin="0,20,0,0"
                 Style="{StaticResource ItemHeaderTextSnapped}" />
        <TextBox Grid.Row="0" Grid.Column="1"
                 Text="{Binding Subtitle, Mode=TwoWay}" Margin="0,20,0,0"  Width="400" HorizontalAlignment="Left"/>
        <TextBlock Text="Starter1:" Margin="0,20,0,0"
                 Style="{StaticResource ItemHeaderTextSnapped}" />
        <TextBox Grid.Row="0" Grid.Column="1"
                 Text="{Binding Starter1, Mode=TwoWay}" Margin="0,20,0,0"  Width="400" HorizontalAlignment="Left"/>
        <TextBlock Text="Main1:" Margin="0,20,0,0"
                 Style="{StaticResource ItemHeaderTextSnapped}" />
        <TextBox Grid.Row="0" Grid.Column="1"
                 Text="{Binding Main1, Mode=TwoWay}" Margin="0,20,0,0"  Width="400" HorizontalAlignment="Left"/>
         <TextBlock Text="Dessert1:" Margin="0,20,0,0"
                 Style="{StaticResource ItemHeaderTextSnapped}" />
        <TextBox Grid.Row="0" Grid.Column="1"
                 Text="{Binding Dessert1, Mode=TwoWay}" Margin="0,20,0,0"  Width="400" HorizontalAlignment="Left"/>
    </StackPanel>
</DataTemplate>

The result will be something like

At this moment, all data can be edited. Now we need to add options for persists it.

Adding the AppBarButtons

For allow to do the operations “Add”, “Save” and “Delete” is needed to add an AppBarButton for each operation.

In the BeveragesDetailPage.xaml add the following app bar


<Page.BottomAppBar>
    <CommandBar Background="{StaticResource AppBarBackground}">
      <AppBarButton DataContext="{Binding BeveragesModel}"
                    x:Uid="SaveButton"
                    Command="{Binding SaveCommand}">
        <AppBarButton.Icon>
          <BitmapIcon UriSource="ms-appx:///Assets/AppBar/Save.png"/>
        </AppBarButton.Icon>
      </AppBarButton>
            <AppBarButton DataContext="{Binding BeveragesModel}"
                    x:Uid="DeleteButton"
                    Command="{Binding DeleteCommand}">
                <AppBarButton.Icon>
                    <BitmapIcon UriSource="ms-appx:///Assets/AppBar/Delete.png"/>
                </AppBarButton.Icon>
            </AppBarButton>
        </CommandBar>
  </Page.BottomAppBar>


That will add the “Save” and “Delete” AppBarButton. This XAML can be added to the others object’s pages.

For add the “Add” AppBarButton, open the BeveragesPage.xaml an

public ICommand AddCommand
{
    get { return new DelegateCommand(AddItem); }
}
   
public ICommand DeleteCommand
{
    get { return new DelegateCommand(DeleteItem); }
}
   
public ICommand SaveCommand
{
    get { return new DelegateCommand(SaveItem); }
}
d added the following XAML

<Page.BottomAppBar>
    <CommandBar Background="{StaticResource AppBarBackground}">
            <AppBarButton x:Uid="AddButton"
                         Command="{Binding AddCommand}"
                        DataContext="{Binding BeveragesModel}">
                <AppBarButton.Icon>
                    <BitmapIcon UriSource="ms-appx:///Assets/AppBar/Add.png"/>
                </AppBarButton.Icon>
            </AppBarButton>
            <AppBarButton x:Uid="RefreshButton" DataContext="{Binding BeveragesModel}" Visibility="{Binding RefreshVisibility}"
                  Command="{Binding RefreshCommand}">
        <AppBarButton.Icon>
          <BitmapIcon UriSource="ms-appx:///Assets/AppBar/Refresh.png"/>
        </AppBarButton.Icon>
      </AppBarButton>
    </CommandBar>
  </Page.BottomAppBar>

Do the same for the others object’s pages.

For now is missing the commands for each AppBarButtonAddCommandSaveCommandand DeleteCommand.

Notes:

Changing the code be hide (C#)

Go to ViewModelBase.cs file in the Shared project

Scroll to the ViewModelBase<T> class and add the following commands

public ICommand AddCommand
{
    get { return new DelegateCommand(AddItem); }
}
 
public ICommand DeleteCommand
{
    get { return new DelegateCommand(DeleteItem); }
}
 
public ICommand SaveCommand
{
    get { return new DelegateCommand(SaveItem); }
}

After it, add the missed methods


public abstract bool CanSave();
 
public abstract void AddItemAsync();
 
private async void DeleteItemAsync ()
{
    // todo
}     
 
private async void SaveItemAsync ()
{
    // todo
}


The methods CanSave and AddItemAsync will be implemented in the view model for each object, more specific the view models: BeveragesViewModel, DessertsViewModel, Main1ViewModel, SpecialOffersViewModel and StartersViewModel. Because it needs to know each object will be added.

The DeleteItemAsync and SaveItemAsync can be implemented in ViewModelBase<T> class because they can be generic.

The DeleteItemAsync method

For the DeleteItemAsync method, we need to show a message to the user for confirm the operation, after it the item will be deleted and then the item will be removed from the Items list and will be raised notifications for update the UI.

The implementation will be something like it


private async void DeleteItemAsync()
{
    ProgressBarVisibility = Visibility.Visible;
    var currentItem = GetCurrentItem();
    var messageDialog = new MessageDialog(currentItem.DefaultTitle, "Are you sure you want to delete this item?");
    messageDialog.Commands.Add(new UICommand("Yes"));
    messageDialog.Commands.Add(new UICommand("No"));
    var result = await messageDialog.ShowAsync();
    if (result.Label == "Yes")
   {
        await DataSource.DeleteAsync(currentItem);
        Items.Remove(currentItem);
        OnPropertyChanged("PreviewItems");
        OnPropertyChanged("Items");
        OnPropertyChanged("HasMoreItems");
   }
 
    ProgressBarVisibility = Visibility.Collapsed;
}


This will require a changes in 
DataSourceBase<T> class

Where we will add the abstract methods for DeleteAsync and SaveAsync. These methods will be implemented in all specific data sources, for example in BeveragesDataSource we will do something like


public override async Task DeleteAsync(BeveragesSchema currentItem)
{
    await _mobileService.Table.DeleteAsync(currentItem);
    await UpdateCacheAsync();
}

This code applies to the others data sources: 
DessertsDataSourceMainDataSource,SpecialOffersDataSource and StartersDataSource.
The SaveItemAsync method

For the SaveItemAsync method, we will update the data and then will show a message to the user for confirm the operation was done and then the UI will be updated.

private async void SaveItem()
{
   if (!CanSave())
   {
        var cannotSaveMessageDialog = new MessageDialog("You must fill all data.", "Attention!");
        cannotSaveMessageDialog.Commands.Add(new UICommand("Ok"));
        await cannotSaveMessageDialog.ShowAsync();
        return;
   }
    ProgressBarVisibility = Visibility.Visible;
    var currentItem = GetCurrentItem();
    var messageDialog = new MessageDialog(currentItem.DefaultTitle, "The item was saved!");
    messageDialog.Commands.Add(new UICommand("Ok"));
    await DataSource.SaveAsync(currentItem);
    await messageDialog.ShowAsync();
    OnPropertyChanged("Items");
    OnPropertyChanged("PreviewItems");
    OnPropertyChanged("HasMoreItems");
    ProgressBarVisibility = Visibility.Collapsed;
}

In  BeveragesDataSource we will do something like

public override async Task SaveAsync(BeveragesSchema currentItem)
{
    BeveragesSchema item = null;
    if (currentItem.IsNew)
    {
        await _mobileService.Table.InsertAsync(currentItem);
    }
    else
    {
        await _mobileService.Table.UpdateAsync(currentItem);
    }
    currentItem.IsNew = false;
    await UpdateCache();
}

This code applies to the others data sources: 
DessertsDataSourceMainDataSource,SpecialOffersDataSource and StartersDataSource.

Note: When an item is saved, the item can be new or can be an existing item, for this reason was created a IsNew property for each object that allow to understand if we will do an Insert or an Update.

The UpdateCacheAsync method

The UpdateCacheAsync is a method used for update the cache for each collection, this code was provided by AppStudio, when we generated the app, only was applied a refactoring in LoadDataAsync method for reuse code.

public async Task<DateTime> LoadDataAsync(ObservableCollection<T> viewItems, bool forceRefresh)
{
    DateTime timeStamp = DateTime.Now;
   
    if (HasStaticData)
    {
        viewItems.AddRangeUnique(await LoadDataAsync());
    }
    else
    {
        var dataInCache = await AppCache.GetItemsAsync<T>(CacheKey);
        if (dataInCache != null)
        {
            timeStamp = dataInCache.TimeStamp;
   
            viewItems.AddRangeUnique(dataInCache.Items);
        }
   
        if (NetworkInterface.GetIsNetworkAvailable() && DataNeedToBeUpdated(forceRefresh, dataInCache))
        {
            var freshData = await UpdateCacheAsync();
   
            viewItems.AddRangeUnique(freshData.Items);
            timeStamp = freshData.TimeStamp;
        }
    }
    return timeStamp;
}

And then we will have

internal async Task<DataSourceContent<T>> UpdateCacheAsync()
{
    var freshData = new DataSourceContent<T>()
    {
        TimeStamp = DateTime.Now,
        Items = await LoadDataAsync()
    };
 
    await AppCache.AddItemsAsync(CacheKey, freshData);
    return freshData;
}

Note
: Each data source must be not static, for it use the property HasStaticData.
The AddItemAsync method

For the AddItemAsync method, the implementation must be done in BeveragesViewModel,DessertsViewModelMain1ViewModelSpecialOffersViewModel and StartersViewModel.

For example, in BeveragesViewModel we will create a BeveragesSchema that is new and it will be added to the Items list, then the app will navigate to the item view for allow to edit this new object.

The implementation will be something like

public override void AddItemAsync()
{
    ProgressBarVisibility = Visibility.Visible;
 
    ProgressBarVisibility = Visibility.Visible;
    var newItem = new BeveragesSchema();
    newItem.IsNew = true;
    Items.Add(newItem);
    NavigationServices.NavigateToPage("BeveragesDetail", newItem);
    OnPropertyChanged("PreviewItems");
    OnPropertyChanged("HasMoreItems");
 
    ProgressBarVisibility = Visibility.Collapsed;
    ProgressBarVisibility = Visibility.Collapsed;
}

And in BeveragesDetailPage.xaml.cs in OnNavigateTo change the code for receive the parameter sent in AddItemAsync method

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    _dataTransferManager = DataTransferManager.GetForCurrentView();
    _dataTransferManager.DataRequested += OnDataRequested;
 
    _navigationHelper.OnNavigatedTo(e);
 
    await BeveragesModel.LoadItemsAsync();
    if (e.Parameter is BeveragesSchema)
    {
        BeveragesModel.Items.Add(e.Parameter as BeveragesSchema);
    }
    BeveragesModel.SelectItem(e.Parameter);
 
    if (BeveragesModel != null)
    {
        BeveragesModel.ViewType = ViewTypes.Detail;
    }
    DataContext = this;
}

For the others objects the process is similar.
The CanSave method

The CanSave method will define if an item can be saved or not, for it used some validations.

The implementation, for Beverages, Starters and Mains, will be something like

public override bool CanSave()
{
    return !string.IsNullOrEmpty(SelectedItem.Title) &&
           !string.IsNullOrEmpty(SelectedItem.Subtitle) &&
           !string.IsNullOrEmpty(SelectedItem.Image) &&
           !string.IsNullOrEmpty(SelectedItem.Description);
}

For Special Offers will be something like

public override bool CanSave()
{
    return !string.IsNullOrEmpty(SelectedItem.Title) &&
          !string.IsNullOrEmpty(SelectedItem.Subtitle) &&
          !string.IsNullOrEmpty(SelectedItem.Starter1) &&
          !string.IsNullOrEmpty(SelectedItem.Main1) &&
          !string.IsNullOrEmpty(SelectedItem.Dessert1);
}

A
t this moment, the BackOffice App has support for edit the data received from the Azure Mobile Service and can persist.

Changing the theme and assets

In the AppStudio we could change the theme and the assets for the BackOffice app, but is possible do the same in the code. For the BackOffice App we will add the same theme and assets from the Menu App. For it, go to the Assets folder for Windows 8.1 app and copy and paste the images related with logos

For change the theme, go to the Style folder in Windows 8.1 app, open the fileAppStyles.xaml and replace the following styles

Running the App

Now that the BackOffice supports editing the data and has a new look, let’s see how it looks.

The main view

The main view will be the start page, in this case, will be the MainPage.xaml.

The collection view

The collection view will be the pages that show a list of objects, in this case, will be

BeveragesPage.xamlDessertsPage.xamlMain1Page.xamlSpecialOffersPage.xaml andStartersPage.xaml.

The item view

The item view the pages that show a specific item, in this case, will beBeveragesDetailPage.xamlDessertsDetailPage.xamlMain1DetailPage.xaml,
SpecialOffersDetailPage.xaml and StartersDetailPage.xaml.

For existing item

For a new item

For have the app bar opened each time each navigate to the collection view or the item view we should add the following definition to the OnNavigationTo for each page

BottomAppBar.IsOpen = true;
BottomAppBar.IsSticky = true;


Code

See the source code for the BackOffice App, here

Step 7: Changes the BackOffice app: add support for edit data from Azure Mobile Service and add new theme and assets.

shopify analytics ecommerce tracking