Pattern-Based XML Literals Prototype: Cross-Platform Mobile Apps w/ Xamarin.Forms

In my last post I introduced the idea of pattern-based XML literals—XML literals which construct arbitrary types other than XDocument/XElement/XAttribute/etc. And as promised, I have recorded a video showing off the practical benefits of this design when using Xamarin.Forms from VB.NET. If you’re not familiar with Xamarin.Forms it’s an API that abstracts over the differences between mobile platforms like Android and iOS to make it easier to create and maintain cross-platform apps while sharing the maximum amount of code. Watch as I explore the Xamarin VB sample app from the official Xamarin samples repo using this new prototype:

As you can see, it’s pretty empowering to be able to use XAML everywhere.

  • I can leverage my XAML skills from WPF to a degree and be more productive.
  • If I’m looking at the documentation or a sample or blog post (most likely written from a C# developer) that uses XAML, I can use that XAML in my code rather than first translating it to VB imperative code.
  • In places where today you’d possibly have to give up markup for code like dynamic view creation, I can still use declarative XAML even if it’s in the middle of a VB method (this scenario comes up in writing VS extensions to the WPF editor too).
  • Even with object initializers there can be situations where you have to fallback to imperative syntax like using attached properties but that’s not an issue using markup.
  • I get to embed any VB expression inside my markup in places where that expressiveness is a benefit over XAML.

WPF XAML vs Xamarin XAML

Xamarin has its own flavor of XAML. It’s essentially the same on the surface (syntactically) as what’s used in WPF and Silverlight (and UWP) but it’s not the same XAML engine and it uses different types internally. Not just in the “Controls” or as Xamarin calls them “Views” but in the infrastructure itself:

  • So rather than DependencyObject and DependencyProperty, Xamarin has BindableObject and BindableProperty.
  • Xamarin has its own base types for type converters, and markup extensions, etc.

So, even though both it and WPF use the XAML syntax (which is XML based), Xamarin.Forms is powered by a completely different engine entirely. Possibly as a consequence of this the XAML used by Xamarin.Forms doesn’t support VB.NET. Which would normally mean you have to create your UI imperatively, rather than declaratively. VB guru Klaus Löffelmann wrote about how to do this back in 2017 on the VB team blog. It was a good post but the no-XAML part was kind of a bummer. This prototype changes all of that!

The Xamarin differences actually highlight another benefit to being pattern-based. Because the language understands patterns—certain methods with certain names and shapes existing—rather than specific types (like DependencyObject) it’s possible to apply the feature to a completely different system than WPF. If the feature were just WPF XAML literals built to understand the specifics of the WPF infrastructure you couldn’t turn around and apply it to Xamarin but by being pattern-based you can do that easily.

Under the hood

As I indicate in the video, the compiler knows XML and how to translate certain idioms in XML into call-outs to extension methods that encapsulate all of the Xamarin-specific knowledge. I’m pretty sure the pattern will change as I explore more but the first page’s code:

Dim page = <ContentPage Title="My First Android App!" BindingContext=<%= Model %>>
<StackLayout VerticalOptions="Center">
<Label
HorizontalTextAlignment="Center"
FontSize="Medium"
Text="Welcome to Xamarin.Forms with Visual Basic .NET!"
/>
<Entry Text="{Binding Name}"/>
<Button Text="Next" Clicked="NextButton_Click"/>
</StackLayout>
</ContentPage>

Translates to this:

' Passing `Nothing` as the first arg of Set<AttributeName> methods indicates
' that the compiler couldn't convert the attribute text to the indicated type
' at compile time. If I had written `FontSize="16"`, that line would read:
' `temp1_1_1.SetFontSize(16.0, "16.0", Nothing)`
' The third argument is the value produced by an embedded expression, if it
' doesn't naturally convert to the first arg type at compile time. If I had
' written `Text=<%= New Binding("Name") %>`, that line would read:
' `temp1_1_2.SetText(Nothing, Nothing, New Binding("Name"))`
Dim temp1 = New ContentPage
temp1.Title = "My First Android App!"
temp1.BindingContext = Model
Dim temp1_1 = New StackLayout
temp1_1.SetVerticalOptions(Nothing, "Center", Nothing)
Dim temp1_1_1 = New Label
temp1_1_1.HorizontalTextAlignment = TextAlignment.Center
temp1_1_1.SetFontSize(Nothing, "Medium", Nothing)
temp1_1_1.Text = "Welcome to Xamarin.Forms with Visual Basic .NET!"
temp1_1.AddChildContent(temp1_1_1)
Dim temp1_1_2 = New Entry
temp1_1_2.SetText(Nothing, "{Binding Name}", Nothing)
temp1_1.AddChildContent(temp1_1_2)
Dim temp1_1_3 = New Button
temp1_1_3.Text = "Next"
AddHandler temp1_1_3.Clicked, AddressOf NextButton_Click
temp1_1.AddChildContent(temp1_1_3)
temp1.SetChildContent(temp1_1)
Dim page = temp1

As you can see, the compiler knows how to translate attribute values to enum members at compile-time. So if I misspell and enum member I’ll get a compile-time error:

Likewise the compiler knows how to translate an attribute value to a delegate creation, so that too gets compile-time validation:

Both of these make it easy to give in-context completion support in the IDE for these cases.

The keen observer may have also noticed that when I selected name CalculateButton in the value of the Name attribute at around the 2:45 mark in the video that references to CalculateButton in code were highlighted. This is another example of the power of Roslyn. Because the compiler binds that text to the CalculateButton variable, the IDE understands it as such and features like Go-to-Definition work automatically!

THIS IS A WORK IN PROGRESS!!!

I accidentally edited out the part where I show what turns a regular XML literal into a pattern based one and it’s a magic "clr-namespace:" XML namespace import at the top of each file (could also be in a project-level import). If I comment out that import you can see that I get conversion errors because the XML reverts to producing an XElement as it does today:

I expect to find a better way to enable the feature though because of some trade-offs with that approach. This is just a draft version of the pattern and I fully expect it to change as I explore other shapes of XML to apply it to and weigh certain experiences that could be built.

For example, right now the pattern respects both a SetChildContent and AddChildContent bridge methods so that the compiler can report an error if you include more than one child element in a situation where only one child is allowed, but maybe it’s better to simplify the pattern and enforce things like that in a Roslyn Analyzer (let me know what you think).

If you’re really curious as to what each of these bridge methods looks like, I’ve uploaded the content of the XmlExtensions.vb file from the sample app I showed in the video as a Gist. It’s just what I wrote out while exploring the pattern and shouldn’t be taken as the “best way” to write such methods and I played around with different approaches. Just take it all with a grain of salt.

Next steps

I know Xamarin.Forms has been around for quite awhile now but honestly I haven’t been as excited to try it out until now. I can see some places where the Xamarin team made extremely reasonable choices in their content model (like how templating works). I’m anxious to see how I can broaden the pattern to work well with those patterns and to just generally explore mobile app development from VB.NET.

Fun Fact: Due to Windows Mobile and Compact Framework and then Windows Phone and Windows 10 Mobile, I have not owned a phone that I couldn’t program in VB.NET in almost 15 years. I’m excited to continue that tradition.

One thing this video didn’t show off was tooling. Because it’s all just the VB.NET language and the IDE is powered by Roslyn, getting things like completion, go-to-definition, F1 help, etc. to work in such XML literals is much easier than it would have been pre-VS2015. Also, there’s this other unrelated prototype I plan to show off… 4-5 prototypes from now that could really improve on both desktop apps using WPF/WinForms and mobile apps using Xamarin too. So whether it’s to show off better tooling, to show off another prototype, or just because I’m having fun exploring Xamarin.Forms I don’t think this will be the last video I make featuring this topic.

As for my next post it’ll be a continuation of this series about this prototype but instead applied to web development. I think you’re going to love it so look out for it.

Until then, as always, thanks for reading, thanks for watching, please share this post, and let me know your thoughts in the comments below and/or on Twitter.

Regards,

-ADG

P.S. As in my last series, I’ll upload all of my notes from implementing the prototype in a GitHub issue after the last post in the series. Don’t sweat the specifics of the pattern too much, they’re subject to and very likely to change. This post took me much longer than intended before the first few iterations of the video were over 30-minutes! It took some re-recording and aggressive editing to get it down to 5.X minutes, but I think that’s optimal for online viewing and sharing. I hope you agree!

“I have made this [letter] longer than usual because I have not had time to make it shorter.”
-Blaise Pascal

5 thoughts on “Pattern-Based XML Literals Prototype: Cross-Platform Mobile Apps w/ Xamarin.Forms

  1. Anthony this is awesome. Truly excited by the prospects here with what you are doing. You’re a true hero of the VB.NET language.

    Everyone knows that the language will become die without support on the platforms (XAMARIN, ASP.NET etc)

    Even Kathleen makes vague comments like “we expect this to continue” with respect to VB.NET support – she can’t even bring herself to state definitely one way or the other if a decision to include VB.NET support has been made. It is true, VB.NET as a LANGUAGE is being developed and support (although slowly and with a directive to keep the language “approachable” (aka DUMB)) but platform support is disappearing, documentation non-existent. project templates, First Class citizen support in AZURE Products (Functions) is never developed. This will kill the language as the platforms we wish to use as developers are no longer easily accessible (or approachable) to VB.NET devs.

    Scepticism will always remain when were told that vb,net would be supported ASP.NET Core only for MS to go quite for 18months before finally admitted they weren’t doing it.

    I can’t help but feel Kathleen’s wrists are tied by an implicit overarching strategy or bias of the .NET team which will ultimately lead to to demise of VB.NET, sentenced to remain only to support Legacy platforms and solutions.

    Like

    • Glad you like it, Aaron. I want to be clear that “approachable” doesn’t mean dumb. I chose the words “straightforward and approachable” rather than “easy” and “simple” to avoid that misconception. The language isn’t simple, the developers aren’t simple, the apps they write aren’t simple. I worked on a compiler/IDE written in VB.NET for 7 years. That compiler is far more straightforward and approachable than the VB.NET compiler written in C++ compiler was. They both do the exact same thing (and in fact the one written in VB.NET does MORE) but /how/ they are designed makes one more approachable for extension than the other and solving problems in one more straightforward than the other.

      All well-designed software products should be approachable. A person who has an interest in that thing should feel like they know where to start and what they’re starting with is quickly comprehensible and gradually expandable. If something throws everything and the kitchen sink at you at once, it’s less approachable. But approachable doesn’t mean that you can’t have a full range of scenarios beyond what’s in your front door. That goes to tooling, to documentation, to samples, to naming conventions, etc. I remember when I was looking at a UWP sample (years ago) I noticed that the sample had like 10 lines of comments for every line of code and every quirky scenario of WinRT development was represented in the first file. That’s *not* approachable. It screams “I’ll do this later, when I have a few hours to spare”.

      If you look at your car, it can be a complex piece of machinery that goes far and goes fast and is loaded with features but the experience of getting in that car can be just as approachable whether it’s a Chevy Cavalier, a Tesla, or a Ferrari. Approachable doesn’t mean VB can’t be a Tesla or a Ferrari, it means it shouldn’t put an extra steering wheel in the back seat in case you’re backing-up and you want a better angle, and a mirrored set of peddles on the floor for left-footed drivers and another set of peddles and a steering wheel in the passenger-side for when drivers from England are visiting, and… a toggle switch that changes it from using a steering wheel to using PlayStation controllers that you have to switch on every time you get into the car because some drivers learned to drive on Gran Turismo, etc.

      There’s a lot I have to write about the subject. I think VB is a very well-designed, straightforward, and approachable language that’s also crazy powerful and flexible and I’ve been using it my whole adult life and I’m still finding corners of it where deepening my skills is rewarding. That’s not “keeping it dumb”, it’s keeping it great!

      Like

  2. Pingback: Pattern-Based XML Literals Prototype: ASP.NET Core Revisited | Anthony's blog

  3. Pingback: Pattern-based XML Literals Prototype: Client-Side VB.NET Running in the Browser (sorta) | Anthony's blog

  4. Pingback: Checking In (Wave 2) | Anthony's blog

Comments are closed.