Uploading sample code and documentation
После Ширина: | Высота: | Размер: 32 KiB |
После Ширина: | Высота: | Размер: 53 KiB |
После Ширина: | Высота: | Размер: 166 KiB |
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 26 KiB |
После Ширина: | Высота: | Размер: 25 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 53 KiB |
После Ширина: | Высота: | Размер: 26 KiB |
После Ширина: | Высота: | Размер: 29 KiB |
После Ширина: | Высота: | Размер: 6.4 KiB |
После Ширина: | Высота: | Размер: 17 KiB |
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 22 KiB |
После Ширина: | Высота: | Размер: 48 KiB |
После Ширина: | Высота: | Размер: 40 KiB |
После Ширина: | Высота: | Размер: 1.9 KiB |
После Ширина: | Высота: | Размер: 17 KiB |
После Ширина: | Высота: | Размер: 24 KiB |
После Ширина: | Высота: | Размер: 26 KiB |
После Ширина: | Высота: | Размер: 23 KiB |
После Ширина: | Высота: | Размер: 26 KiB |
После Ширина: | Высота: | Размер: 31 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 13 KiB |
После Ширина: | Высота: | Размер: 16 KiB |
После Ширина: | Высота: | Размер: 50 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 13 KiB |
После Ширина: | Высота: | Размер: 54 KiB |
После Ширина: | Высота: | Размер: 9.5 KiB |
После Ширина: | Высота: | Размер: 21 KiB |
После Ширина: | Высота: | Размер: 59 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 30 KiB |
После Ширина: | Высота: | Размер: 35 KiB |
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 31 KiB |
После Ширина: | Высота: | Размер: 43 KiB |
После Ширина: | Высота: | Размер: 19 KiB |
После Ширина: | Высота: | Размер: 32 KiB |
После Ширина: | Высота: | Размер: 7.9 KiB |
После Ширина: | Высота: | Размер: 27 KiB |
После Ширина: | Высота: | Размер: 27 KiB |
После Ширина: | Высота: | Размер: 65 KiB |
После Ширина: | Высота: | Размер: 38 KiB |
После Ширина: | Высота: | Размер: 16 KiB |
|
@ -0,0 +1,146 @@
|
|||
# Creating the Azure Function in Visual Studio
|
||||
|
||||
The great thing with the Azure tooling is that you can decide what tools you are more comfortable with. You can decide to [create the function in the Azure web portal](./creating.md), or you can take advantage of Visual Studio and its complete suite of tools, including unit testing, performance analysis, local debugging etc. In this section, we will show how the function can be created in Visual Studio, how to run the function locally to test it and how to publish it to Azure.
|
||||
|
||||
> Note: You can find more tutorials and quickstarts on the Azure Functions documentation page](http://gslb.ch/a10).
|
||||
|
||||
## Creating the function application
|
||||
|
||||
To create the function application in Visual Studio, you will need Visual Studio 2017. You can perform these steps in any edition of Visual Studio, [including the free Community edition](http://gslb.ch/a72). In the installer, make sure that the Azure development workload is installed.
|
||||
|
||||
![Visual Studio installer](./Img/2018-01-05_13-43-24.png)
|
||||
|
||||
1. Start Visual Studio 2017.
|
||||
|
||||
2. Select File > New > Project from the menu bar.
|
||||
|
||||
3. In the New Project dialog, select the Cloud category and then Azure Functions.
|
||||
|
||||
4. Enter a name for the Function application. Note that you can have multiple functions in one Function application. Then press OK.
|
||||
|
||||
5. In the New Template dialog, select Http trigger and the following options:
|
||||
|
||||
- Azure Functions v2 Preview (.NET Core). If you prefer, you can also select Azure Functions v1 (.NET Framework). The advantage of a .NET core function application is that it can run on servers with Linux. However some features are unavailable at this point.
|
||||
- Under Storage Account, select None. This particular sample doesn't require storage. However if your function needs data, tables, etc., you may want to connect it to an Azure Storage account.
|
||||
- Set Access rights to Function.
|
||||
|
||||
![New Template dialog](./Img/2018-01-15_15-01-00.png)
|
||||
|
||||
When the function application is created, it gives the default name "Function1" to the function. You will need to rename it to something more meaningful.
|
||||
|
||||
5. Rename the ```Function1.cs``` file to ```Add.cs```.
|
||||
|
||||
6. Open the ```Add.cs``` file in the code editor and modify the code as shown here:
|
||||
|
||||
```CS
|
||||
public static class Add
|
||||
{
|
||||
[FunctionName("Add")]
|
||||
public static IActionResult Run(
|
||||
[HttpTrigger(
|
||||
AuthorizationLevel.Function,
|
||||
"get",
|
||||
Route = "add/num1/{num1}/num2/{num2}")]
|
||||
HttpRequest req,
|
||||
int num1,
|
||||
int num2,
|
||||
TraceWriter log)
|
||||
{
|
||||
log.Info($"C# HTTP trigger function processed a request with {num1} and {num2}");
|
||||
|
||||
var addition = num1 + num2;
|
||||
|
||||
return new OkObjectResult(addition);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There are a few interesting things about the code above:
|
||||
|
||||
- We changed the ```Run``` method's signature. The Azure Functions runtime will use this information to configure the service. First, we removed the ```"post"``` method because we want this function to only accept ```get``` methods. Then we modified the ```Route``` parameter of the ```HttpTrigger``` attribute. We declare the new route to be ```"add/num1/{num1}/num2/{num2}"```. In the client code, when we call the URL, we will replace ```{num1}``` with the first operand of the addition, and ```{num2}``` with the second operand.
|
||||
|
||||
- We declare two parameters named ```num1``` and ```num2``` of type ```int```. Conveniently, the Azure Functions runtime will automatically convert the ```{num1}``` and ```{num2}``` parts of the URL into the corresponding integers.
|
||||
|
||||
- We log an entry when the function is called. You can see the log entry in the debug window later, or in the Azure web portal. Logging can be very useful to debug some difficult issues.
|
||||
|
||||
- We then execute the addition with the two operands and return an ```OkObjectResult``` which will translate to an OK HTTP response .
|
||||
|
||||
> Note: since HTTP is a text-based protocol, the result of the addition will be returned to the client as text. [Later we will see how modern APIs use the JavaScript Object Notation (JSON)](./refactoring.md) to encode API inputs and outputs. JSON can easily be serialized and deserialized.
|
||||
|
||||
## Testing the function
|
||||
|
||||
One of the greatest advantages of Visual Studio over the Azure web portal for function creation and implementation is that you can run the function locally, which is very convenient for test purposes.
|
||||
|
||||
1. In the code editor, in Add.cs, place a breakpoint on the first line of the Run method, where the log call is placed.
|
||||
|
||||
2. Run the function in debug mode. This will start the Azure Functions runtime in a command window.
|
||||
|
||||
> Note: The Azure Functions runtime which is installed locally is an exact copy of the Azure Functions runtime running in Azure. This is not a simulator. This ensures that you get conditions as closed to reality as possible.
|
||||
|
||||
3. At the bottom of the command window, you will find the local URL of the function. Copy this URL which should be similar to ```http://localhost:7071/api/add/num1/{num1}/num2/{num2}```
|
||||
|
||||
![Command window with Function runtime](./Img/2018-01-15_15-57-00.png)
|
||||
|
||||
4. Open a web browser window and paste the URL in the location bar.
|
||||
|
||||
5. In the URL, replace ```{num1}``` with an integer, for example 12. Then replace ```{num2}``` with another integer, for example 34. Then press Enter to load the page.
|
||||
|
||||
6. The application should break in the debugger in Visual Studio, at the breakpoint that you placed earlier. You can now inspect the ```num1``` and ```num2``` operands, and step through the function's code to debug it. Finally you should see the result, for example ```46``` in the web browser window.
|
||||
|
||||
## Publishing the function to Azure
|
||||
|
||||
Now that we have created and tested the function, we can publish it to Azure. In practice for larger applications, the Publishing step would be taken care of by a script and some tooling. Also, we wouldn't publish to a production server first, but we would deploy to a test server and run additional tests before moving the code to production.
|
||||
|
||||
In this simple sample, we will use the [Publish feature of Visual Studio](http://gslb.ch/a76) instead.
|
||||
|
||||
1. In the Solution Explorer, right click on the functions application and select Publish from the context menu.
|
||||
|
||||
![Publish](./Img/2018-01-04_11-14-39.png)
|
||||
|
||||
2. In the next dialog, select Create New in order to create a new Functions application. In this dialog, you could also select an existing Functions application if you have one that you wish to replace.
|
||||
|
||||
![Publish dialog](./Img/2018-01-04_11-15-00.png)
|
||||
|
||||
3. In the Create Service dialog, set the following information:
|
||||
|
||||
- App Name: This is the name that will be used in the Azure portal.
|
||||
|
||||
> Note: The function's name should be unique and will appear in the function's URL. For example if the function is named LbCalculator, the domain will be ```https://lbcalculator.azurewebsites.net```.
|
||||
|
||||
- Subscription: This is the Azure subscription that will be billed. Note that you can create a free subscription for trial at [https://azure.microsoft.com/free](http://gslb.ch/a17).
|
||||
|
||||
- Resource group: This is a logical grouping of your application's resources, to make it easier to manage them. You can create a new resource group or select am existing one.
|
||||
|
||||
- App service plan: This is the billing plan that you can use for this Azure Functions application. App Service plans can also be used for other app services such as web applications, web APIs, etc. You can find more information about [App service plans in the Azure documentation](https://docs.microsoft.com/en-us/azure/app-service/azure-web-sites-web-hosting-plans-in-depth-overview).
|
||||
|
||||
![Create App Service](./Img/2018-01-04_11-30-09.png)
|
||||
|
||||
3. Click on the Create button. After the publication succeeds you will see a new dialog with information about the application.
|
||||
|
||||
![Successful publication](./Img/2018-01-04_11-32-51.png)
|
||||
|
||||
## Getting the URL for the Xamarin client app
|
||||
|
||||
Later in the sample, we will need the URL of the service for our client app. Since all the communication between the client and the server happens over HTTP, the URL is the interface for it.
|
||||
|
||||
1. Log into the Azure web portal. In the menu on the left, select Function Apps.
|
||||
|
||||
![Azure Web Portal menu](./Img/2018-01-04_11-34-15.png)
|
||||
|
||||
2. Locate the functions application that you just published and click on the Add menu item.
|
||||
|
||||
![Add function](./Img/2018-01-04_11-34-46.png)
|
||||
|
||||
3. Above the code editor window, click on the "Get function URL" button.
|
||||
|
||||
![Get Function URL](./Img/2018-01-04_11-35-04.png)
|
||||
|
||||
4. Copy the URL from the pop-up window and keep it safe for later.
|
||||
|
||||
![Function URL](./Img/2018-01-04_11-35-45.png)
|
||||
|
||||
## Conclusion
|
||||
|
||||
Our function's code is now complete and available for additional features in Visual Studio. We can now [modify to the client app's implementation to use the function](./second-client.md).
|
||||
|
||||
Later we will also refactor [the server](./refactoring.md) and [the client](./refactoring-client.md) to use JavaScript Object Notation JSON to communicate.
|
|
@ -0,0 +1,94 @@
|
|||
# Creating the Azure Function in the Azure Web Portal
|
||||
|
||||
In this section, we will build the Azure Functions application in the Azure web portal and then add an HTTP Triggered function. This will allow us to call the function from the Xamarin client, for example with an [HttpClient](http://gslb.ch/a75) instance.
|
||||
|
||||
> Note: If you prefer, you can create the Azure Function in Visual Studio 2017 instead. [A detailed tutorial can be found here](./creating-vs.md).
|
||||
|
||||
To create the Azure Functions application in the Azure portal, follow these steps:
|
||||
|
||||
1. Log into the [Azure Portal](http://portal.azure.com) with your user account.
|
||||
|
||||
> Note: You will need an Azure account to create this sample. If you don't have one already, [you can get a free trial account here](http://gslb.ch/a17).
|
||||
|
||||
2. Click the "Create a resource" menu item.
|
||||
|
||||
![Create a resource](./Img/2017-12-25_11-28-43.png)
|
||||
|
||||
3. In the Azure Marketplace, select "Serverless Function App".
|
||||
|
||||
![Serverless Function App](./Img/2017-12-25_11-29-38.png)
|
||||
|
||||
4. Fill the form with the following data:
|
||||
|
||||
- App Name: This is a unique name for your application. One application can contain multiple functions.
|
||||
|
||||
- Subscription: The subscription to which these functions will be billed. In some cases you will only see one subscription here, but some people have multiple subscriptions associated to their account.
|
||||
|
||||
- Resource group: This is a logical grouping of Azure resources. It makes sense to have one resource group per application, so you can easily locate the resources that you are using. In this case we are creating a new resource group for this application.
|
||||
|
||||
- OS: The operating system of the server on which the functions will run.
|
||||
|
||||
- Hosting plan: This shows how the function usage will be billed.
|
||||
- Consumption plan means that the function will be billed whenever it is called, and only for the time that it runs. This is the best plan to get started.
|
||||
- App Service Plan is best after your business starts attracting more users and you need some more predictable billing.
|
||||
|
||||
- Location will be the physical location of the server on which your functions will run. You should choose a server close to your users.
|
||||
|
||||
- Storage: You can either create a new storage account, or use an existing one. Note that this sample doesn't use storage but you still need to specify a storage account.
|
||||
|
||||
> Note: The storage account name should be entered in lower case.
|
||||
|
||||
- Application Insights: If you want to add extra analytics on your functions application, you can switch this on. This provides you with stats about the usage, crash reports, custom events, etc. In this sample we will not use Application Insights.
|
||||
|
||||
![Creating the function app](./Img/2017-12-25_11-31-10.png)
|
||||
|
||||
5. Click the Create button. This will trigger the deployment, and you should see a popup like shown below.
|
||||
|
||||
![Deployment in progress](./Img/2017-12-25_11-31-59.png)
|
||||
|
||||
6. After a moment, you should see a new notification: Deployment succeeded. You can then click the button to go to the resource, or simply close the notification.
|
||||
|
||||
![Deployment succeeded](./Img/2017-12-25_11-33-09.png)
|
||||
|
||||
> Note: You can always go back to the application by clicking on the Function Apps menu item on the left-hand side.
|
||||
|
||||
![Function Apps menu item](./Img/2017-12-25_11-33-36.png)
|
||||
|
||||
7. Once you are in the Functions Apps section in the portal, expand the application itself. Next to the "Functions" submenu, click on the "+" sign when you hover over the submenu.
|
||||
|
||||
![Application submenus](./Img/2017-12-25_11-40-33.png)
|
||||
|
||||
Now we need to choose what will *trigger* the function that we will create. There are a large number of triggers available and we cannot review all of them here, but there is [documentation available on our Docs website](http://gslb.ch/a63). The most common triggers are:
|
||||
|
||||
- [HTTP Trigger](http://gslb.ch/a65): The function will be executed when an HTTP request arrives. This is the type of trigger we will use.
|
||||
- [Timer trigger](http://gslb.ch/a66): The function is executed every interval of time, where the interval is specified [by a CRON expression](https://en.wikipedia.org/wiki/Cron#CRON_expression).
|
||||
- [Blob trigger](http://gslb.ch/a64): The function is executed when a file is uploaded to a given blob container
|
||||
- [and more...](http://gslb.ch/a63)
|
||||
|
||||
8. Click on the "Custom function" button as shown below.
|
||||
|
||||
![Custom function](./Img/2017-12-25_11-41-25.png)
|
||||
|
||||
9. You will now see a large list of potential triggers, which can be implemented in various languages. Scroll down until you see the "HTTP trigger with parameter". In this sample, we will create the function in C#, so click the corresponding button.
|
||||
|
||||
![HTTP trigger with parameter](./Img/2017-12-25_12-14-21.png)
|
||||
|
||||
10. Enter a name for the function (for example "Add") and press Create.
|
||||
|
||||
![Function creation](./Img/2017-12-25_12-15-02.png)
|
||||
|
||||
11. The function is created, and some basic implementation is added. Let's test to see how the function works. Since it is an HTTP trigger, we can execute the function by calling a URL. You can get the URL from the top right corner, where the "Get function URL" button is found.
|
||||
|
||||
![Get function URL](./Img/2017-12-25_12-22-15.png)
|
||||
|
||||
12. Copy the URL from the popup window.
|
||||
|
||||
![Function URL](./Img/2017-12-25_12-23-13.png)
|
||||
|
||||
13. Open a web browser window and paste the link into the location bar. Before you press the Enter key, make sure to replace the ```{name}``` parameter in the URL with your own name. Then press enter and you should see the response "Hello Laurent" appear (except that your own name should be shown instead of Laurent).
|
||||
|
||||
## Conclusion
|
||||
|
||||
We now have the infrastructure in place for our Azure Function. Once you are a bit more experienced, the process of creating such a function should not take more than a few minutes.
|
||||
|
||||
[In the next section, we will now modify the function's interface and then implement it.](./implementing.md)
|
|
@ -0,0 +1,162 @@
|
|||
# Implementing the first version of the Xamarin.Forms client app
|
||||
|
||||
We will start this sample by creating a Xamarin.Forms client app which works offline. Then we will see how we can transfer the business logic of this app to the Azure cloud.
|
||||
|
||||
> Note: If you are already familiar with Xamarin.Forms, you can jump to the next step without fear. You will find the client that we create in this page in [the XamCalculator - Start folder](https://github.com/lbugnion/sample-azure-simplexamarinfunction/tree/master/XamCalculator%20-%20Start).
|
||||
|
||||
The Xamarin client app that we create here is extremely simple and obviously not a real life scenario. However it shows all the steps necessary to creating the client and the server applications, and it should give you a good jumpstart into your own projects and use cases.
|
||||
|
||||
1. In Visual Studio 2017, select File > New > Project.
|
||||
|
||||
> Note: We use Visual Studio 2017 on Windows for this sample, but you can also create Xamarin.Forms applications in Visual Studio for Mac if you prefer. Xamarin is available for free in all editions of Visual Studio, including the free Community edition, on PC and Mac.
|
||||
> - [Visual Studio Community Edition for Windows](http://gslb.ch/a72)
|
||||
> - [Visual Studio for Mac](http://gslb.ch/a73)
|
||||
|
||||
2. In the New Project dialog, select the Cross-Platform category, and then Cross-Platform App (Xamarin.Forms) with Visual C#. Name the new application ```XamCalculator```, select a location for the project and press OK.
|
||||
|
||||
![New Project](./Img/2017-12-25_12-51-53.png)
|
||||
|
||||
> Note: The Cross-platform category is available if you selected the "Mobile development with .NET" workload in the Visual Studio 2017 installer.
|
||||
|
||||
3. In the New Cross Platform App dialog, select the following settings, then press OK.
|
||||
- Android, iOS and Windows
|
||||
- Xamarin.Forms
|
||||
- .NET Standard
|
||||
|
||||
![New Cross Platform App](./Img/2017-12-25_12-55-16.png)
|
||||
|
||||
The new application consists of 4 projects:
|
||||
|
||||
- XamCalculator: This is the shared .NET Standard project, where we will implement the UI and the code calling the function. This project is referenced by each of the 3 other projects.
|
||||
- XamCalculator.Android: The Android version of the application.
|
||||
- XamCalculator.iOS: The iOS version of the application.
|
||||
- XamCalculator.UWP: The Universal Windows Platform (UWP) of the application.
|
||||
|
||||
Later we will see how we can select each application to test it and run it.
|
||||
|
||||
4. In the XamCalculator project, select the MainPage.xaml and open it in the editor.
|
||||
|
||||
5. Replace the existing XAML with the following:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:local="clr-namespace:XamCalculator"
|
||||
x:Class="XamCalculator.MainPage">
|
||||
|
||||
<StackLayout VerticalOptions="Center"
|
||||
HorizontalOptions="Fill">
|
||||
|
||||
<Entry x:Name="Number1"
|
||||
Placeholder="Enter the first integer"
|
||||
PlaceholderColor="Gray" />
|
||||
|
||||
<Entry x:Name="Number2"
|
||||
Placeholder="Enter the second integer"
|
||||
PlaceholderColor="Gray" />
|
||||
|
||||
<Button Text="Add"
|
||||
x:Name="AddButton" />
|
||||
|
||||
<Label x:Name="Result"
|
||||
FontSize="Large"
|
||||
HorizontalOptions="Center"
|
||||
Text="Ready for operation" />
|
||||
|
||||
</StackLayout>
|
||||
</ContentPage>
|
||||
```
|
||||
|
||||
The code above creates a new user interface with 4 UI elements placed under each other. The layout is performed by the ```StackLayout``` panel. By default, the StackLayout uses a vertical layout, but it could also be changed to horizontal if needed. [There are many other layout types](http://gslb.ch/a67) that can be used to create more complex layouts.
|
||||
|
||||
- The first and second UI elements are [Entry controls](http://gslb.ch/a68) where the user will be able to enter some text. We will access this text from the code behind. Note how we use the [Placeholder property](http://gslb.ch/a69) to show a placeholder text when the field is empty. The controls are named ```Number1``` and ```Number2```.
|
||||
|
||||
- The third element is a [Button control](http://gslb.ch/a70). This control can be clicked by the user, which will create an event that we will respond to. The button is named ```AddButton```.
|
||||
|
||||
- The last element is a [Label control](http://gslb.ch/a71), used to show some simple text output to the user. The Label is named ```Result```.
|
||||
|
||||
6. Open the MainPage.xaml.cs now. This C# code file is what we call "code behind". This is the view's controller, where we will handle events and modify the UI accordingly.
|
||||
|
||||
7. Modify the MainPage class to look like this:
|
||||
|
||||
```CS
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
AddButton.Clicked += async (s, e) =>
|
||||
{
|
||||
int number1 = 0, number2 = 0;
|
||||
|
||||
var success = int.TryParse(Number1.Text, out number1)
|
||||
&& int.TryParse(Number2.Text, out number2);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
await DisplayAlert(
|
||||
"Error in inputs",
|
||||
"You must enter two integers", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = number1 + number2;
|
||||
Result.Text = result + $" {result.GetType()}";
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Let's review the code above:
|
||||
|
||||
- In the ```MainPage``` constructor, we handle the Clicked event of the Button control. When this event is called, the event handler will be executed.
|
||||
|
||||
- We parse the text that the user entered. We want to make sure that we send integers to the server, to avoid error there. Parsing the text with the ```TryParse``` method ensures that the user input is suitable.
|
||||
|
||||
- If the user enters incorrect inputs, we show a warning message and we stop the execution.
|
||||
|
||||
- If the user input is correct, we perform the addition.
|
||||
|
||||
- Finally, we show the result to the user, as well as the type of the result.
|
||||
|
||||
Now we can test the application and see if it works as expected.
|
||||
|
||||
## Testing the app
|
||||
|
||||
You can run and test the application on an emulator/simulator, or on a device directly.
|
||||
|
||||
### On Android
|
||||
|
||||
For example, here is how you can test the app on Android:
|
||||
|
||||
1. Right-click on the Android application and select "Set as Startup Project".
|
||||
|
||||
![Android application](./Img/2018-01-04_15-25-17.png)
|
||||
|
||||
2. Make sure that an emulator is selected in the Run dropdown.
|
||||
|
||||
![Run button](./Img/2018-01-04_15-26-08.png)
|
||||
|
||||
3. Press the Run button to debug the code.
|
||||
|
||||
4. In the emulator window, enter two operands and press the Add button. After a short wait, you should see the result.
|
||||
|
||||
![Android application](./Img/2018-01-14_10-57-00.png)
|
||||
|
||||
### On iOS and Windows
|
||||
|
||||
You can of course also test on iOS and Windows. To do this [you can follow the steps described here](./second-client.md#testing-the-client-app). The result you will see should be very similar to what you see on Android.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Our "offline" client app works great, but now is the time to leverage the power of the cloud. Of course for this extremely simple sample, putting code in the cloud makes literally no sense. However there are many other scenarios where leveraging Azure is a great idea:
|
||||
|
||||
- You can take advantage of a server to process calculations that would be too complex or too slow on a mobile client.
|
||||
|
||||
- You can have one server processing the code and caching the results instead of thousands of mobile clients, thus saving resources.
|
||||
|
||||
- and dozens more reasons.
|
||||
|
||||
We will now show you how to create an Azure Functions app ([in the Azure portal](./creating.md) or [in Visual Studio 2017](./creating-vs.md)), move the business logic code from the Xamarin client app to the cloud, and then [modify the Xamarin client app](./second-client.md) to use this new online resource.
|
|
@ -0,0 +1,130 @@
|
|||
# Modifying the function's interface and implementing it
|
||||
|
||||
At this stage [we have created a basic function with the default implementation in the Azure portal](./creating.md). Now we are going to modify its interface to suit our purpose, and we will implement its code.
|
||||
|
||||
> Note: You can also create the Azure Function in Visual Studio 2017 if you prefer. [You can find a complete tutorial here](./creating-vs.md).
|
||||
|
||||
## Modifying the interface
|
||||
|
||||
At the moment, our function's URL looks something like:
|
||||
|
||||
```https://xamfunctionssample.azurewebsites.net/HttpTriggerCSharp/name/{name}?code=9r9jauRrThIFjGcP1nz3xRJLiriF9IAo5dmPlsLHBfS4hq0gv06E7A==```
|
||||
|
||||
What we need for our "Add" function however is two operands. We will call them ```num1``` and ```num2```. Also, the name ```HttpTriggerCSharp``` is not very descriptive and we will use a better name such as ```add```. So our target URL should be:
|
||||
|
||||
```https://xamfunctionssample.azurewebsites.net/api/add/num1/{num1}/num2/{num2}?code=9r9jauRrThIFjGcP1nz3xRJLiriF9IAo5dmPlsLHBfS4hq0gv06E7A==```
|
||||
|
||||
1. In the web portal, under the function's name, click on the Integrate menu item.
|
||||
|
||||
![Integrate menu item](./Img/2017-12-25_12-24-48.png)
|
||||
|
||||
2. Modify the ```Route template``` to look like the following:
|
||||
|
||||
```
|
||||
add/num1/{num1}/num2/{num2}
|
||||
```
|
||||
|
||||
![Route template](./Img/2017-12-25_12-25-55.png)
|
||||
|
||||
3. Click again on the name of the function, just above the Integrate menu item. This should display the code again in the editor window.
|
||||
|
||||
4. Modify the code to look like this:
|
||||
|
||||
```CS
|
||||
using System.Net;
|
||||
|
||||
public static HttpResponseMessage Run(
|
||||
HttpRequestMessage req,
|
||||
int num1,
|
||||
int num2,
|
||||
TraceWriter log)
|
||||
{
|
||||
log.Info($"C# HTTP trigger function processed a request with {num1} and {num2}");
|
||||
|
||||
// Fetching the name from the path parameter in the request URL
|
||||
return req.CreateResponse(HttpStatusCode.OK, $"Called {num1} + {num2}" );
|
||||
}
|
||||
```
|
||||
|
||||
The code above expects two parameters ```num1``` and ```num2``` of type ```int```. The mapping between the URL and the function's signature will be done by the Azure Functions runtime.
|
||||
|
||||
## Testing the new signature
|
||||
|
||||
You can test the new signature with the following steps:
|
||||
|
||||
1. In the web portal, under the function's code, expand the Logs section.
|
||||
|
||||
![Logs](./Img/2017-12-27_14-26-46.png)
|
||||
|
||||
2. Click again on the "Get function URL" button on the top right corner.
|
||||
|
||||
3. Copy the URL from the popup box. Notice that it should correspond to the URL we wanted to target earlier.
|
||||
|
||||
4. Paste the URL in the location bar of a new browser window.
|
||||
|
||||
5. Replace the ```{num1}``` parameter with an integer, for example ```12```.
|
||||
|
||||
6. Replace the ```{num2}``` parameter with another integer, for example ```34```.
|
||||
|
||||
7. Press enter to load the URL in the browser window. After a short wait, you should see the result:
|
||||
|
||||
```
|
||||
Called 12 + 34
|
||||
```
|
||||
|
||||
8. Switch back to the logs section in the function's browser window. You should see a log entry there looking like:
|
||||
|
||||
```
|
||||
2017-12-27T13:30:05.126 Function started (Id=525c6fba-a346-4df7-a133-007660da482e)
|
||||
|
||||
2017-12-27T13:30:05.254 C# HTTP trigger function processed a request with 12 and 34
|
||||
|
||||
2017-12-27T13:30:05.254 Function completed (Success, Id=525c6fba-a346-4df7-a133-007660da482e, Duration=129ms)
|
||||
```
|
||||
|
||||
In case there is an issue with the function, the log window will give additional indications. You can of course add more logging calls if necessary.
|
||||
|
||||
## Implementing the Add function
|
||||
|
||||
Now that we know that the function works with the new signature, we can implement the addition code:
|
||||
|
||||
1. Replace the function's body with the following code:
|
||||
|
||||
```CS
|
||||
using System.Net;
|
||||
|
||||
public static HttpResponseMessage Run(
|
||||
HttpRequestMessage req,
|
||||
int num1,
|
||||
int num2,
|
||||
TraceWriter log)
|
||||
{
|
||||
log.Info($"C# HTTP trigger function processed a request with {num1} and {num2}");
|
||||
|
||||
var addition = num1 + num2;
|
||||
|
||||
// Fetching the name from the path parameter in the request URL
|
||||
return req.CreateResponse(HttpStatusCode.OK, addition);
|
||||
}
|
||||
```
|
||||
|
||||
2. Return to the previous browser window where we tested the function's signature before, and refresh the page. After a short wait, you should now see the result ```46```.
|
||||
|
||||
Interestingly, in the code above we simply declared that ```num1``` and ```num2``` are integers, and the Azure Functions runtime automatically parsed the values from the URL into integers for us. This is quite convenient.
|
||||
|
||||
## Getting the URL for the Xamarin client app
|
||||
|
||||
Later in the sample, we will need the URL of the service for our client. Since all the communication between the client and the server happens over HTTP, the URL is the interface for it.
|
||||
|
||||
3. In the web portal, above the code editor window, click on the "Get function URL" button.
|
||||
|
||||
![Get function URL](./Img/2017-12-25_12-22-15.png)
|
||||
|
||||
4. Copy the URL from the pop-up window and keep it safe for later.
|
||||
|
||||
![Function URL](./Img/2018-01-03_14-40-53.png)
|
||||
|
||||
## Conclusion
|
||||
|
||||
Our function's code is now complete. We can now [move to the client's implementation](./first-client.md).
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# Refactoring the Xamarin client app to use JSON
|
||||
|
||||
The function is now returning a JSON-formatted string. Thankfully parsing JSON in C# is extremely easy with the help of the [JSON.NET Nuget package](https://www.nuget.org/packages/Newtonsoft.Json). In this section, we will add the Nuget package to our Xamarin application, and then modify the code slightly to take advantage of this package and deserialize the JSON result.
|
||||
|
||||
1. Open the XamCalculator solution in Visual Studio.
|
||||
|
||||
2. In the Solution Explorer, right-click on the XamCalculator solution and select "Manage Nuget Packages for Solution" from the context menu.
|
||||
|
||||
![Context menu](./Img/2018-01-08_17-23-14.png)
|
||||
|
||||
3. Make sure that Browse is selected and type ```json.net``` in the search box.
|
||||
|
||||
4. Select Newtonsoft.Json from the list.
|
||||
|
||||
![Browse for Newtonsoft.Json](./Img/2018-01-08_17-43-56.png)
|
||||
|
||||
5. On the right hand side, make sure to select the XamCalculator project and click on the Install button. If needed, accept the license.
|
||||
|
||||
![Selecting the project](./Img/2018-01-08_17-45-48.png)
|
||||
|
||||
## Adding the class library
|
||||
|
||||
When we modified the server side code, we added a portable class library (PCL) to the Azure Functions application and stored the object code into this library. This will allow us to easily reuse this code in the client application too.
|
||||
|
||||
1. In the Solution Explorer, right click on the XamCalculator solution and select Add, Existing Project from the context menu.
|
||||
|
||||
2. Navigate to the Calculator.Data project that we created earlier. You need to locate the file Calculator.Data.csproj and select it in the dialog.
|
||||
|
||||
3. Right click on the XamCalculator project (not the Solution but the main project of the Xamarin.Forms application) and select Add, Reference from the context menu.
|
||||
|
||||
4. In the Reference Manager dialog, select the Calculator.Data project and click on OK.
|
||||
|
||||
5. Open the file MainPage.xaml.cs and update the code of the try/catch block as follows. Note that nothing else changes in the client application!
|
||||
|
||||
```CS
|
||||
try
|
||||
{
|
||||
var url = Url.Replace("{num1}", number1.ToString())
|
||||
.Replace("{num2}", number2.ToString());
|
||||
|
||||
var json = await Client.GetStringAsync(url);
|
||||
|
||||
var deserialized = JsonConvert.DeserializeObject<AdditionResult>(json);
|
||||
|
||||
Result.Text = deserialized.Result + $" {deserialized.Result.GetType()}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex;
|
||||
}
|
||||
```
|
||||
|
||||
The changes to the client application are very minor: We use exactly the same URL with the two operands. What we get from the service is now a JSON-formatted string.
|
||||
|
||||
The next step is to deserialize the JSON into an instance of the ```AdditionResult``` class. This is the exact same class that we used on the server. The JSON format is only used for the HTTP transport.
|
||||
|
||||
Finally, we use the ```Result``` property of the ```AdditionResult``` class. You can now test the application again in iOS, Android or in Windows 10 UWP (following [the instructions we used earlier](./first-client.md#testing-the-client-app)). For example, here is the application running in the Android emulator:
|
||||
|
||||
![Running the updated application in Android](./Img/2018-01-08_18-06-01.png)
|
||||
|
||||
Note how the ```Result``` property is now of type ```System.Int32``` instead of ```System.String``` like before. Also, we can pass multiple values from the server to the client, and easily add properties to the ```AdditionResult``` class if needed for new features of the application.
|
||||
|
||||
## Conclusion
|
||||
|
||||
At this point, we have an Azure Functions application with one HTTP endpoint, and a Xamarin.Forms app running on iOS, Android and Windows 10. The server and the client use JSON to communicate. Modifying and extending the application for your own usage should be straightforward.
|
||||
|
||||
This concludes this sample. We hope that you found this code and tutorial useful. Please don't hesitate to enter comments and questions in the Issues tab above. You can also contact me privately but I prefer to keep the discussion in the open, so everyone can see the answers.
|
||||
|
||||
Happy coding!
|
||||
|
||||
[Laurent](https://twitter.com/lbugnion)
|
|
@ -0,0 +1,130 @@
|
|||
# Refactoring the Function to use JSON
|
||||
|
||||
One thing that we notice [when we use the Xamarin client](./second-client.md) is that the type of the result is ```System.String```. This is because we use HTTP to communicate between the client and the server, and HTTP (HyperText Transfer Protocol) is of course text-based. As such, it means that we need an additional agreement between the client and the server, to specify the type of the result, so that the client can parse it and convert the result to the desired type. If the server developer decides to change the implementation and the type of the result, or to add more information in the result, the client developer needs to be notified and update the application accordingly. This is not very efficient.
|
||||
|
||||
To avoid this kind of issues, many APIs these days use the JavaScript Object Notation JSON to encode the result of the function. JSON has various advantages: It is easy to serialize/deserialize and it can be transmitted as text over HTTP. We will now update our sample implementation to use JSON instead of a simple result.
|
||||
|
||||
> Note: Some APIs also use XML to transmit data. XML is also text-based, so it also works fine with HTTP. However XML is more verbose than JSON and thus is lost in popularity, especially for mobile clients.
|
||||
|
||||
## Adding a class library
|
||||
|
||||
In order to share code between the client and the server, we will use a class library that we will consume on the server and on the client. The class library can be seen as a contract between client and server. In this sample, we use .NET Standard for the Azure Function, so we will also create a .NET Standard class library. If you have selected a .NET Framework Azure Functions app, you can select a Portable Class Library here.
|
||||
|
||||
Follow the steps to add the class library to the server project:
|
||||
|
||||
1. Open the Functions application project in Visual Studio.
|
||||
|
||||
2. In the Solution Explorer, right click on the Solution name and select Add, New Project from the context menu.
|
||||
|
||||
3. In the Add New Project dialog, select the .NET Standard category on the left-hand side, and then Class Library (.NET Standard).
|
||||
|
||||
4. Enter a name (for example Calculator.Data) and a location for the new project.
|
||||
|
||||
![Creating the class library](./Img/2018-01-15_16-15-00.png)
|
||||
|
||||
5. In the Calculator.Data project, rename the file Class1.cs to AdditionResult.cs
|
||||
|
||||
7. Replace the class with the following code. For the sake of the sample, we will transmit the result of the addition as well as the current date/time on the server. We could also easily decide to transmit more information if necessary.
|
||||
|
||||
```CS
|
||||
public class AdditionResult
|
||||
{
|
||||
public int Result
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DateTime TimeOnServer
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Consuming the class library on the server
|
||||
|
||||
Now that we have our new Data class library, we will use it on the server and modify the Function accordingly.
|
||||
|
||||
1. Right click on the LbCalculator Function project and select Add, Reference from the context menu.
|
||||
|
||||
2. In the Reference Manager dialog, select the Calculator.Data class library and press OK.
|
||||
|
||||
![Reference Manager dialog](./Img/2018-01-08_09-53-48.png)
|
||||
|
||||
3. Reopen the Add.cs file in the Azure Function application.
|
||||
|
||||
4. Replace the ```Add``` class with the following code:
|
||||
|
||||
```CS
|
||||
public static class Add
|
||||
{
|
||||
[FunctionName("Add")]
|
||||
public static IActionResult Run(
|
||||
[HttpTrigger(
|
||||
AuthorizationLevel.Function,
|
||||
"get",
|
||||
Route = "add/num1/{num1}/num2/{num2}")]
|
||||
HttpRequest req,
|
||||
int num1,
|
||||
int num2,
|
||||
TraceWriter log)
|
||||
{
|
||||
log.Info($"C# HTTP trigger function processed a request with {num1} and {num2}");
|
||||
|
||||
var result = new AdditionResult
|
||||
{
|
||||
Result = num1 + num2,
|
||||
TimeOnServer = DateTime.Now
|
||||
};
|
||||
|
||||
return new OkObjectResult(result);
|
||||
}
|
||||
}
|
||||
```
|
||||
There are a few small changes to the previous version of the function:
|
||||
|
||||
- The result is now an instance of the ```AdditionResult``` class that we added earlier in the ```Calculator.Data``` class library. Note how we also store the date/time on the server.
|
||||
|
||||
- Instead of the ```addition```, we pass the ```result``` instance to the ```OkObjectResult``` constructor now.
|
||||
|
||||
The ```result``` object will automatically be serialized to the JavaScript Object Notation JSON and passed back to the caller.
|
||||
|
||||
## Testing the new interface
|
||||
|
||||
Now we can test the new function result in the web browser.
|
||||
|
||||
1. In Visual Studio, select Debug, Start without Debugging from the menu bar.
|
||||
|
||||
2. In the Command window with the Azure Runtime that opens up, copy the debug URL from the ```Http Function``` section (in green).
|
||||
|
||||
3. Like before, paste the debug URL in a web browser and replace the ```{num1}``` and ```{num2}``` occurrences in the URL with operands, for example ```12``` and ```34```.
|
||||
|
||||
4. In the web browser, you should now see a result looking like
|
||||
|
||||
```json
|
||||
{"Result":46,"TimeOnServer":"2018-01-08T10:11:54.5719894-08:00"}
|
||||
```
|
||||
|
||||
## Publishing the new function to Azure
|
||||
|
||||
Now that the code changed, we will publish the updated function to Azure. The process is easier [than the first time we did that](./creating-vs.md#publishing-the-function-to-azure), because we don't have to specify all the parameters again.
|
||||
|
||||
1. In Visual Studio, in the Solution Explorer, right click on the Azure functions application name and select Publish from the context menu.
|
||||
|
||||
If everything went well before, the publication parameters should be all saved and available in Visual Studio. You should see something similar to the image below:
|
||||
|
||||
![Publishing the changes](./Img/2018-01-08_16-12-08.png)
|
||||
|
||||
If you don't see something like that, you might have to re-publish the application to Azure. Follow the steps we did earlier, and select the existing functions application instead of creating a new one from scratch.
|
||||
|
||||
2. Press on the Publish button. You can see the progress in Visual Studio's Output window.
|
||||
|
||||
3. After a short while, the changes are published to Azure. You can test the new function's interface by using [the exact same URL we obtained before from the Azure web portal](./creating-vs.md#getting-the-url-for-the-xamarin-client-app). Simply reload this URL in the web browser, and you should now see a JSON formatted result, including the date/time on the server.
|
||||
|
||||
> Note: If you are observant, you might notice that the date/time returned by the server is always the UTC date/time, even if you selected a different region when you created the functions application. This is because all Azure servers run in UTC date/time, to make it easier to let applications communicate with each other.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Now that we saw that the new interface of the Azure function works fine, and the function now returns a JSON-formatted result. [We can now modify the Xamarin.Forms client](./refactoring-client.md) to take advantage of the new result.
|
|
@ -0,0 +1,169 @@
|
|||
# Modifying the Xamarin.Forms client to use the Azure Function
|
||||
|
||||
We know that our function works well now, because we tested it [in the Azure Portal](./implementing.md#testing-the-new-signature) and [in Visual Studio 2017](./creating-vs.md#testing-the-function). Now we will build a Xamarin.Forms client app that runs on iOS, Android and Windows to use this new function.
|
||||
|
||||
In the previous step, we copied the function's URL for later usage. Make sure to keep this URL handy, we will need it later in the client's code.
|
||||
|
||||
- [Copying the URL when creating the Function in the Azure Portal](./implementing.md#getting-the-url-for-the-xamarin-client)
|
||||
- [Copying the URL when creating the Function in Visual Studio 2017](./creating-vs.md#getting-the-url-for-the-xamarin-client-app)
|
||||
|
||||
1. Open the previous state of the Xamarin client app XamCalculator. If you skipped building the offline client, [you can get the application from here](https://github.com/lbugnion/sample-azure-simplexamarinfunction/tree/master/XamCalculator%20-%20Start).
|
||||
|
||||
2. Open the MainPage.xaml.cs file.
|
||||
|
||||
3. Replace the ```MainPage``` constructor with the following code:
|
||||
|
||||
```CS
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
private const string Url = "YOUR URL HERE";
|
||||
|
||||
private HttpClient _client;
|
||||
|
||||
private HttpClient Client
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_client == null)
|
||||
{
|
||||
_client = new HttpClient();
|
||||
}
|
||||
|
||||
return _client;
|
||||
}
|
||||
}
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
AddButton.Clicked += async (s, e) =>
|
||||
{
|
||||
int number1 = 0, number2 = 0;
|
||||
|
||||
var success = int.TryParse(Number1.Text, out number1)
|
||||
&& int.TryParse(Number2.Text, out number2);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
await DisplayAlert("Error in inputs", "You must enter two integers", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
Result.Text = "Please wait...";
|
||||
AddButton.IsEnabled = false;
|
||||
Exception error = null;
|
||||
|
||||
try
|
||||
{
|
||||
var url = Url.Replace("{num1}", number1.ToString())
|
||||
.Replace("{num2}", number2.ToString());
|
||||
var result = await Client.GetStringAsync(url);
|
||||
Result.Text = result + $" {result.GetType()}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex;
|
||||
}
|
||||
|
||||
if (error != null)
|
||||
{
|
||||
Result.Text = "Error!!";
|
||||
await DisplayAlert("There was an error", error.Message, "OK");
|
||||
}
|
||||
|
||||
AddButton.IsEnabled = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
What the code above does is the following:
|
||||
|
||||
- We define a constant for the URL template for the service. You should replace the words ```YOUR URL HERE``` with the URL that you copied in the previous step.
|
||||
|
||||
- We define an ```HttpClient``` as a property so that we can easily reuse it. Like the name suggests, the ```HttpClient``` is a class designed for interaction with servers over HTTP. It is the most convenient and simple way to access an HTTP service, such as our HTTP-Triggered function.
|
||||
|
||||
- In the ```MainPage``` constructor, we handle the Clicked event of the Button control. When this event is called, the event handler will be executed.
|
||||
|
||||
- We parse the text that the user entered. We want to make sure that we send integers to the server, to avoid error there. Parsing the text with the ```TryParse``` method ensures that the user input is suitable.
|
||||
|
||||
- If the user enters incorrect inputs, we show a warning message and we stop the execution.
|
||||
|
||||
- We show a message to the user saying ```Please wait```. This is because we will perform an asynchronous operation that could take a moment, and it is nice to let the user know what's happening. On the next line, we also disable the ```AddButton``` to avoid that the user presses the button again while the operation is active.
|
||||
|
||||
The next execution block is placed in a ```try/catch``` so that we catch any potential error and inform the user accordingly. The ```HttpClient``` may throw an exception if the server is down, or if there is a server error for example. If such an exception occurs, we need to make sure that the application doesn't crash, and that the user knows what happened.
|
||||
|
||||
- We create the URL out of the URL template declared as a constant higher up. In this URL, the first and second numbers are defined as ```{num1}``` and ```{num2}```.
|
||||
|
||||
- The next line is the call to the ```GetStringAsync``` method of the ```HttpClient```. This method is asynchronous, like the name suggests. This is why we use the ```await``` keyword when we call it.
|
||||
|
||||
> Note: Calling the method with the ```await``` keyword does not block the method's execution. It means that the user interface will remain usable. This is why informing the user is important.
|
||||
|
||||
- If everything works well, we show the result of the operation to the user. In this sample I am also showing the type of the result, which is a string (as returned by the web service). [Later we will see how we can modify this part](./refactoring-client.md) to make it more convenient to use.
|
||||
|
||||
- Outside of the try/catch block, we check if there was an error. Note that you cannot use DisplayAlert asynchronously from within the ```catch``` block because the ```await``` keyword is not allowed there. This is why we saved the potential error, and later we check if there was an error, and show the message to the user if needed.
|
||||
|
||||
- Finally, we re-enable the ```AddButton``` so the user can try another operation.
|
||||
|
||||
## Testing the client app
|
||||
|
||||
Time to test the new client which connects to the Azure Function! Again you can test on emulator/simulator, or you can deploy on a real device if you prefer.
|
||||
|
||||
### Testing on Android
|
||||
|
||||
Here is how you can test the app on Android:
|
||||
|
||||
1. Right-click on the Android application and select "Set as Startup Project".
|
||||
|
||||
![Android application](./Img/2018-01-04_15-25-17.png)
|
||||
|
||||
2. Make sure that an emulator is selected in the Run dropdown.
|
||||
|
||||
![Run button](./Img/2018-01-04_15-26-08.png)
|
||||
|
||||
3. Press the Run button to debug the code.
|
||||
|
||||
4. In the emulator window, enter two operands and press the Add button. After a short wait, you should see the result.
|
||||
|
||||
![Android application](./Img/2018-01-04_15-30-54.png)
|
||||
|
||||
### Testing on iOS
|
||||
|
||||
On iOS you can run the app in the iOS simulator to test it.
|
||||
|
||||
1. Right-click on the iOS application and select "Set as Startup Project".
|
||||
|
||||
![iOS application](./Img/2018-01-04_20-33-16.png)
|
||||
|
||||
2. Make sure that "iPhoneSimulator" and a simulator are selected in the toolbar.
|
||||
|
||||
![Run button](./Img/2018-01-04_20-33-37.png)
|
||||
|
||||
3. Press the Run button to debug the code.
|
||||
|
||||
4. In the simulator window, enter two operands and press the Add button. After a short wait, you should see the result.
|
||||
|
||||
![iOS application](./Img/2018-01-04_20-35-52.png)
|
||||
|
||||
### Testing on Windows (UWP)
|
||||
|
||||
To test on Windows 10, you can run the application on the local machine directly from Visual Studio 2017.
|
||||
|
||||
1. Right-click on the UWP application and select "Set as Startup Project".
|
||||
|
||||
![Set as StartUp Project](./Img/2018-01-04_15-18-41.png)
|
||||
|
||||
2. Make sure that x86 and Local Machine are selected in the toolbar.
|
||||
|
||||
![Run button](./Img/2018-01-04_15-19-44.png)
|
||||
|
||||
3. Press the Run button to debug the code.
|
||||
|
||||
4. In the window that opens up, enter two operands and press the Add button. After a short wait, you should see the result.
|
||||
|
||||
![Windows UWP application](./Img/2018-01-04_15-24-40.png)
|
||||
|
||||
## Conclusion
|
||||
|
||||
We have now tested that the application works well. However using simple text to communicate between the server and the client is not very flexible. Adding new properties to the interface would be quite complex. To solve this, we will now refactor [the Azure Function](./refactoring.md) and [the Xamarin client app](./refactoring-client.md) to use the JavaScript Object Notation JSON instead.
|
|
@ -0,0 +1,3 @@
|
|||
# Work in progress
|
||||
|
||||
> Note: Two other things are annoying in this URL: The name ```xamfunctionssample.azurewebsites.net``` is not elegant nor personal. Also the query string ```?code=9r9jauRrThIFjGcP1nz3xRJLiriF9IAo5dmPlsLHBfS4hq0gv06E7A==``` is quite ugly. Thankfully these things can be fixed later by [setting up a short URL and a redirection]{./shortening.md}. We will see later how we can do that.
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace Calculator.Data
|
||||
{
|
||||
public class AdditionResult
|
||||
{
|
||||
public int Result
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DateTime TimeOnServer
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2020
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LbCalculator", "LbCalculator\LbCalculator.csproj", "{2A9748FC-D60E-40AE-BE5C-988128DFB17F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator.Data", "Calculator.Data\Calculator.Data.csproj", "{181116A3-A973-4288-8CDF-BC5E8D810120}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2A9748FC-D60E-40AE-BE5C-988128DFB17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2A9748FC-D60E-40AE-BE5C-988128DFB17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2A9748FC-D60E-40AE-BE5C-988128DFB17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2A9748FC-D60E-40AE-BE5C-988128DFB17F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{181116A3-A973-4288-8CDF-BC5E8D810120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{181116A3-A973-4288-8CDF-BC5E8D810120}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{181116A3-A973-4288-8CDF-BC5E8D810120}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{181116A3-A973-4288-8CDF-BC5E8D810120}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BEF6B969-3B7A-4E74-9C98-9B0AA2C2CA4E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,264 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# Azure Functions localsettings file
|
||||
local.settings.json
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
using Newtonsoft.Json;
|
||||
using Calculator.Data;
|
||||
using System;
|
||||
|
||||
namespace LbCalculator
|
||||
{
|
||||
public static class Add
|
||||
{
|
||||
[FunctionName("Add")]
|
||||
public static IActionResult Run(
|
||||
[HttpTrigger(
|
||||
AuthorizationLevel.Function,
|
||||
"get",
|
||||
Route = "add/num1/{num1}/num2/{num2}")]
|
||||
HttpRequest req,
|
||||
int num1,
|
||||
int num2,
|
||||
TraceWriter log)
|
||||
{
|
||||
log.Info($"C# HTTP trigger function processed a request with {num1} and {num2}");
|
||||
|
||||
var result = new AdditionResult
|
||||
{
|
||||
Result = num1 + num2,
|
||||
TimeOnServer = DateTime.Now
|
||||
};
|
||||
|
||||
return new OkObjectResult(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.6" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Calculator.Data\Calculator.Data.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="host.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="local.settings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
57
README.md
|
@ -1,57 +1,30 @@
|
|||
# Project Name
|
||||
# Implementing a simple Azure Function with a Xamarin.Forms client
|
||||
|
||||
(short, 1-3 sentenced, description of the project)
|
||||
![Azure Functions logo](./Doc/Img/Azure-Functions-Logo.png)
|
||||
|
||||
## Features
|
||||
[Azure Functions](http://gslb.ch/a10) are a great way to implement an API in an easy manner, without any deployment or maintenance headaches. You can implement the code in the Azure Web Portal directly (or in Visual Studio if you prefer, of course). Functions are also running at a very interesting cost, since they are only billed when they are actually executed. If your business is just starting and you have only a few users, the costs will be very low. Later when the business expands, you have the possibility to switch to a different plan making it easier to budget your costs.
|
||||
|
||||
This project framework provides the following features:
|
||||
Because they are very easy to implement and maintain, and accessible through HTTP, Azure Functions are a great way to implement an API for a mobile application. Microsoft offers great cross-platform tools for iOS, Android and Windows with [Xamarin](https://developer.xamarin.com). As such, Xamarin and Azure Functions are working great together. This article will show how to implement a very simple Azure Function in the Azure Web Portal or in Visual Studio at first, and build a cross-platform client with Xamarin.Forms, running on Android, iOS and Windows.
|
||||
|
||||
* Feature 1
|
||||
* Feature 2
|
||||
* ...
|
||||
Later we will refine this application by using the JavaScript Object Notation JSON as a communication medium between the server and the mobile clients.
|
||||
|
||||
## Getting Started
|
||||
## Table of content
|
||||
|
||||
### Prerequisites
|
||||
- [Implementing the first version of the Xamarin.Forms client app](./Doc/first-client.md).
|
||||
|
||||
(ideally very short, if any)
|
||||
- [Creating the Azure Function in the Azure Web Portal](./Doc/creating.md).
|
||||
|
||||
- OS
|
||||
- Library version
|
||||
- ...
|
||||
- [Modifying the function's interface and implementing it](./Doc/implementing.md).
|
||||
|
||||
### Installation
|
||||
- [Creating the Azure Function in Visual Studio](./Doc/creating-vs.md).
|
||||
|
||||
(ideally very short)
|
||||
- [Modifying the Xamarin.Forms client app to use the Azure Function](./Doc/second-client.md).
|
||||
|
||||
- npm install [package name]
|
||||
- mvn install
|
||||
- ...
|
||||
## Modifying the application to use JavaScript Object Notation JSON instead
|
||||
|
||||
### Quickstart
|
||||
(Add steps to get up and running quickly)
|
||||
In this section, we will modify the function application interface to use JSON instead of normal text to pass the result to the client.
|
||||
|
||||
1. git clone [repository clone url]
|
||||
2. cd [respository name]
|
||||
3. ...
|
||||
- [Modifying the server application to use JSON](./Doc/refactoring.md).
|
||||
|
||||
- [Modifying the client application to use JSON](./Doc/refactoring-client.md).
|
||||
|
||||
## Demo
|
||||
|
||||
A demo app is included to show how to use the project.
|
||||
|
||||
To run the demo, follow these steps:
|
||||
|
||||
(Add steps to start up the demo)
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Resources
|
||||
|
||||
(Any additional resources or related projects)
|
||||
|
||||
- Link to supporting information
|
||||
- Link to similar sample
|
||||
- ...
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2020
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamCalculator.Android", "XamCalculator\XamCalculator.Android\XamCalculator.Android.csproj", "{4EE25F99-9136-4CA8-8E4A-097309F58F24}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamCalculator.iOS", "XamCalculator\XamCalculator.iOS\XamCalculator.iOS.csproj", "{52859590-1A56-451F-A5E0-197CED3BFF40}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamCalculator.UWP", "XamCalculator\XamCalculator.UWP\XamCalculator.UWP.csproj", "{BBE8375D-3167-4328-BE41-B6A84AEFF63B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamCalculator", "XamCalculator\XamCalculator\XamCalculator.csproj", "{CF7D5987-8A34-4088-8CC7-9E4616073DDE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
Ad-Hoc|ARM = Ad-Hoc|ARM
|
||||
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
||||
Ad-Hoc|x64 = Ad-Hoc|x64
|
||||
Ad-Hoc|x86 = Ad-Hoc|x86
|
||||
AppStore|Any CPU = AppStore|Any CPU
|
||||
AppStore|ARM = AppStore|ARM
|
||||
AppStore|iPhone = AppStore|iPhone
|
||||
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
||||
AppStore|x64 = AppStore|x64
|
||||
AppStore|x86 = AppStore|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|iPhone = Debug|iPhone
|
||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|iPhone = Release|iPhone
|
||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|ARM.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|x64.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Ad-Hoc|x86.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|ARM.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|x64.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|x64.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|x86.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.AppStore|x86.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|ARM.Deploy.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|x64.Deploy.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Debug|x86.Deploy.0 = Debug|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|ARM.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|x64.Deploy.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4EE25F99-9136-4CA8-8E4A-097309F58F24}.Release|x86.Deploy.0 = Release|Any CPU
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|ARM.ActiveCfg = AppStore|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|x64.ActiveCfg = AppStore|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.AppStore|x86.ActiveCfg = AppStore|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|ARM.ActiveCfg = Debug|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|x64.ActiveCfg = Debug|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Debug|x86.ActiveCfg = Debug|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|ARM.ActiveCfg = Release|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|x64.ActiveCfg = Release|iPhone
|
||||
{52859590-1A56-451F-A5E0-197CED3BFF40}.Release|x86.ActiveCfg = Release|iPhone
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|Any CPU.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|Any CPU.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|Any CPU.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|ARM.ActiveCfg = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|ARM.Build.0 = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|ARM.Deploy.0 = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|iPhone.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|iPhone.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|iPhone.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|x64.ActiveCfg = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|x64.Build.0 = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|x64.Deploy.0 = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|x86.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|x86.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Ad-Hoc|x86.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|Any CPU.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|Any CPU.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|Any CPU.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|ARM.ActiveCfg = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|ARM.Build.0 = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|ARM.Deploy.0 = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|iPhone.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|iPhone.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|iPhone.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|iPhoneSimulator.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|iPhoneSimulator.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|iPhoneSimulator.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|x64.ActiveCfg = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|x64.Build.0 = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|x64.Deploy.0 = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|x86.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|x86.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.AppStore|x86.Deploy.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|iPhone.ActiveCfg = Debug|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|x64.Build.0 = Debug|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|x86.Build.0 = Debug|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|ARM.Build.0 = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|iPhone.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|iPhoneSimulator.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|x64.ActiveCfg = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|x64.Build.0 = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|x64.Deploy.0 = Release|x64
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|x86.ActiveCfg = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|x86.Build.0 = Release|x86
|
||||
{BBE8375D-3167-4328-BE41-B6A84AEFF63B}.Release|x86.Deploy.0 = Release|x86
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CF7D5987-8A34-4088-8CC7-9E4616073DDE}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6DF556A2-5859-4109-ABB5-8455A5955001}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,19 @@
|
|||
Any raw assets you want to be deployed with your application can be placed in
|
||||
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
||||
|
||||
These files will be deployed with you package and will be accessible using Android's
|
||||
AssetManager, like this:
|
||||
|
||||
public class ReadAsset : Activity
|
||||
{
|
||||
protected override void OnCreate (Bundle bundle)
|
||||
{
|
||||
base.OnCreate (bundle);
|
||||
|
||||
InputStream input = Assets.Open ("my_asset.txt");
|
||||
}
|
||||
}
|
||||
|
||||
Additionally, some Android functions will automatically load asset files:
|
||||
|
||||
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.OS;
|
||||
|
||||
namespace XamCalculator.Droid
|
||||
{
|
||||
[Activity(Label = "XamCalculator", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
|
||||
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
TabLayoutResource = Resource.Layout.Tabbar;
|
||||
ToolbarResource = Resource.Layout.Toolbar;
|
||||
|
||||
base.OnCreate(bundle);
|
||||
|
||||
global::Xamarin.Forms.Forms.Init(this, bundle);
|
||||
LoadApplication(new App());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.XamCalculator">
|
||||
<uses-sdk android:minSdkVersion="15" />
|
||||
<application android:label="XamCalculator.Android"></application>
|
||||
</manifest>
|
|
@ -0,0 +1,34 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Android.App;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("XamCalculator.Android")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("XamCalculator.Android")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
// Add some common permissions, these can be removed if not needed
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
|
|
@ -0,0 +1,50 @@
|
|||
Images, layout descriptions, binary blobs and string dictionaries can be included
|
||||
in your application as resource files. Various Android APIs are designed to
|
||||
operate on the resource IDs instead of dealing with images, strings or binary blobs
|
||||
directly.
|
||||
|
||||
For example, a sample Android app that contains a user interface layout (main.xml),
|
||||
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
|
||||
would keep its resources in the "Resources" directory of the application:
|
||||
|
||||
Resources/
|
||||
drawable-hdpi/
|
||||
icon.png
|
||||
|
||||
drawable-ldpi/
|
||||
icon.png
|
||||
|
||||
drawable-mdpi/
|
||||
icon.png
|
||||
|
||||
layout/
|
||||
main.xml
|
||||
|
||||
values/
|
||||
strings.xml
|
||||
|
||||
In order to get the build system to recognize Android resources, set the build action to
|
||||
"AndroidResource". The native Android APIs do not operate directly with filenames, but
|
||||
instead operate on resource IDs. When you compile an Android application that uses resources,
|
||||
the build system will package the resources for distribution and generate a class called
|
||||
"Resource" that contains the tokens for each one of the resources included. For example,
|
||||
for the above Resources layout, this is what the Resource class would expose:
|
||||
|
||||
public class Resource {
|
||||
public class drawable {
|
||||
public const int icon = 0x123;
|
||||
}
|
||||
|
||||
public class layout {
|
||||
public const int main = 0x456;
|
||||
}
|
||||
|
||||
public class strings {
|
||||
public const int first_string = 0xabc;
|
||||
public const int second_string = 0xbcd;
|
||||
}
|
||||
}
|
||||
|
||||
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
|
||||
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
|
||||
string in the dictionary file values/strings.xml.
|
7003
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/Resource.designer.cs
сгенерированный
Normal file
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/drawable-hdpi/icon.png
Normal file
После Ширина: | Высота: | Размер: 1.4 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/drawable-xhdpi/icon.png
Normal file
После Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/drawable-xxhdpi/icon.png
Normal file
После Ширина: | Высота: | Размер: 2.3 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/drawable/icon.png
Normal file
После Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
|
||||
<Button android:id="@+id/myButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:tabIndicatorColor="@android:color/white"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed" />
|
|
@ -0,0 +1,9 @@
|
|||
<android.support.v7.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
android:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
||||
|
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/mipmap-hdpi/Icon.png
Normal file
После Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/mipmap-mdpi/Icon.png
Normal file
После Ширина: | Высота: | Размер: 1.4 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/mipmap-xhdpi/Icon.png
Normal file
После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/mipmap-xxhdpi/Icon.png
Normal file
После Ширина: | Высота: | Размер: 5.3 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.Android/Resources/mipmap-xxxhdpi/Icon.png
Normal file
После Ширина: | Высота: | Размер: 7.6 KiB |
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="hello">Hello World, Click Me!</string>
|
||||
<string name="app_name">XamCalculator.Droid</string>
|
||||
</resources>
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<resources>
|
||||
|
||||
<style name="MainTheme" parent="MainTheme.Base">
|
||||
</style>
|
||||
<!-- Base theme applied no matter what API -->
|
||||
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
|
||||
<item name="windowNoTitle">true</item>
|
||||
<!--We will be using the toolbar so no need to show ActionBar-->
|
||||
<item name="windowActionBar">false</item>
|
||||
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
|
||||
<!-- colorPrimary is used for the default action bar background -->
|
||||
<item name="colorPrimary">#2196F3</item>
|
||||
<!-- colorPrimaryDark is used for the status bar -->
|
||||
<item name="colorPrimaryDark">#1976D2</item>
|
||||
<!-- colorAccent is used as the default value for colorControlActivated
|
||||
which is used to tint widgets -->
|
||||
<item name="colorAccent">#FF4081</item>
|
||||
<!-- You can also set colorControlNormal, colorControlActivated
|
||||
colorControlHighlight and colorSwitchThumbNormal. -->
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
|
||||
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
|
||||
<item name="colorAccent">#FF4081</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4EE25F99-9136-4CA8-8E4A-097309F58F24}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>XamCalculator.Droid</RootNamespace>
|
||||
<AssemblyName>XamCalculator.Android</AssemblyName>
|
||||
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
|
||||
<AndroidApplication>True</AndroidApplication>
|
||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Forms" Version="2.5.0.122203" />
|
||||
<PackageReference Include="Xamarin.Android.Support.Design" Version="25.4.0.2" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="25.4.0.2" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v4" Version="25.4.0.2" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="25.4.0.2" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.MediaRouter" Version="25.4.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Resources\Resource.Designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\icon.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
||||
<AndroidResource Include="Resources\values\styles.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\XamCalculator\XamCalculator.csproj">
|
||||
<Project>{16E57EAC-BF4E-496E-9667-39A7DAA7D78D}</Project>
|
||||
<Name>XamCalculator</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,8 @@
|
|||
<Application
|
||||
x:Class="XamCalculator.UWP.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:XamCalculator.UWP"
|
||||
RequestedTheme="Light">
|
||||
|
||||
</Application>
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace XamCalculator.UWP
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
|
||||
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
Xamarin.Forms.Forms.Init(e);
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (rootFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored navigate to the first page,
|
||||
// configuring the new page by passing required information as a navigation
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/LockScreenLogo.scale-100.png
Normal file
После Ширина: | Высота: | Размер: 261 B |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/LockScreenLogo.scale-125.png
Normal file
После Ширина: | Высота: | Размер: 305 B |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/LockScreenLogo.scale-150.png
Normal file
После Ширина: | Высота: | Размер: 347 B |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/LockScreenLogo.scale-200.png
Normal file
После Ширина: | Высота: | Размер: 431 B |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/LockScreenLogo.scale-400.png
Normal file
После Ширина: | Высота: | Размер: 758 B |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/SplashScreen.scale-100.png
Normal file
После Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/SplashScreen.scale-125.png
Normal file
После Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/SplashScreen.scale-150.png
Normal file
После Ширина: | Высота: | Размер: 2.5 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/SplashScreen.scale-200.png
Normal file
После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/SplashScreen.scale-400.png
Normal file
После Ширина: | Высота: | Размер: 8.6 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/Square150x150Logo.scale-100.png
Normal file
После Ширина: | Высота: | Размер: 1019 B |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/Square150x150Logo.scale-125.png
Normal file
После Ширина: | Высота: | Размер: 1.3 KiB |
Двоичные данные
XamCalculator - Start/XamCalculator/XamCalculator.UWP/Assets/Square150x150Logo.scale-150.png
Normal file
После Ширина: | Высота: | Размер: 1.4 KiB |