jeudi 1 juin 2017

Using Microsoft account login in your UWP applications (Desktop and Xbox One) [XAML,C#]

After having used the google account and facebook account login in UWP apps I must say that the Microsoft account login was much easier to implement !  The only tricky part is when you wish to login on your Xbox One.

My example will be strongly base off the work MS has already done and published in  Github, the main elements that my sample code will add is a service and a event that is fired when we receive the Oauth token.

First I wanted to create a service, so I create an interface as follows:
    public interface IMicrosoftService
    {
        event Action<string> MsTokenReceived;
        Task LogIntoMicrosoftService();
    }

I have create the MsTokenReceived event as it will allow me to pass the information that I have received my token and thus can continue to try and log the user.

First we create our class:   (MicrosoftService.cs)

public class MicrosoftService : IMicrosoftService

then 




// To obtain Microsoft account tokens, you must register your application online
        // Then, you must associate the app with the store.
        const string MicrosoftAccountProviderId = "https://login.microsoft.com";
        const string ConsumerAuthority = "consumers";
        const string AccountScopeRequested = "wl.basic";
        const string AccountClientId = "your cliend id";
        const string StoredAccountToken = "NameOfWhereYouStoreAccountToekn";

You will find or create your AccountClientId here https://apps.dev.microsoft.com/#/appList







Click on Add App, fill in the necessary information, add a platform (here under platform I have added a Native Application)



and click Save.

Now back to our app, in our class MicrosoftService.cs, we will add the method:

 public event Action<string> MsTokenReceived;

 public Task LogIntoMicrosoftService()
 {
     // The AccountCommandsRequested event triggers before the Accounts settings pane is displayed 
     AccountsSettingsPane.GetForCurrentView().AccountCommandsRequested += OnAccountCommandsRequested;
     // show the pane
AccountsSettingsPane.Show(); return Task.CompletedTask; }


Again this is exactly what you will find in the windows sample, except for when you want to run your application on an Xbox.

  // This event handler is called when the Account settings pane is to be launched.
  private async void OnAccountCommandsRequested(
            AccountsSettingsPane sender,
            AccountsSettingsPaneCommandsRequestedEventArgs e)
        {
            // In order to make async calls within this callback, the deferral object is needed
            AccountsSettingsPaneEventDeferral deferral = e.GetDeferral();

            if (App.DeviceType == Helper.DeviceTypeEnum.Xbox)
            {
                await GetAccountProviderForXboxLogin();
            }
            else
            {
                await AddWebAccountProvider(e);
            }
            deferral.Complete();
        }

This is a simple copy and paste of the code from the MS sample.
      private async Task AddWebAccountProvider(AccountsSettingsPaneCommandsRequestedEventArgs e)
        {
            // FindAccountProviderAsync returns the WebAccountProvider of an installed plugin
            // The Provider and Authority specifies the specific plugin
            // This scenario only supports Microsoft accounts.

            // The Microsoft account provider is always present in Windows 10 devices, as is the Azure AD plugin.
            // If a non-installed plugin or incorect identity is specified, FindAccountProviderAsync will return null   
            WebAccountProvider provider = await WebAuthenticationCoreManager.FindAccountProviderAsync(MicrosoftAccountProviderId, MicrosoftAccountProviderId);

            WebAccountProviderCommand providerCommand = new WebAccountProviderCommand(provider, WebAccountProviderCommandInvoked);
            e.WebAccountProviderCommands.Add(providerCommand);
        }


        private async void WebAccountProviderCommandInvoked(WebAccountProviderCommand command)
        {
            // ClientID is ignored by MSA
            await RequestTokenAndSaveAccount(command.WebAccountProvider, AccountScopeRequested, AccountClientId);
        }


        private async Task RequestTokenAndSaveAccount(WebAccountProvider Provider, String Scope, String ClientID)
        {
            try
            {
                WebTokenRequest webTokenRequest = new WebTokenRequest(Provider, Scope, ClientID);

                // If the user selected a specific account, RequestTokenAsync will return a token for that account.
                // The user may be prompted for credentials or to authorize using that account with your app
                // If the user selected a provider, the user will be prompted for credentials to login to a new account
                WebTokenRequestResult webTokenRequestResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest);

                // If a token was successfully returned, then store the WebAccount Id into local app data
                // This Id can be used to retrieve the account whenever needed. To later get a token with that account
                // First retrieve the account with FindAccountAsync, and include that webaccount 
                // as a parameter to RequestTokenAsync or RequestTokenSilentlyAsync
                if (webTokenRequestResult.ResponseStatus == WebTokenRequestStatus.Success)
                {
                    ApplicationData.Current.LocalSettings.Values.Remove(StoredAccountToken);

                    ApplicationData.Current.LocalSettings.Values[StoredAccountToken] = webTokenRequestResult.ResponseData[0].Token;

                    MsTokenReceived?.Invoke(webTokenRequestResult.ResponseData[0].Token);
                }
            }
            catch (Exception ex)
            {
                App.ReportErrorInternalOnly(ex);
            }
        }

the only added code is this:

MsTokenReceived?.Invoke(webTokenRequestResult.ResponseData[0].Token);

which allows me to send the information back to the app that we have received the Oauth token, here I send back a string that is the Oauth token but you can send back whatever you wish.

For the Xbox we must find the default provider with only the ClientId:

        private async Task GetAccountProviderForXboxLogin()
        {
            //get the default provider by using only the Account Id
            var defaultProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(MicrosoftAccountProviderId);

            //get the token
            await RequestTokenAndSaveAccount(defaultProvider, AccountScopeRequested, AccountClientId);
        }


Now we just need to instantiate our class call the LogIntoMicrosoftService method for the IMicrosoftService and wait for the MsTokenReceived event to be fire for the login to have worked

private void Load()
{
       SimpleIoc.Default.GetInstance<IMicrosoftService>().LogIntoMicrosoftService();
       SimpleIoc.Default.GetInstance<IMicrosoftService>().MsTokenReceived += OnMsTokenReceived;
}
 
private void OnMsTokenReceived(string token)
{
      var AccessToken = token;
      SimpleIoc.Default.GetInstance<IMicrosoftService>().MsTokenReceived -= OnMsTokenReceived;
      ValidateMSLogin();
}


Happy Coding!

mardi 14 mars 2017

Using GraphQL in your Windows Application part II - using mutations [UWP,NET,GraphQL]

In this article we are going to see how we can do a Mutation in GraphQL in your .NET app, you will be able to find more documentation about mutations here: http://graphql.org/learn/queries/

We will be using the same endpoints and example as in the previous article:
Using GraphQL in your Windows Application part I [UWP,NET,GraphQL]

Just like the previous article related to querying GraphQL, you will need a text file that will hold a JSON mutation query as follow:

mutation($input: FavBookInput!){
  favoriteBook(input:$input){
    status
    clientMutationId
  }
}

Next we will need to create a Class what will hold the variables that we will pass in our query:

namespace GraphQL.QlFiles.M
{
    public class QueryAddToFavBooksMutationModel
        {
        public BookInput input { get; set; }
    }
    public class BookInput
    {
        public string bookXid { get; set; }
    }
}

Here are the string const that we will be using:

 public const string GrapgQL_PARAM_Query_and_Variables_To_CALL = "query={0}&variables={1}";
 public const string GRAPHQL_URL_BASE = "https://graphql.api.abcde.com/";
 public const string MyMutationQueryCallFile = "ms-appx:///QlFiles/M/AddToFavBooks.txt";

Doing a mutation on GraphQL is very much like doing a classic GET HTTP GraphQL query but you also need to pass variable in the query.  You will need to intenciante the QueryAddToFavBooksMutationModel class with the correct value so that you can add the correct book to your favorites.  Next you will convert the class to JSON and pass this it to your query as follows:

 private async void GraphQLMutationQuery()
        {
            //prepartion the variables that will be sent for the get query
            var myMutation = new QueryAddToFavBooksMutationModel()
            {
                input = new BookInput()
                {
                    bookXid = "ABC"
                }
            };

            //getting ou file
            var queryParams = await FileIOReaderHelper.ReadFromDefaultFileAsync(MyMutationQueryCallFile);

            //serializing our class to json so that we can send it in the GET call.
            string Variables = JsonConvert.Serialize(myMutation);

            var paramsToCall = String.Format(GrapgQL_PARAM_Query_and_Variables_To_CALL,
                            WebUtility.UrlEncode(queryParams),
                            WebUtility.UrlEncode(Variables)
                        );

            //creating our query
            var urlQuery = String.Format("{0}?{1}", GRAPHQL_URL_BASE, paramsToCall);

            //now you can do your http call 
            var response = await HttpClient.SendAsync(urlQuery);
        }





NAd there you have it you can now do mutations on GraphQL. This could be greatly improved, however for our example this gets the job done.

Happy coding.

jeudi 2 mars 2017

Using GraphQL in your Windows Application part I [UWP,NET,GraphQL]

init()

In this article we are going to see how can query a GraphQL endpoint, in the next article we are going to see how you could do a Mutation.

Here is a quick overview of what GrapgQL is http://graphql.org/ 

FYI: GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.

Now lets say that we have this end point https://grapql.api.MyWebsite.com

Also lets say that on this endpoint I can query it as follow:


fragment BookFields on Book {
  xid
  title
  author
  thumbnails
  year
}

{
  views {
    sections {
      edges {
        node {
          name
          title
          components {
            edges {
              node {
                __typename
                ...BookFields
              }
            }
          }
        }
      }
    }
  }
}


And lets say that the endpoint will respond with the following json payload:

{
  "data": {
    "views": {
       "sections": {
          "edges": [
            {
              "node": {
                "name": "HarryPotter_books",
                "title": "Harry Potter Books",
                "components": {
                  "edges": [
                    {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Philosopher's Stone",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 1997
                        }
                     
                    },
                    {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Chamber of Secrets",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 1998
                        }
                    },
     {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Prisoner of Azkaban",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 1999
                        }
                    },
     {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Goblet of Fire",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 2000
                       }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
}

Now we convert this JSON to C# classes:


public class NodeItem
{
    public string __typename { get; set; }
    public string xid { get; set; }
    public string author { get; set; }
    public string title { get; set; }
    public string thumbnails { get; set; }
    public int year { get; set; }
}

public class EdgeItem
{
    public NodeItem node { get; set; }
}

public class Components
{
    public List<EdgeItem> edges { get; set; }
}

public class Node
{
    public string name { get; set; }
    public string title { get; set; }
    public Components components { get; set; }
}

public class Edge
{
    public Node node { get; set; }
}

public class Sections
{
    public List<Edge> edges { get; set; }
}

public class Views
{
    public Sections sections { get; set; }
}

public class Data
{
    public Views views { get; set; }
}

public class RootObject
{
    public Data data { get; set; }
}


Ok now that we can create a blank UWP app, add 2 folders one for the models and one for the GraqhQL txt file.  In my solution the folders are called Model and QlFiles.  In QlFiles we will add a txt file called MyQuery.txt that will hold our query.

Next we will need to read this json text file using :

await StorageFile.GetFileFromApplicationUriAsync(appUri);
and 
await FileIO.ReadTextAsync(anjFile);

And now we just need to format our get query and we can do the HTTP call.


public sealed partial class MainPage : Page
{
        public const string GrapgQL_PARAM_To_CALL = "query={0}";
        public const string GRAPHQL_URL_BASE = "https://graphql.api.abcde.com/";
        public const string MyQueryCallFile = "ms-appx:///QlFiles/MyQuery.txt";

        public MainPage()
        {
            this.InitializeComponent();
            Loaded += MainPage_Loaded;
        }

        private async void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            //Fetching the json from the txt file
var queryParams = await FileIOReaderHelper.ReadFromDefaultFileAsync(MyQueryCallFile);
            
            //merging the parms for the query
var paramsToCall = String.Format(GrapgQL_PARAM_To_CALL,
                                             WebUtility.UrlEncode(queryParams));
            //Creating the query to call
var urlQuery = String.Format("{0}?{1}",
                                         GRAPHQL_URL_BASE,        
                                         paramsToCall);

            //doing the http call 
            var response = await HttpClient.SendAsync(urlQuery);
            var responseJson = await response.Content.ReadAsStringAsync();

            //you can deserialize with the RootObject class you created
            var responseObject = JsonService.DeserializeObject<RootObject>(responseJson);

        }

        public static class FileIOReaderHelper
        {
            //Read the content from Json file 
            public static async Task<string> ReadFromDefaultFileAsync(string fileName)
            {
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    throw new ArgumentNullException(nameof(fileName));
                }

                Uri appUri = new Uri(fileName);

                IStorageFile anjFile = await StorageFile.GetFileFromApplicationUriAsync(appUri);

                string txtFile = await FileIO.ReadTextAsync(anjFile);

                return txtFile;

            }
        }
}


As of today as you can see using GraphQL in you .NET application is a bit hash and not developer friendly.  If by any chance you have a cleaner way of doing it don't hesitate to comment!

Happy coding!



dimanche 1 janvier 2017

Using .NET WebAuthenticationBroker for Google Login in your Windows 10 application [UWP,C#,GOOGLE]

I was fighting with my Google login on my UWP app and thus thought that it would be great if I just copied and pasted my code here so that it might help others.

Long story short, I did not want to use the google SDK to log into my app so I ended up using WebAuthenticationBroker.AuthenticateAsync.   For the WebAuthenticationBroker you need a startUrl and a endUrl which you can find here:
var googleUrl = new System.Text.StringBuilder();
            googleUrl.Append("https://accounts.google.com/o/oauth2/auth?client_id=");
            googleUrl.Append(Uri.EscapeDataString(ClientID));
            googleUrl.Append("&scope=");
            googleUrl.Append(Uri.EscapeDataString("https://www.googleapis.com/auth/plus.profile.emails.read"));
            googleUrl.Append("&redirect_uri=");
            googleUrl.Append(Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob"));
            googleUrl.Append("&response_type=code");


string endURL = "https://accounts.google.com/o/oauth2/approval?";


One small problem, was that when using WebAuthenticationBroker on UWP you don't get an access token but a authorization code which doesn't really help you,  because you cant authenticate with an authorization code, I needed an access token.

What we need to do next is a POST call on  https://accounts.google.com/o/oauth2/token
with my client id, client secret and authorization code and a few other parameters, here is the full list:
 var pairs = new Dictionary<string, string>();
                    pairs.Add("code", authorizationCode);
                    pairs.Add("client_id", ClientID);
                    pairs.Add("client_secret", ClientSecret);
                    pairs.Add("grant_type", "authorization_code");
                    pairs.Add("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");

We encode the content:
var formContent = new HttpFormUrlEncodedContent(pairs);

Next we do our POST call:
await client.PostAsync(new Uri("https://accounts.google.com/o/oauth2/token"), formContent);

And Voila you have your auth token =)
string response = await httpResponseMessage.Content.ReadAsStringAsync();

Full code here:
Warning to people that like sexy code this will hurt you eyes:

 public async Task<string> LogIntoGoogleClean()
 {
            var googleUrl = new System.Text.StringBuilder();
            googleUrl.Append("https://accounts.google.com/o/oauth2/auth?client_id=");
            googleUrl.Append(Uri.EscapeDataString(ClientID));
            googleUrl.Append("&scope=");
            googleUrl.Append(Uri.EscapeDataString("https://www.googleapis.com/auth/plus.profile.emails.read"));
            googleUrl.Append("&redirect_uri=");
            googleUrl.Append(Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob"));
            googleUrl.Append("&response_type=code");

            //approval
            string endURL = "https://accounts.google.com/o/oauth2/approval?";

            Uri startUri = new Uri(googleUrl.ToString());
            Uri endUri = new Uri(endURL);

            try
            {
                // Using WebAuthenticationBroker
                WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, startUri, endUri);

                //Checking to see if we haev succeded
                if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
                {
                    Debug.WriteLine("ResponseData: " + webAuthenticationResult.ResponseData);

                    //getting just the autorizationCode to continue and get the token 
                    var authorizationCode = webAuthenticationResult.ResponseData.Substring(13);

                    //lets get crazy and get the access token so that i can really login
                    var pairs = new Dictionary<string, string>();
                    pairs.Add("code", authorizationCode);
                    pairs.Add("client_id", ClientID);
                    pairs.Add("client_secret", ClientSecret);
                    pairs.Add("grant_type", "authorization_code");
                    pairs.Add("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");


                    var formContent = new HttpFormUrlEncodedContent(pairs);

                    //please dont hate me but this is dirty
                    var client = new HttpClient();
                    var httpResponseMessage =
                        await client.PostAsync(new Uri("https://accounts.google.com/o/oauth2/token"), formContent);
                    string response = await httpResponseMessage.Content.ReadAsStringAsync();

                    //but at least I got it to work :P
                    GoogleAccessToken token = JsonConvert.DeserializeObject<GoogleAccessToken>(response);

                    //return access token
                    return token.access_token;
                }
                else
                    return webAuthenticationResult.ResponseStatus.ToString();
            }
            catch (Exception Error)
            {
                //report the issue
App.RepportError(Error); } return "error"; }

Happy Coding!

dimanche 4 décembre 2016

Webview Edge vs IE, ScriptNotify working on WP 8.1 but not Windows 10, when the Edge Webview throws you a little curve ball and how to fix it [HTML,C#]

I need to use a Webview in my app so that the application could communicate with my Webview and vise versa.  In my previous article I explained how you can call JavaScript methods from an app [Here], but what happens when the Webview wants to send you some kind of information.

You will tell me, well just use:

window.external.notify(message); 


 and you are good to go! Or use like you did in your previous article:

window.SCObject.getMyMethod();    

However I had the constraint that I am not the one developing the Html and JavaScript that is being called in the Webview, and thus had to work with what I was given.

What you must now is that for Windows Phone 8.1 the Webview uses IE and for Windows 10 the Webview uses Edge.

So, lets head back to my story, on Window Phone 8.1 and Windows 8.1 when I executed a html page in my Webview that had:


function SendTestNotify() {
   if(typeof window.external.notify !== 'undefined')
   {
     window.external.notify('test info');
   }
}           

My Webview would send me back events through ScriptNotify.  However on Windows 10 this code will not send you anything...

So going back to the basic I test this on Windows Phone 8.1

 window.external.notify(typeof window.external.notify);

And got a 'undefined' oddly when you test this on Windows 10 you also get  'undefined' ... So now you can start thinking that I messed up somewhere, however I have found out that trying this code on Windows Phone and on Windows 10 will also not give you the same result:

 window.external.notify(typeof window.external.notify !== 'undefined');

On Windows Phone 8.1 this will send you true and on Windows 10 false.  So I have concluded that the Windows 10 Webview is weird. It can tell me the type of window.external.notify however the JavaScript doesn't seem to be able to detect what typeof it is.

All in all, there will need to be specific code for Windows 10 because its Webview does not behave like the other Webview  on windows 8.x.  Thus this part of the JavaScript code does not work as expected on Windows 10:

if(typeof window.external.notify !== 'undefined') 

Happy Coding,

lundi 15 août 2016

Communicating back and forth with a WebView in a UWP application using AddWebAllowedObject or ScriptNotify [HTML,C#]

There are many solutions to the problem, in this article I will try and explain why I I think that using a Windows Runtime Component library is better then using a window.external.notify to try and communicate with your WebView in a UWP application.


Using window.external.notify() and ScriptNotify 

Trying to get your application and you HTML page to communicate with each other is never easy and the WebView in UWP doesn't seem to really help us out (IMO of course).  If you try to use window.external.notify(in your WebView not only do you need the link to be in HTTPS but also need to declare the https link(s) in the manifest of your application and need to have access to the html page to add IE/EDGE specific code.

FYI: the you can only declare HTTPS links in Content URi that is why you need your webview link to be HTTPS.

And so your Content URIs might look like this for example:


Also using window.external.notify would force us to have to listen to the ScriptNotify event, and parse the value to know what method we need to call, it would look something like this:

public MainPage()
{
       this.InitializeComponent();
       string src = " https://XXXXXXXXX.com/";
       webView.Navigate(new Uri(src));
       webView.ScriptNotify += webView_ScriptNotify;
}


void webView_ScriptNotify(object sender, NotifyEventArgs e)
{
    var elementPassed =  e.Value; //need to parse this
    
    // now we need to parse our value to know what method needs to be called
    string elementName = elementPassed[0];
    string elementValue = elementPassed[1];
}

For me this was not an option, I wanted to be able to call my C# methods from within my html app.


Looking at MSDN we can see that WebView.AddWebAllowedObject method will Adds a ''native Windows Runtime object as a global parameter to the top level document inside of a WebView''.  This sounds EXACTLY like what I want: to be able to call C# code from within my local html page using javascript!

Creating the Windows Runtime Component library to communicate with the WebView

So let get started, first we need to create a new project Windows Runtime Component library.  For some weird reason you need to add create this in new WRC library and mark this class this  [AllowForWeb] so that you can bypass the WebView security subsystem... (weird but I guess MS must have a good reason for doing this?).

Here is what my Windows Runtime Component library looks like, it only have one class called HtmlCommunicator that is a public sealed class and the attribute AllowForWeb.

using System;
using Windows.ApplicationModel;
using Windows.Foundation.Metadata;


namespace MainApp.Connector
{
    [AllowForWeb]
    public sealed class HtmlCommunicator
    {
        public void getHtmlSpecificEvent()
        {
          // do something else
        }

        public string getAppVersion()
        {
            PackageVersion version = Package.Current.Id.Version;
            return String.Format("{0}.{1}.{2}.{3}",
                                 version.Major, version.Minor, version.Build, version.Revision);
        }
    }
}


Getting the Html page to communicate with our C# code

Lets start with the our main page of our XAML app, I will add a simple WebView to the app:

<Page
    x:Class="MainApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MainApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <WebView VerticalAlignment="Bottom" 
             NavigationStarting="HtmlWebView_NavigationStarting"
             x:Name="HtmlWebView"
             Margin="0"
             Height="146"
             />
    </Grid>
</Page>

Now for the cs part of the page, we will now get our Windows Runtime Component library hocked onto the WebView .  We will need to call AddWebAllowedObject  every time the WebView navigates to a new web page, by doing this we can access the native objects that are in our HtmlCommunicator class:


        private HtmlCommunicator communicationWinRT = new HtmlCommunicator();


        private void HtmlWebView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
        {
            this.HtmlWebView.AddWebAllowedObject("SCObject", communicationWinRT);
        }

Lastly we create our html page (because I am lazy I will host the html page inside the application) with 2 methods that will call 2 different c# methods.

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>

    <button style="width: 200px; height: 60px; font-size: x-large" onclick="HtmlPageEvent()">Get Event</button>

    <button style="width: 250px; height: 60px; font-size: x-large" onclick="HtmlGetAppVersion()">Get App Version</button>

    <script type="text/javascript">
        function HtmlPageEvent() {
            window.SCObject.getHtmlSpecificEvent();
        }

        function HtmlGetAppVersion() {
            var version = window.SCObject.getAppVersion();
            alert(version);
        }
    </script>

</body>
</html>

And there you have, you can now call C# methods from within your local HTML page in you UWP application.

I truly believe that being able to call a specific method from within out HTML page is a better solution then using a window.external.notify() and having to catch the event using ScriptNotify to the route the event and parameters to the correct method.

You can find my solution here
Happy coding.



mercredi 1 juin 2016

Customizing Template 10 page header bar by editing its styles [Template10,XAML,UWP]

In this very short article we will look at how to customize your PageHeader in the Template 10 Control.

In the example we will remove the three dots that allow you to show the name of the button or show the secondary buttons in the header bar.

Or in other words we will go from this:


To this :

To keep things very simple I have just cloned the default Hamburger sample app from template 10 which can be found here under  https://github.com/Windows-XAML/Template10/tree/master/Templates%20(Project)/Hamburger

Next we need to find the default styles for the PageHeader and the PageHeaderButton, the two different styles can be found here under https://github.com/Windows-XAML/Template10/blob/master/Template10%20(Library)/Themes/PageHeader.xaml

What you will need to do is look under the style named PageHeader and under each VisualTransition you will have  ObjectAnimationUsingKeyFrames elements that is targeting MoreButton and should comment out this Element.

Here is an example of what one of the ObjectAnimationUsingKeyFrames look like:


<ObjectAnimationUsingKeyFrames 
      Storyboard.TargetName="MoreButton" 
      Storyboard.TargetProperty="VerticalAlignment">
     <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="Stretch" />
</ObjectAnimationUsingKeyFrames>

You will need to comment out element that reference MoreButton about 34 times, once you have done this you should not be seeing the three anymore congratulation!

Here is the Link to the sample project.
Happy coding.