Monthly Archives: June 2018

Xamarin Forms TabbedPage

The TabbedPage is, as you’d probably expect, a page that hosts ContentPage and NavigationPage elements and displays “tabs” for selecting between those pages.

You cannot have a ContentPage hosting a tab control within it without using a third party control or writing your own.

Let’s create a TabbedPage based application

Let’s take look at implementing a TabbedPage based UI in Visual Studio 2017 (the Visual Studio for Mac project template creates a tabbed page application by default).

  • In Visual Studio 2017, File | New | Project
  • In the search box, type mobile (or select Cross-Platform | Mobile App (Xamarin.Forms))
  • Give your project a name, mine’s TabbedPageExample
  • Select Blank App, I’m aiming to write for all three listed platforms and so keep all three checked, I then select .NET Standard (or Shared Project if you prefer)
  • Build the project just to get NuGet packages updated etc.

We’ve got our project created and by default on Visual Studio 2017 you’ll have created a MainPage.xaml which is a ContentPage, we’re going to change this to a TabbedPage

  • Open the MainPage.xaml and change ContentPage to TabbedPage
  • Before we leave MainPage.xaml remove the StackLayout and everything within it, we won’t be needing this
  • Open the MainPage.xaml.cs and change ContentPage to TabbedPage here also
  • Right mouse click on the shared project (the one not suffixed with a platform name) and select Add | New Item. Select The Xamarin.Forms item on the left, then Content Page (note: not the Content Page (C#) as we’re going to just writing XAML here). Do this two more times as these will form our three tab pages. Mine are named ProjectsPage, HistoryPage and AboutPage.
  • Back in MainPage.xaml, add the following, within the TabbedPage element (i.e. where StackLayout used to reside)
    <local:ProjectsPage />
    <local:HistoryPage />
    <local:AboutPage />
    

    Note: For those not used to XAML etc. the local text is an xmlns (namespace), automatically added to our XAML files.

  • Now in each XAML file (ProjectsPage.xaml, History.xaml etc.) just change the Label to use the display then name as the page (just so we can see the page changes when we click on a tab). Also add a Title=”” to each ContentPage as an attribute and inside the “” put the tab name, i.e. Projects, History, About

If you build and run this now (I’m using the Visual Studio Emulator for Android to view things on Windows), you should see – on Android and UWP three tabs with the labels all at the top of the screen, if you run this against an iOS emulator/simulator the tabs will be at the bottom of the screen and the text is very small – this is because Android and UWP, by default, show just text, iOS be default shows text and an image, so the small text is that size to accommodate the image.

Platform specific XAML

We’re trying to keep all our shared code, whether these are services, other libraries or UI, in the shared project. Xamarin.Forms allows us to conditionally add XAML based upon the platform, i.e.

<ContentPage.Icon>
   <OnPlatform x:TypeArguments="FileImageSource">
      <On Platform="iOS" Value="history.png"/>
   </OnPlatform>
</ContentPage.Icon>

For each ContentPage we add the above as a child to the ContentPage element. the x:TypeArguments refers to the type of objects for the On Platform Value, i.e. these are Image file locations in this case.

As this adds platforms specific conditions to the XAML, we would then create the various .png images, not within the shared code but instead within the TabbedPageExample.iOS project, into the Resources folder and marked as BundleResource.

Each image file should come in three sizes, so let’s suppose we create an file about.png (for the About tab). This should be 30 x 30 pixels in size. Then the next file should be about@2x.png and should be 60 x 60 pixels, finally the last file should be about@3x.png and should be 90 x 90 pixels in size.

Once you’ve created a group of three image’s per tab (as outlined) and ensured their Build Action is BundleResource and got the XAML correctly references each of the smaller images, then you should find that when you run the app. on iOS, text and an image is displayed on each tab. Whilst Android and UWP is solely text. By only including the images in the iOS project you’re not wasting space on the other projects that do not use them.

Code

Code is available on github.

Errors within gRPC

Whilst we’d love our code to work perfectly, we also need to handle errors that might come from our server code.

We might simple wrap any response’s in a Result class (or similar) which returns data along with a success or failure status code (or ofcourse include a status code in a response object).

C#, Java etc. also use exceptions, so we might prefer to throw exceptions on the server.

gRPC supports exceptions but with some limitations…

Exceptions come with status codes

Any exceptions thrown on the server will result in RpcException being thrown – these do NOT reflect the exception that was originally thrown, i.e. if your server code threw an ArgumentException the client will only ever see an RpcExecption with a StatusCode of Unknown.

As you can see, an RpcException includes a status code, so obviously our server can instead throw an RpcException and supply the Status and StatusCode along with it, for example

throw new RpcException(
   new Status(
      StatusCode.FailedPrecondition, 
      $"Argument {nameof(request)} is invalid"));

Ofcourse handling such exceptions is as simple as

try
{
   var response = client.Query(new NotesReques())
}
catch(RpcException e) 
{
   Debug.WriteLine(e.Status.Detail);
   Debug.WriteLine(e.Status.StatusCode);
}

A little more gRPC

In my last two posts I looked at using .proto files to define the IDL which protoc.exe along with gRPC generated our preferred language’s data files and method calls – in our case this meant generating C# files.

Now let’s look at how we can extend our code a little further, for example to include meat data/headers for sending tokens or other state between the client and server.

What was generated for us?

When we generated our code using the gRPC plugin, we started with the IDL method written as

service MusicService {
   rpc Query(NotesRequest) returns (NotesResponse) {
   }

however several overloads for this method were generated (I’ve cleaned them up to remove superfluous namespaces etc. and to make them easier to read in a blog post

public virtual NotesResponse Query(
   NotesRequest request, 
   Metadata headers = null, 
   DateTime? deadline = null, 
   CancellationToken cancellationToken = 
      default(CancellationToken))
{
   return Query(request, 
      new CallOptions(
         headers, 
         deadline, 
         cancellationToken));
}

public virtual NotesResponse Query(
   NotesRequest request, 
   CallOptions options)
{
   return CallInvoker.BlockingUnaryCall(
       __Method_Query, 
       null, 
       options, 
       request);
}

public virtual AsyncUnaryCall<NotesResponse> QueryAsync(
   NotesRequest request, 
   Metadata headers = null, 
   DateTime? deadline = null, 
   CancellationToken cancellationToken = 
       default(CancellationToken))
{
   return QueryAsync(
       request, 
       new CallOptions(
           headers, 
           deadline, 
           cancellationToken));
}

public virtual AsyncUnaryCall<NotesResponse> QueryAsync(
   NotesRequest request, 
   CallOptions options)
{
   return CallInvoker.AsyncUnaryCall(
      __Method_Query, 
      null, 
      options, 
      request);
}

We’ve got several overloads, include async version and there’s support for passing metadata headers, a deadline (similar to a timeout), as well as a cancellation token.

Metadata

We might use the Metadata argument to pass in SSO tokens or other relevant information that does not form part of the actual message, here’s an example of using the Query method in such a way

// client code
var response = client.Query(request, new Metadata
{
   new Metadata.Entry("SSO", token)
});

// server 
var token = 
   context?.RequestHeaders?.FirstOrDefault(e => e.Key == "sso");

Note: Beware, for some reason, the key has been turned to lower case.

In the server method we implemented in the last post you’ll notice that along with the request there’s the ServerCallContext type which contains all the other parameters that might be sent via the client, i.e. headers, cancellation token etc.

The server can return meta data using the ServerContext’s ResponseTrailers. However the client must use the Async versions of the client methods to receive these extra bits of data.

Here’s an example of returning something via ResponseTrailers, from the server

context.ResponseTrailers.Add(new Metadata.Entry("SSO", "Success"));

and the client would change to use the QueryAsync overload and possibly look like this

var response = client.QueryAsync(request, new Metadata
{
   new Metadata.Entry("SSO", "abcdefg")
});

foreach (var note in response.ResponseAsync.Result.Notes)
{
   Console.WriteLine(note);
}

var rt = response
   .GetTrailers()
   .FirstOrDefault(e => e.Key == "sso")
   .Value;

CallOptions

Ultimately the methods that take Metadata and other arguments end up wrapping those arguments in a CallOptions struct. However CallOptions also supports CallCredentials as well as a couple of other types (WriteOptions and ContextPropagationToken which I will not be looking at in this post).

Using gRPC with Protocol Buffers

In the last post, Using Protocol Buffers, we looked at creating .proto files and how we generate C# code from them along with how to stream the binary data created by the generated code.

Let’s now look at how we might like to use Protocol Buffers “over the wire”.

Whilst we can write our own sockets code and stream data via this, there’s a close relationship between gRPC and Protocol Buffers which allows us to generate RPC code using the. proto file.

Let’s begin by adding a service and a method to the .proto file, so add the following

service MusicService {
   rpc Query(NotesRequest) returns (NotesResponse) {
   }
}

In the last post, I mentioned the NoteResponse was designed for use in the remoting code. Here it’s our return type.

To generate the gRPC code we need to make some additions to our previously defined Pre-Build event. Before we can do that, we need some more tools installed. So using nuget install the following package, Grpc.Tools, while you’re at it, if you’re working with the VS project previously defined, also add the package Grpc.

Now, append the following to the Pre-Build command (formatted to be a little more readable)

--grpc_out $(ProjectDir) 
--plugin=protoc-gen-grpc=$(SolutionDir)packages\Grpc.Tools.1.12.0\tools\windows_x86\grpc_csharp_plugin.exe

In my case, rebuilding my VS solution will result in a new file MusicGrpc.cs which I’ll need to include in the project.

If you’ve created a Console application already, this can act as the server, so you’ll need to create another Console application to be our client. I won’t go through all the steps for adding the files etc. but let’s just jump straight into looking at the server code.

The Server

Add a new class, mine’s MusicServer we derive this from the gRPC generated MusicServiceBase, like this

using System.Threading.Tasks;
using Grpc.Core;
using PutridParrot.Music;

namespace Server
{
    public class MusicServer : MusicService.MusicServiceBase
    {
        public override Task<NotesResponse> Query(
           NotesRequest request, 
           ServerCallContext context)
        {
            if (request.Key == Note.C)
            {
                return Task.FromResult(new NotesResponse
                {
                    Name = request.Name,
                    Key = request.Key,
                    Notes =
                    {
                        Note.C, Note.E, Note.G
                    }
                });
            }
            return base.Query(request, context);
        }
    }
}

Obviously the functionality here is rather limited, but you get the idea, the Query method was generated for us by protoc, and we simply supply our implementation.

To run up the server, we change our Main method to look like this

var server = new Grpc.Core.Server
{
   Services = 
   {
      MusicService.BindService(new MusicServer())
   },
   Ports = 
   { 
      new ServerPort("127.0.0.1", 
         50051, 
         ServerCredentials.Insecure)
   }
};

server.Start();

Console.ReadKey();
server.ShutdownAsync().Wait();

This is pretty self-explanatory, we supply the Server with the Services and the ports, then start the server.

The Client

The client code looks like this

var channel = new Channel(
   "127.0.0.1:50051", 
   ChannelCredentials.Insecure);

var client = new MusicService.MusicServiceClient(channel);

var request = new NotesRequest
{
   Key = Note.C,
   Name = "Major"
};

var response = client.Query(request);

// output the results
foreach (var note in response.Notes)
{
   Console.WriteLine(note);
}
      
channel.ShutdownAsync().Wait();

As you can see, we create a Channel which is the equivalent of a socket connection, passing in the and port information.

Next we create an instance of the MusicServiceClient which was generated by protoc for us. Everything else is as you’d expect, we create our request object call our rpc method passing in the request and a response object is returned.

Code available here https://github.com/putridparrot/blog-projects/tree/master/ProtocolBuffers/CSharp

Using Protocol Buffers

I’ve written once before about using protocol buffers, using the protobuf-net library, but I didn’t go into any depth regarding the .proto file which is used for the IDL. Let’s rectify this.

Introduction

Protocol buffers are simply a way to define a “language-neutral, “platform-neutral, extensible mechanism for serializing structed data”. What this really means is this is a specification (and tooling) for creating binary data. This data might exist as files or streamed over HTTP or any other type of stream. Think of Protocol Buffers as CSV, XML or the likes, but obviously being binary these resultant streams would generally be more compact than these other formats.

Proto file format

I’m not going to cover the .proto syntax in full as it’s already available at Language Guide (proto3), but as I build up an example .proto file I will cover the pieces that I add to the file as I go.

We’re going to want to create a .proto file which we be used to declare our messages/data. Currently the latest syntax supported is “proto3” and we declare the version we support in our .proto file. If you do not specify the syntax, currently this syntax will default to proto2 syntax.

So first off create a file with the .proto extension – I’m doing this within Visual Studio which supports Protocol Buffer syntax highlighting etc.

To declare the supported syntax we start off by adding the following line (I’m going to use proto3 syntax in the post, there are several differences between proto3 and proto2)

syntax = "proto3";

Packages/Namespaces

Whilst it’s optional, the next thing we’ll add is a package which, whilst optional, is useful for code generation in your preferred language. For example in Java this maps directly to the Java package name and in C# and C++ this maps to the namespace of the code.

We can actually override the package/namespace name for Java and C# by using option java_package and/or option csharp_namespace instead or as well as the package line. Obviously we might wish to have all three in our .proto file so the file can be used to generate for Ruby, Go, C++ etc. as well as explicit definitions of Java and C#

So let’s add a package

package music;

option java_package = "com.putridparrot.music";
option csharp_namespace = "PutridParrot.Music";

Types

Scalar types are supported, such as double, float, int32, int64 etc. along with the string type.

Enum’s are all supported, so let’s add an enum to our file

/*
 Note definitions, where two letters are used,
 the first denotes the # (sharp) and the second 
 the b (flat)
*/
enum Note {
   C = 0;
   CD = 1;
   D = 2;
   DE = 3;
   E = 4;
   F = 5;
   FG = 6;
   G = 7;
   GA = 8;
   A = 9;
   AB = 10;
   B = 11;
}

We need to define the possible values for the enum and these must have a zero element. This obviously gives us a default value (hence zero should be your enum default value).

We’ve also added a multi-line comment using /* */ syntax, single line comments using // are also supported.

A message type can be viewed as a composite type, such as structs, i.e. we can combine types, so let’s create a request and response type (the response will be used in my next post on gRPC)

message NotesRequest {
   Note key = 1;
   string name = 2;
}

message NotesResponse {
   Note key = 1;
   string name = 2;
   repeated Note notes = 3;
}

Notice the use of = 1 etc. these are field numbers and each field must have a unique field number.

As per the Google documentation, fields in the range 1 through 15 take one byte to encode, fields 16 through to 2047 take two bytes. So yes, you could have up to 2047 fields in a message, if you really wanted.

Notice in the NotesResponse message we define a repeated keyword which denotes this field can be repeated, think of this like an array (or list) field.

Code Generation

One of the key things XML gave developers was a specification which allow developers to write tools for generating code from the data specifications. Protocol Buffers is no different and ofcourse, this makes such specification more usable to the developer.

The tool we use is protoc.exe. If you’re using Visual Studio/nuget you can install Google.Protobuf.Tools via nuget. This will then be installed to ${SolutionDir)packages\Google.Protobuf.Tools.3.6.0\tools\windows_x86 (or whichever OS you’re supporting).

Now we can run this tool from nant, or other build tools, or as a pre-build event, i.e. selecting your project in Visual Studio, right mouse clicking, selecting Properties then Build Events.

Here’s an example command (formatted to make it readable)

$(SolutionDir)packages\Google.Protobuf.Tools.3.6.0\tools\windows_x86\protoc.exe 
$(ProjectDir)Proto\music.proto 
-I=$(ProjectDir)Proto 
--csharp_out=$(ProjectDir)

The first line is obviously the location of the installed protoc.exe. Next up we declare where the proto file(s) is/are. We can use wildcard, i.e. *.proto, but if we have several different location for the files we will probably need to run the command multiple times.

The -I= allows us to define import directories. This isn’t really needed in the example here as we’re not importing anything. Finally we declare that we want to generate C# code into the project folder.

Note: If you want to generate the code into another folder you’ll need to ensure it already exists, protoc will not create it for you.

Once run, this command will create a C# file which will include the types/messages as well as serialization/deserialization code.

If you’re using Visual Studio to create an application which uses Protocol Buffers, then you’ll need to install the nuget package Google.Protobuf to install the library that the generated source references.

Serializing/Deserializing

Let’s create a Visual Studio Console application, in the project folder add a Proto folder (which will contain our *.proto) files. Now, added the two nuget packages (previously mentioned, Google.Protobuf.Tools and Google.Protobuf).

Next, create a file in the Proto folder named music.proto which should look like this

syntax = "proto3";

package music;

option java_package = "com.putridparrot.music";
option csharp_namespace = "PutridParrot.Music";

/*
 Note definitions, where two letters are used,
 the first denotes the # (sharp) and the second 
 the b (flat)
*/
enum Note {
   C = 0;
   CD = 1;
   D = 2;
   DE = 3;
   E = 4;
   F = 5;
   FG = 6;
   G = 7;
   GA = 8;
   A = 9;
   AB = 10;
   B = 11;
}

message NotesRequest {
   Note key = 1;
   string name = 2;
}

message NotesResponse {
	Note key = 1;
	string name = 2;
	repeated Note notes = 3;
} 

Next, add to the Pre-Build event for the solution the command line (listed previously) to generate the C# from the .proto file.

Lastly, let’s just add the following using clauses to Program.cs

using PutridParrot.Music;
using Google.Protobuf;

and here’s the code to place in Main

var request = new NotesRequest
{
   Key = Note.C,
   Name = "Major"
};

using (var w = File.Create(@"C:\Data\request.dat"))
{
   request.WriteTo(w);
}

NotesRequest request2;
using (var r = File.OpenRead(@"C:\Data\request.dat"))
{
   request2 = NotesRequest.Parser.ParseFrom(r);
}

This will create a file request.dat with the request instance data and then, if all goes well, load the contents of the file into the request2 variable and that’s all there is to it.

We can stream the object using the WriteTo and ParseForm methods but Protocol Buffers also supports gRPC which we’ll look at in the next post.

Code available here https://github.com/putridparrot/blog-projects/tree/master/ProtocolBuffers/CSharp

It’s been a long time JDBC…

As I’m working in Java again. I’m having to reacquaint myself with various Java lanaguge features and libraries.

It’s been a long time since I’ve had to use JDBC, but here’s a snippet of code to demonstrate a accessing an Oracle LDAP datasource.

// import java.sql.*;

Properties connectionProps = new Properties();
connectionProps.put("user", "YOUR_USER_NAME");
connectionProps.put("password", "YOUR_PASSWORD");

Connection conn = DriverManager.getConnection(
   "jdbc:oracle:thin:@ldap://SOME_URL:SOME_PORT/,cn=OracleContext,dc=putridparrot,dc=com",
                    connectionProps);

Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery("select id, blob from SOME_TABLE");

while(rs.next()) {
   String id = rs.getString(1);
   String blob = rs.getString(2);
   // do something with the results
}

Where to store your application data?

Actually I don’t intend to answer the question “Where to store your application data?” because this will depend on your requirements, but what this post will look at is, some of the options available and hopefully help shed light on what best suits your application.

Application data can be separated into two types, user specific data and application specific data (or if you prefer “All User” data).

Obviously multiple user’s might have access to a single machine but an application may be available to all users of a machine, hence we need a way to store settings specific to each user on the machine, for example user preferences. However we also may have application specific data, maybe the application stores a list of URL’s specific, in essence global settings.

Let’s look at some of our options for storing data…

Within your application’s folder

Obviously we could simply store configuration data etc. along with the application, one way to locate this folder is, as follows

var folder = Path.GetDirectoryName(
   Assembly.GetExecutingAssembly().Location) +
   Path.DirectorySeparatorChar + 
   SettingsFileName;

Here we might store a file for application specific data then create another file using the username (here we can use the Environment.UserName) of the user logged into the machine for each user.

This is a simple solution and in some cases more than adequate, plus it has the benefit that if we delete the application (i.e. it wasn’t installed via an installer) then we delete any configuration files.

Program Data

The ProgramData folder is on the system drive and is hidden by default (see C:\ProgramData). As can be inferred from the name, it’s generally used for settings specific to the application itself, i.e. not based upon specific users on a machine.

We can access it using the following code

var folder = Path.Combine(
   Environment.GetFolderPath(
      Environment.SpecialFolder.CommonApplicationData),
      "YourAppName");

Interestingly you can access the ProgramData using C:\Users\AllUsers in File Explorer, although File Explorer will state that you are in C:\Users\AllUsers it’s the same folder as C:\ProgramData.

Program Data can also be located using the environment variable %programdata%.

User Data

So we’ve seen that we can use the Environment.UserName to combine with our file name to create user files, but Windows already has the capability locations for user data. Plus, depending how your OS is set up, this data may be used across any machine a user logs into (known as Roaming).

The default location for the following “User Data” folders is under the location C:\Users\<username>\AppData

Local

The Local folder can be located using the special folder LocalApplicationData, for example

var folder = Path.Combine(
   Environment.GetFolderPath(
      Environment.SpecialFolder.LocalApplicationData),
      "YourAppName");

and is also available via the environment variable %localappdata%.

This location contains data that cannot be stored in the Roaming folder, for example data that’s specific to the machine the user is logged into or that is too large to store in a synchronized roaming folder (i.e. where Roaming folders are synchronized with a server).

Roaming

As hinted at in the section on the Local folder. The Roaming folder can be synchronized with a server, i.e. this is a profile which is accessible from other machines that a user logs into on the same domain. Hence anything stored here will “follow” the user around and so is very useful for preferences, favourites etc. However the space available may be limited depending upon quota settings or other space limitations.

To access this folder we simply use the ApplicationData special folder or environment variable %appdata%, for example

var folder = Path.Combine(
   Environment.GetFolderPath(
      Environment.SpecialFolder.ApplicationData),
      "YourAppName");

LocalLow

The LocalLow folder is basically a restricted version of the Local folder. The data is not synchronized with a server and hence does not move from the machine its created on and it has a lower level of access.

When I say “restricted” or “lower level access” basically this means the application being run, itself has security constraints placed upon it.

The LocalLow folder does not have an entry within the SpecialFolder enumeration, so access the folder you need to use the following (copied from Thomans Levesque’s answer on StackOverflow – https://stackoverflow.com/questions/4494290/detect-the-location-of-appdata-locallow)

[DllImport("shell32.dll")]
static extern int SHGetKnownFolderPath(
   [MarshalAs(UnmanagedType.LPStruct)] Guid rfid, 
   uint dwFlags, 
   IntPtr hToken, 
   out IntPtr pszPath);

public static string GetFolderLocalLow()
{
   var pszPath = IntPtr.Zero;
   try
   {
      var hr = SHGetKnownFolderPath(folderGuid, 0, IntPtr.Zero, out pszPath);
      if (hr < 0)
      {
         throw Marshal.GetExceptionForHR(hr);
      }
      return Marshal.PtrToStringAuto(pszPath);
   }
   finally
   {
      if (pszPath != IntPtr.Zero)
      {
         Marshal.FreeCoTaskMem(pszPath);
      }
   }
}

Accessing location via the environment variables

In a few places I’ve shown the environment variable for each of the locations mentioned. We can also use these variables to locate the folders, for example

var location = 
   Environment.ExpandEnvironmentVariables("%AppData%")

This will result in returning the Roaming folder location, but what’s nice is this static method will work with environment variables combined with file locations (as you’d probably expect), so for example

var location = 
   Environment.ExpandEnvironmentVariables("%AppData%\MyApp")

This will return a path along the lines C:\Users\<username>\AppData\Roaming\MyApp

Source added to https://github.com/putridparrot/blog-projects/tree/master/FileLocations

The WPF Hyperlink

WPF comes with a HyperLink class, but it’s from the System.Windows.Documents namespace, so is mean’t to be embedded within a textual control, such as a TextBlock (i.e. it’s not a standalone control like the System.Windows.Forms.LinkLabel) and within WPF it doesn’t support opening the supplied Uri in an associated process.

Let’s see it’s usage in some XAML

<TextBlock>
   <Hyperlink NavigateUri="http://putridparrot.com/blog/the-wpf-hyperlink">
   The WPF Hyperlink
   </Hyperlink>
</TextBlock>

This XAML will display a the text “The WPF Hyperlink” with underline and when you move your mouse over the link it’ll change colour and the mouse cursor will change to the hand cursor, but clicking on the link will not result in any web browser (or other associated application opening). We must implement such functionality ourselves either responding to the Click event or supplying an ICommand to the Command property.

Here’s a simple example of the sort of code we’d use to running the Uri via it’s associated application.

var process = new Process
{
   StartInfo = new ProcessStartInfo(Uri)
};
process.Start();

We can use databinding to supply the NavigateUri in the standard way, but if you wanted to change the displayed text, then we need to embed another control into the Hyperlink. For example, here we’re using another class from the System.Windows.Documents namespace, the Run class

<TextBlock>
   <Hyperlink NavigateUri="{Binding Uri}">
      <Run>
         <Run.Text>
            <Binding Path="DisplayText"/>
         </Run.Text>
      </Run>
   </Hyperlink>
</TextBlock>

Turning XAML into objects using XamlReader

I couldn’t come up with a good title for this post, basically the post is about taking a XAML declared Style and finding the easiest way to turn this into a Style object in code.

I had a problem whereby I ended up with multiple style objects which were exactly the same except for the DataItem they were binding to. This ended up meaning I had lots of duplicate XAML code, apart from one difference. Once I started making the code more dynamic (it was adding columns to the Infragistics XamDataGrid) this XAML became almost useless as I needed to create a style for each dynamically added column and hence really need to generate the Style in code.

If you’ve done anything much with code behind for such things as creating Style objects or replicating XAML code you’ve probably found the code doesn’t always map directly to the XAML, and if you already have XAML that works, why not simply reused it.

Note: The reason the code doesn’t always map is that it includes resources, converters and other XAML magically things that are automatically applied, for example converting colour names to colour values, or field lengths etc.

So let’s simple copy our XAML into a string in code and then programmatically change the DataItem field and then generate our Style object from this.

Here’s an example of the XAML as a string

var styleString = 
   "<Style TargetType=\"{x:Type idp:CellValuePresenter}\">" +
   "<Setter Property=\"Template\">" +
   "<Setter.Value>" +
   "<ControlTemplate>" +
   "<Grid>" +
   "<ListBox ItemsSource=\"{Binding DataItem." + source + "}\">" +
   "<ListBox.ItemTemplate>" +
   "<DataTemplate>" +
   "<TextBlock HorizontalAlignment=\"Stretch\" Text=\"{Binding}\"/>" +
   "</DataTemplate>" +
   "</ListBox.ItemTemplate>" +
   "<ListBox.ItemsPanel>" +
   "<ItemsPanelTemplate>" +
   "<StackPanel Orientation=\"Vertical\"/>" +
   "</ItemsPanelTemplate>" +
   "</ListBox.ItemsPanel>" +
   "</ListBox>" +
   "</Grid>" +
   "</ControlTemplate>" +
   "</Setter.Value>" +
   "</Setter>" +
   "</Style>";

In the above we’d obviously supply the source variable and this will then form part of our XAML style. To turn this into a Style object we need to use the XamlReader.Parse method. Before we can use the XamlReader.Parse method we also need to create the namespaces (context items) that we would expect from our XAML code, in this case we create a ParseContent object and assign our namespaces, then pass this into the XamlReader.Parse method also with the styleString. Our code might look like the following

public Style CreateStyle(string source)
{
   var context = new ParserContext();
   context.XmlnsDictionary.Add
   ("", 
    "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
   context.XmlnsDictionary.Add
   ("x", 
    "http://schemas.microsoft.com/winfx/2006/xaml");

   // other namespaces for XamaDataGrid etc.

   var styleString = 
      "<Style TargetType=\"{x:Type dataPresenter:CellValuePresenter}\">" +
      "<Setter Property=\"Template\">" +
      "<Setter.Value>" +
      "<ControlTemplate>" +
      "<Grid>" +
      "<ListBox ItemsSource=\"{Binding DataItem." + source + "}\">" +
      "<ListBox.ItemTemplate>" +
      "<DataTemplate>" +
      "<TextBlock HorizontalAlignment=\"Stretch\" Text=\"{Binding}\"/>" +
      "</DataTemplate>" +
      "</ListBox.ItemTemplate>" +
      "<ListBox.ItemsPanel>" +
      "<ItemsPanelTemplate>" +
      "<StackPanel Orientation=\"Vertical\"/>" +
      "</ItemsPanelTemplate>" +
      "</ListBox.ItemsPanel>" +
      "</ListBox>" +
      "</Grid>" +
      "</ControlTemplate>" +
      "</Setter.Value>" +
      "</Setter>" +
      "</Style>";

   return (Style)XamlReader.Parse(styleString, context);
}

That’s it – much simpler that create each piece of the Style using C# objects and allows us to first test our XAML out then reused it to generate our objects in code.

Note: If your code relied on namespaces/assemblies which are not already loaded you will have to load them into memory yourself before they can be used in this way.

Xamarin Forms (>= 3.0) supports CSS

In my previous post Styles in Xamarin Forms I demonstrated creating a simple styles using XAML Style objects. However, as of version 3.0 of Xamarin Forms, you can also use CSS (Cascading Style Sheet) files/syntax to define your styles.

XAML Style is quite a verbose way of defining styles but if you’re used to WPF or UWP it’s probably something you’re quite happy with. If, however, you come from a web background you’ll probably be used to CSS files instead. Now you can use similar syntax to define your styles for Xamarin Forms (3.0 or above).

If you create a standard mobile application in Visual Studio you’ll get a simple ContentPage based application – as per the previous post we’re going to start off by simply defining a Lime green background for our ContentPage’s.

Now simply add a CSS file (mine’s named Styles.css) to your solution and set it’s Build Action to Embedded resource and place the following into the file

^ContentPage {
     background-color: Lime;
}

Note: the CSS is case insensitive, but I’ve stuck to using the case associated with the controls/page here.

Notice the use of the ^ followed by the base type. If you read my previous post Styles in Xamarin Forms, you’ll notice that this is equivalent to an implicit style. i.e. it’s applied to anything of the type ContentPage.

To use this style we need to add the following to our ContentPage XAML

<ContentPage.Resources>
   <StyleSheet Source="Styles.css" />
</ContentPage.Resources>

Note: you do NOT need to add any namespace to use the StyleSheet (or at least I didn’t at the time of writing). if Visual Studio or Resharper suggests you need to add a namespace, just ignore it.

Now if you run your application you’ll be presented with the Lime background ContentPage.

If you’re used to CSS you’ll know that you can also declare an id (the equivalent of an explicit style) to your CSS. Let’s change our CSS to this following

#ContentStyle {
     background-color: Lime;
 }

Now we can assign this to either the StyleId or it will fallback to using x:Name (if no StyleId is set) on our control. For example

StyleId="ContentStyle"

or if you prefer you can simply use the x:Name (remember no StyleId should exist)

x:Name="ContentStyle"

We can also declare our CSS using CLASS selectors such as

.ContentStyle {
     background-color: Lime;
}

Now we would use the StyleClass attribute on our ContentPage instead of StyleId or x:Name, i.e.

StyleClass="ContentStyle"

Finally, we can also declare CSS for child elements, so for example CSS for the Label which is a child of a StackLayout would look like this

StackLayout Label {
    background-color: Lime;
}

See Selector reference for more on selector syntax, which also demonstrated setting style for direct child objects etc.

References

Styling Xamarin.Forms apps using Cascading Style Sheets (CSS)
Styling Xamarin.Forms Apps with CSS