mercredi 6 décembre 2017

Reactive UI with your UWP applications [XAML,C#,RxUI]

In the tutorial we will create a sample application that uses ReactiveUI in a UWP application. what we will do is have a text field, and whenever the user types something into it, you want to make a network request which searches for that query. In bonus we will add a back off to wait for the user to stop typing before doing the request.

The idea is not mine but taken from the ReactiveUI.


First create your UWP application and add the ReactiveUI nuget package:

Either by using the command line:

Or in the Nuget package Manager:

Once installed let the fun begin!

Because we want to do a search we will have to bind a property to the textblock, first in the ViewModel of the page we will add:
        private string _searchValue;
         
        public string SearchValue
        {
            get { return _searchValue; }
            set { Set(ref _searchValue, value); }
        }

Next in the XAML page we will add the SearchValue property to the AutoSuggestBox control as follow:
<AutoSuggestBox
                x:Name="SearchBoxSuggestions"
                Grid.Row="0"                
                PlaceholderText="{Binding Path=[txt_SearchPlaceHolder], Source={StaticResource LocalizedStrings}, FallbackValue='txt_SearchPlaceHolder'}"
                QueryIcon="Find"
                Text="{Binding SearchValue, Mode=TwoWay}" />


In our ViewModel we will need to setup the ReactiveUI events:
 public void SetupRxUI()
 {
               this.WhenAnyValue(x => x.SearchValue)
                    .Where(x => x != null && x.Length >= 3)                   
                   .Subscribe(o => OnSearchCommand());
 }

This means that when the SearchValue property changes and that it is not null and have more then 2 chars we will launch the OnSearchCommand() method.
public void OnSearchCommand()
{
   //do a search
}

We can even imagine that the search command should not be fired every time but only once the user has stopped typing for 700 milliseconds and we would have something like this:

 public void SetupRxUI()
 {
            var Interval = TimeSpan.FromMilliseconds(700);          

            this.WhenAnyValue(x => x.SearchValue)
                    .Where(x => x != null && x.Length >= 3)
                   .Throttle(Interval, RxApp.MainThreadScheduler)
                   .Subscribe(o => OnSearchCommand());
 }

and there you have it!

//Happy Coding

jeudi 30 novembre 2017

Building your Shell for your UWP app, quick tutorial on how to get started [XAML,C#]

In this tutorial we will see how to setup your shell in your UWP application using the UWP Community Toolkit HamburgerMenu control.  I really liked the shell that was done for the sample app of the UWP Community Toolkit and thus we will try to do the same thing!

The HamburgerMenu control in the UWP Community Toolkit sample has an ineteresting way or using narrow and wide states.  It allow us to have a hamburger menu when the app is in narrow mode or have the navigation at the top when we are in the wide mode, this is what we are going to reproduce.

This is when you are in wide mode:



This is when you are in Narrow mode:



And that is what we are going to setup in this tutorial!

Lets start, first we need create a page called Shell.xaml/.cs this will be our shell of our application. 

Next we will create a HamburgerMenu control that we will named x:Name="HamburgerMenu" inside the HamburgerMenu tag we will add a VisualStateManager which will allow us to change between the Narrow and Wide States of the app.  Depending on which state we are in we will need to change the style and the ItemTample of the HamburgerMenu.

 <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="WindowStates">
                <VisualState x:Name="NarrowState">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="0" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="HamburgerMenu.Style" Value="{StaticResource VerticalHamburgerMenu}" />
                        <Setter Target="HamburgerMenu.ItemTemplate" Value="{StaticResource VerticalItemTemplate}" />

                        <Setter Target="HamburgerMenu.IsPaneOpen" Value="False" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="WideState">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="700" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="HamburgerMenu.Style" Value="{StaticResource HorizontalHamburgerMenu}" />
                        <Setter Target="HamburgerMenu.ItemTemplate" Value="{StaticResource HorizontalItemTemplate}" />

                        <Setter Target="HamburgerMenu.PaneBackground" Value="White" />
                        <Setter Target="HamburgerMenu.PaneForeground" Value="Black" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>


For this page we will add 2 DataTemplates :

 <Page.Resources>
        <DataTemplate x:Key="HorizontalItemTemplate" x:DataType="local:SampleCategory">
            <Grid>
                <TextBlock
                    Grid.Column="1"
                    VerticalAlignment="Center"
                    FontFamily="Segoe UI"
                    FontSize="15px"
                    FontWeight="Normal"
                    Foreground="Black"
                    Text="{x:Bind Name}" />
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="VerticalItemTemplate" x:DataType="local:SampleCategory">
            <Grid>
                <TextBlock
                    Padding="30,14"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Top"
                    FontFamily="Segoe UI"
                    FontSize="20px"
                    FontWeight="SemiBold"
                    Foreground="White"
                    Opacity="0.8"
                    Text="{x:Bind Name}" />
            </Grid>
        </DataTemplate>
    </Page.Resources>

Next we will need to set the different styles for the HamburgerMenu which you can find here, most of these style were taken from the sample UWP app of the toolkit and reworked to fit our needs you can check it out here.


In our Shell.xaml.cs file we will add 3 properties:

 public static Shell Current { get; private set; }
So that we can acces the shell from anywhere in the application.

private NavViewModel _currentSample;
So that we know under which tab we arer navigating

private List<NavViewModel> NavigationViews { get; set; }
To load the different view that should be accessible in the nav bar.


Next we need to work on the OnNavigatedTo method, here we are going to want to populate our NavigationViews property and bind it to our HamburgerMenu as follows:

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            NavigationFrame.Navigating += NavigationFrame_Navigating;

            NavigationViews = new List<NavViewModel>();

            NavigationViews.Add(new NavViewModel() { Name = "Red view", PageView = "RedView" });
            NavigationViews.Add(new NavViewModel() { Name = "Blue view", PageView = "BlueView" });
            NavigationViews.Add(new NavViewModel() { Name = "Orange view", PageView = "OrangeView" });

            HamburgerMenu.ItemsSource = NavigationViews;

            NavigationFrame.Navigate(typeof(BlueView));
        }


You should have something like this in the end:

        public static Shell Current { get; private set; }
        private NavViewModel _currentSample;
        private List<NavViewModel> NavigationViews { get; set; }


        public Shell()
        {
            this.InitializeComponent();
            Current = this;
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            NavigationFrame.Navigating += NavigationFrame_Navigating;

            NavigationViews = new List<NavViewModel>();

            NavigationViews.Add(new NavViewModel() { Name = "Red view", PageView = "RedView" });
            NavigationViews.Add(new NavViewModel() { Name = "Blue view", PageView = "BlueView" });
            NavigationViews.Add(new NavViewModel() { Name = "Orange view", PageView = "OrangeView" });

            HamburgerMenu.ItemsSource = NavigationViews;

            NavigationFrame.Navigate(typeof(BlueView));
        }


Next we will what to handle the NavigationFrame_Navigating this will allow us to make sure that the correct tab is selected deepending on which tab we click, tap, etc

        private async void NavigationFrame_Navigating(object sender, NavigatingCancelEventArgs navigationEventArgs)
        {
            if (navigationEventArgs.Parameter != null && NavigationViews != null)
            {
                _currentSample = NavigationViews.Where(a => a.Name == navigationEventArgs.Parameter).FirstOrDefault();
            }
            else
            {
                _currentSample = null;
            }

            await SetHamburgerMenuSelection();
        }



        private async Task SetHamburgerMenuSelection()
        {
            if (_currentSample != null)
            {
                if (HamburgerMenu.Items.Contains(_currentSample))
                {
                    HamburgerMenu.SelectedItem = _currentSample;
                    HamburgerMenu.SelectedOptionsItem = null;
                }
            }
            else
            {
                try
                {
                    HamburgerMenu.SelectedItem = null;
                    HamburgerMenu.SelectedOptionsIndex = 0;
                }
                catch (Exception e)
                {
                    //fail in silence
                }
            }
        }

and there you have it =), have fun paying around with the demo app.

Happy coding!

Full Source code of the app here.


mercredi 11 octobre 2017

Allowing a Horizontal list to have a Slidable items [XAML,UWP]

For a hackathon I needed to have items that where slideable when they where in a Horizontal list.
To do this I decided to use the UWP Community Toolkit and rework the SlidableListItem control.

To speed things up we will need to use the Animations from the UWP Community toolkit, install it by using package manager:



Now you should be able to use this namespace :

using Microsoft.Toolkit.Uwp.UI.Animations;

Next lets have a look at the SlidableItem from the UWP toolkit.  You can see that it has a slidable mechanism from left to right and right to left, and that it uses animation to transition from on state to another.

I converted this control so that it would work for my needs, basically all I did was replace these with a mechanism from top to bottom and left to top.  Also all of the animations where changed from the X axis to the Y axis and I had to rework how the animations worked.

You can see the changes here on the Github page, I wont go over them as there isnt any added value for me to do this.

In the demo app, you will see a horizontal list with items in it:
When you swipe down in this sample you will see a red background with the wording delete (you can customise this as you wish) :
When you swipe up you will see another possible action:
To customize your DataTemplate have a look at the one in the sample app:


 <DataTemplate x:Key="KeyQueueSwipeTemplate">
                <local:SlidableGridItem
                    MinWidth="300"
                    MaxWidth="300"
                    HorizontalAlignment="Stretch"
                    ActivationWidth="71"
                    AllowDrop="True"
                    BottomBackground="SkyBlue"
                    BottomCommand="{Binding DataContext.CallBottomItemCommand, RelativeSource={RelativeSource TemplatedParent}}"
                    BottomForeground="White"
                    BottomIcon="Play"
                    BottomLabel="Next"
                    CanDrag="True"
                    DataContext="{Binding DataContext, ElementName=Page, Mode=OneWay}"
                    IsBottomCommandEnabled="True"
                    IsOffsetLimited="False"
                    IsPointerReleasedOnSwipingHandled="True"
                    IsTopCommandEnabled="True"
                    MouseSlidingEnabled="True"
                    TopBackground="OrangeRed"
                    TopCommand="{Binding DataContext.CallTopActionItemCommand, RelativeSource={RelativeSource TemplatedParent}}"
                    TopForeground="White"
                    TopIcon="Delete"
                    TopLabel="Delete">
                    <Grid Height="190" Background="LightGray">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <slidableitemsample:MyUserControl
                            Grid.Column="0"
                            Margin="0,0,0,0"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            AllowDrop="True"
                            CanDrag="True"
                            DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}" />
                    </Grid>
                </local:SlidableGridItem>
            </DataTemplate>


As you can see the most important parts are:
  • BottomBackground="SkyBlue"
  • BottomCommand="{Binding DataContext.CallBottomItemCommand, RelativeSource={RelativeSource TemplatedParent}}"
  • BottomForeground="White"
  • BottomIcon="Play"
  • BottomLabel="Next"
Bottom part of the control and
  • TopBackground="OrangeRed"
  • TopCommand="{Binding DataContext.CallTopActionItemCommand, RelativeSource={RelativeSource TemplatedParent}}"
  • TopForeground="White"
  • TopIcon="Delete"
  • TopLabel="Delete"
for the top part of the control, changing these are what will allow you to change how the control behaves.

You can find my code and the sample here.

Happy coding!

mercredi 4 octobre 2017

Editing the HTTP header done by your WebView using NavigationStarting in a UWP application [HTML,C#]

I recently encounter a very weird issue with how my WebView was doing some of  my HTTP calls on redirects.  Sometimes when calling a URL that will do a redirect the HTTP headers would get lost or replaced by some default values.

To fix this the only solution that I found was to override the HTTP query done every time the WebView started navigating to another page.   In this I was lucky as we have a NavigationStarting event that is fired when this happens, thus I have NavigationStarting += Wb_NavigationStarting; when I am creating my WebView.

Now that ce have caught this event we need to edit  it in Wb_NavigationStarting method, I will unbind the event (so that it dosent fire multiple times), tell the WebView that I am handling the event with args.Cancel = true; and now edit the HTTP query with a method that I will call NavigateWithHeader .

In the method NavigateWithHeader I will just add again my header and my authorization token so that the HTTP query has all of the values it is supposed to have, you will have something like this:

var requestMsg = new Windows.Web.Http.HttpRequestMessage(HttpMethod.Get, uri);
requestMsg.Headers.Add("User-Agent", "some user agent");
requestMsg.Headers.Add("Authorization", "token abc");                      
MyWebView.NavigateWithHttpRequestMessage(requestMsg);
MyWebView.NavigationStarting += Wb_NavigationStarting;


 Here is the full code:


 private WebView NewWebView()
        {
            var webView = new WebView(WebViewExecutionMode.SameThread);
            webView.NavigationStarting += Wb_NavigationStarting;         
            return webView;
        }     

private void NavigateWithHeader(Uri uri)
        {
            var requestMsg = new Windows.Web.Http.HttpRequestMessage(HttpMethod.Get, uri);
            requestMsg.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063");
            MyWebView.NavigateWithHttpRequestMessage(requestMsg);
            MyWebView.NavigationStarting += Wb_NavigationStarting;
        }

private void Wb_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
        {
            MyWebView.NavigationStarting -= Wb_NavigationStarting;
            args.Cancel = true;
            NavigateWithHeader(args.Uri);
        }

Happy Coding!

mercredi 20 septembre 2017

Setting a cookie and HTTP headers in your WebView in a UWP application [WebView,C#]

In this post we will see how to set values in the header and the cookie of your WebView in a UWP application.

First we need a method to create a new WebView:

//Creating a new webview
private WebView NewWebView()
        {
            var webView = new WebView(WebViewExecutionMode.SameThread);
            return webView;
        }

To edit the HTTP header that will be called by the WebView, and because we are using HttpRequestMessage from the Windows.Web.Http namespace.  We will edit the header like we would normally by creating a HttpRequestMessage property and adding a header by using Headers.Add:

private HttpRequestMessage NewRequest(Uri url)
       {
            var message = new HttpRequestMessage(HttpMethod.Get, url);
            
            //adding User Agent to header            
            message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063");
            
            //adding Authorization to header
message.Headers.Add("Authorization", "Bearer xxxxxxxxxxxx"); return message; }


Next here is how we can set cookies for our WebView, make sur that for the HttpCookie(key, ".YourDomain.com", "/") you set the correct domain or it will not work. Make sur that you set all the value correct (if the cookie is for a third party then make sure that SetCookie is set to TRUE and not false).

private void SetCookieInWebView(string key, string value)
        {
            Windows.Web.Http.Filters.HttpBaseProtocolFilter filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
            Windows.Web.Http.HttpCookie cookie = new Windows.Web.Http.HttpCookie(key, ".YourDomain.com", "/");
            cookie.Value = value;
            filter.CookieManager.SetCookie(cookie, false);
        }
 
And lastly is how you could for example use all of these methods together.

//creating a new WebView
MyWebView = NewWebView();

//Setting cookies
SetCookieInWebView("Key1", "xxxxxxxxxxxxxxx"); SetCookieInWebView("Key2", "aaaaaaaaaaaaaaaa"); SetCookieInWebView("Key3", "bbbbbbbbbbbb"); //creating http request message to send to the webview HttpRequestMessage request = NewRequest("http:// xxxxx .com"); //doing http call MyWebView.NavigateWithHttpRequestMessage(request);

Happy Coding!


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!

lundi 10 avril 2017

Using state triggers to change your ItemTemplate in a GridView or ListView [XAML][UWP]

Here is another very quick post about State Triggers and why they are awesome, recently I needed to have  2 very different visuals depending on what size my application was and on what page my application was. Usually I set my StateTriggers inside my UserControl however today this was not an option because of the design on my application.

My best option was to change the ItemTemplate on my gridview using statetriggers, I needed to have 2 different states depending I was in Narrow or Wide mode.

Here is the Gridview:

 <GridView 
            x:Name="MyDemoList"
            Grid.Row="0"
            VerticalAlignment="Stretch"
            HorizontalAlignment="Stretch"
            ItemTemplate="{StaticResource KeyWideTemplate}"
            />

Here is my statetrigger:

        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="VisualStateNarrow">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger x:Name="VisualStateNarrowTrigger" MinWindowWidth="450" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="MyDemoList.(ItemsControl.ItemTemplate)" Value="{StaticResource KeyNarrowTemplate}" />
                    </VisualState.Setters>
                </VisualState>

                <VisualState x:Name="VisualStateNormal">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger x:Name="VisualStateNormalTrigger" MinWindowWidth="600" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="MyDemoList.(ItemsControl.ItemTemplate)" Value="{StaticResource KeyWideTemplate}" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>


This means that when the application is in wide mode the KeyWideTemplate will be used in the GridView template



and when the application is in narrow mode the KeyNarrowTemplate will be used.



Happy coding.
Github sample here

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);
        }





And 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!