├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── comparisons ├── maui-default-page.md ├── maui-sample-page.md ├── readme.md ├── winui-new-window.md └── wpf-new-window.md ├── enamel-tease.gif └── slides ├── 00_the-basics.png ├── 01_root-elements.png ├── 02_optional-braces.png ├── 03_properties.png ├── 04_properties2.png ├── 05_default-properties.png ├── 06_multi-properties.png ├── 07_default-markuExtension.png ├── 08_comments.png ├── 09_substitutions.png ├── 10_expansions-dotattributes.png ├── 11_for-loops.png ├── 12_foreach-loops.png ├── 13_autogrids.png ├── 14_inlinecsharp.png └── readme.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: MRLacey # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: ["https://paypal.me/mrlaceydev"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Matt Lacey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ENAMEL - An RFC for possible future XAML-based development 2 | 3 | ## Executive Summary / TLDR 4 | 5 | A new, simplified markup language to define application UI. The new files automatically generate comparable XAML files for your WPF, .NET MAUI, or WinUI app which is then compiled as normal. Fully configurable, totally optional (use it for some or all XAML files) and low risk as the XAML (and C#) files are still available. 6 | 7 | It addresses the common complaints about having to work with XAML and adds new functionality without the need to change any of the existing tooling. 8 | 9 | How much less verbose is it? 10 | 11 | Well, this is the XAML for an Empty page in a .NET MAUI app. 12 | 13 | ```xml 14 | 15 | 19 | 20 | ``` 21 | 22 | And this is the exact same thing in ENAMEL. 23 | 24 | ```enamel 25 | ContentPage 26 | ``` 27 | 28 | _There are more examples comparing XAML and ENAMEL [here](./comparisons/)_ 29 | 30 | ENAMEL: Simple, human readable, and easily maintainable UI markup. 31 | 32 | ## Introduction 33 | 34 | For many developers, XAML (eXtensible Application Markup Language) is seen as verbose, hard to read, and difficult to work with. There are others who describe it a "fine" or "adequate". 35 | For both groups, that there has been no significant update to XAML since its launch, almost twenty years ago, highlights that it is overdue to consider what improvements or enhancements may be appropriate. 36 | 37 | That XAML has existed for so long without the necessity for change can be considered a positive for the language as it shows reliability, stability, and the strengths of the original design. 38 | However, lots has changed in that time. Requirements, expectations, and what's possible, practical, & desirable have all evolved. Developers want, need and expect the tools and languages they use to improve over time. If they don't, when considered alongside alternatives, the tools can easily be perceived as getting worse. 39 | 40 | XAML can be written in ways that follow conventions, patterns, and "best practices" of other programming languages to greatly improve the readability and maintainability of the code. (Such as [demonstrated in this workshop](https://github.com/dotnet-presentations/dotnet-maui-workshop/tree/main/Community%20Modules/XAML).) But this still more to read than is necessary for the person wanting to understand the intent and important details in the code. 41 | 42 | This RFC was driven by a desire to ask "What could be done to improve the code used to declare a GUI interface if it wasn't limited by historic choices and restrictions of XML-based markup?" If the desire is to build "modern apps", using a twenty-year-old technology (a lifetime in tech terms) at least deserves to be questioned. 43 | 44 | This is not an attempt to persuade anyone happy with the XAML they write or the alternative they use to switch from what they are currently being productive with. Use what works for you. 45 | However, for many people currently using XAML, there is an implicit understanding, or expectation, that things could be better. This RFC explores one possible solution. 46 | 47 | ## Why changing XAML is hard 48 | 49 | Changing XAML is hard. Modifications risk breaking existing code and tooling. 50 | 51 | A complete replacement would make some people think that they need to rewrite everything they currently have or be stuck on a legacy technology that would fail to get further updates. The plethora of options for building native Windows apps (many of which use XAML) already creates this feeling in many. Any solution should not look to extend this uncertainty. Similarly, .NET MAUI is growing steadily after the conversion from Xamarin.Forms. It would not be desirable to create confusion amongst users and those considering it after such a big, recent change. 52 | 53 | An additional (official) option for defining UIs would also increase the total support overhead as XAML would still need to be supported for many years to come. 54 | 55 | Variants of XAML are used by multiple frameworks and project types. These include (but are not limited to) WPF, .NET MAUI, and WinUI. Ideally, any change or alternative to XAML should not be limited to only one of these. 56 | 57 | Creating a new, alternative language and integrating it with the tooling (IDEs, compilers, CI/CD systems) and the frameworks where it is used, has the potential to be a large amount of complex work. This risks prohibiting the number of possible alternatives that can be tried and the number of people with the skills to create such experiments. It's in no one's interest to take a lot of time (and/or spend a lot of money) on an experiment that may not turn into an actual product. 58 | 59 | Trying new languages can be risky. 60 | Trivial demos rarely give a true impression of what a language is like to build "real" applications with. Completely rewriting an existing app can be time-consuming. Building something entirely new presents potential maintenance issues if the new app is wanted but the technology used to build it is not fully adopted. 61 | 62 | Learning a new language can be hard and teaching/training can be expensive. 63 | 64 | ## A new language as a possible solution 65 | 66 | ENAMEL (**E**xperimental **N**ative **A**pplication **M**arkup **E**xtension **L**anguage) is a new proposed language that avoids and addresses the challenges mentioned above. 67 | 68 | It primarily addresses the above concerns by providing a way of creating valid XAML files that are then used by the existing tooling. 69 | 70 | 1. Write ENAMEL (in a `.enml` file) 71 | 2. When the file is saved, it automatically generates a corresponding `.xaml` file. 72 | 3. The generated XAML files (and accompanying code-behind) are used as if written by hand. 73 | 74 | The tooling to build the app ignores the new files it doesn't know about and Visual Studio's built-in capabilities to nest files means that the solution doesn't become cluttered. 75 | 76 | It's fully optional. 77 | As the tools to build an app don't need the ENAMEL files it doesn't matter if they exist for some, none, or all the XAML files. This allows for incremental adoption as there's no need to rewrite all UI files at once in a new language. Additionally the risks of experimentation are also removed as if tried but not-ultimately adopted, the project still contains all the XAML it needs to keep on working. 78 | It's also optional in the sense that anyone happy with XAML as it currently is, is free to keep using it as they currently do. Additionally, any improvements to XAML or changes to the toolchain would benefit the people using XAML and any new solution that generates it. 79 | 80 | It relies on a simple but powerful ruleset that is explained in detail below. By having such a small and specific set of rules it is easy to learn. These rules and syntax are also optimized for human readability, rather than the rigorous structure of something (XML) initially intended for reading and writing by machines. 81 | 82 | In addition to producing XAML, ENAMEL also accepts XAML as valid input. Not only does this make migrating XAML to ENAMEL a trivial process, it also makes it easy to explore how it works with more complex examples in existing codebases. 83 | An additional benefit of supporting "inline XAML" within an ENAMEL file is that it offers a fallback option for any particular elements that ENAMEL does not support or someone chooses not to convert. 84 | 85 | It's not magic, it's just source generation. Source generation is increasingly used and accepted in .NET and other technology stacks. This proposed solution may be well timed to be accepted based on the widespread adoption of source generated C# code elsewhere in project that would use this. 86 | 87 | By continuing to use the existing tool chains, ENAMEL has no direct dependency on or connection to any other technology. It could just as easily produce XAML files for use in WPF, WinUI, .NET MAUI, or anything else. 88 | 89 | It is intended to be highly configurable. This enables the flexibility to support any dialect of XAML, and it also enables optimizations based on preferred ways of working and personal preferences. 90 | All configurable settings are also optional. 91 | 92 | The simplicity of the language and the way of avoiding the need to modify existing toolchains means that experiments as to the suitability of this as a solution can be done quickly and cheaply. An initial proof-of-concept with basic Visual Studio integration was created in just two days. 93 | 94 | A new language that produces XAML does not have the same constraints as XAML itself. This makes it simple to add features and functionality that are beneficial but impossible with XAML. 95 | 96 | ## Language goals 97 | 98 | The design of the ENAMEL language has been guided by these principles: 99 | 100 | - Be logically comparable with equivalent XAML. 101 | - Avoid duplication and repetition. 102 | - Aim for brevity AND clarity in the code. 103 | - Prefer words over symbols and punctuation. 104 | - Avoid adding keywords unless they offer clear and significant benefits. 105 | 106 | The intention is to create something that anyone unfamiliar with the language would find easily understandable. 107 | 108 | ## Language rules 109 | 110 | The language is defined by a small set of rules that are also very powerful. 111 | 112 | ### Basic rules 113 | 114 | As the purpose is to create a XAML file that describes a "UI tree", an ENAMEL file also adopts a tree like structure that is representative of the `Elements` that may also have `Attributes` specified and zero or more children. 115 | 116 | #### Elements and child-elements 117 | 118 | The following rules define how to specify an Element in ENAMEL. 119 | 120 | - Elements are specified by their name only. No brackets (angled or otherwise.) 121 | - Each element starts on a different line. 122 | - Child elements are indented from their parents. 123 | - Siblings are always indented the same amount. 124 | - Indenting can be any size (and use tabs, spaces, or both), but must be consistent among siblings. 125 | - Blank lines (or containing only whitespace) _may_ be used to separate elements. These are not included in the generated output. 126 | 127 | The following (partial) example uses elements (Types) from .NET MAUI but should be clear to all. 128 | 129 | ```ascii 130 | Page 131 | VerticalStackLayout 132 | Label 133 | 134 | CollectionView 135 | ``` 136 | 137 | - Child elements may optionally be surrounded by curly braces (`{` & `}`). If used, the opening brace should be on the end of the line containing the element opening. The closing brace should be on its own line and may be indented if desired. 138 | - Curly braces can be nested as appropriate. 139 | 140 | While neither are particularly useful, the following example is functionally equivalent to the one above. 141 | 142 | ```ascii 143 | Page { 144 | VerticalStackLayout { 145 | Label 146 | 147 | CollectionView 148 | } 149 | } 150 | ``` 151 | 152 | - XAML elements (anything inside matching angle brackets) are assumed to be valid XAML and are output directly as input. 153 | 154 | Again, this example will produce the same output as above. 155 | 156 | ```ascii 157 | Page 158 | VerticalStackLayout 159 |