-
-
Save VincentH-Net/c7568727517c4ef4f622815a580316d9 to your computer and use it in GitHub Desktop.
// C# vNext markup friendly | |
enum Row { Icon, Prompt, Header, Entry } | |
void Build() => Content = new Grid | |
{ | |
RowDefinitions = Rows.Define( | |
(Icon , Auto), | |
(Prompt, Auto), | |
(Header, 50 ), | |
(Entry , Auto) | |
), | |
{ | |
Image { } | |
.Row (Icon) .CenterH () | |
.Bind (vm.Icon), | |
Label { LineBreakMode = WordWrap } | |
.Row (Prompt) .TextCenterH () | |
.Bind (vm.RegistrationPrompt), | |
Label { Text = "CODE" } | |
.Row (Header) .Bottom (), | |
Entry { Placeholder = "123456", Keyboard = Numeric } | |
.Row (Entry) .Margins (left: 10) | |
.Bind (vm.RegistrationCode) | |
} | |
}; | |
// C# 8 | |
void Build() => Content = new Grid | |
{ | |
RowDefinitions = Rows.Define( | |
(Row.Icon , Auto), | |
(Row.Prompt, Auto), | |
(Row.Header, 50 ), | |
(Row.Entry , Auto) | |
), | |
Children = { | |
new Image { } | |
.Row (Row.Icon) .CenterH () | |
.Bind (nameof(vm.Icon)), | |
new Label { LineBreakMode = LineBreakMode.WordWrap } | |
.Row (Row.Prompt) .TextCenterH () | |
.Bind (nameof(vm.RegistrationPrompt)), | |
new Label { Text = "CODE" } | |
.Row (Row.Header) .Bottom (), | |
new Entry { Placeholder = "123456", Keyboard = Keyboard.Numeric } | |
.Row (Row.Entry) .Margins (left: 10) | |
.Bind (nameof(vm.RegistrationCode)) | |
} | |
}; |
Automatic nameof surport has many risks, maybe new type is needed that can pass details of a property that does not have automatic conversion to string.
Nameof can sort-of be eliminated in C# 10 with the [CallerArgumentExpression]
attribute.
Could we reduce repetition in nested object initializers?
(e.g. in a declarative UI markup expression, but useful when new-ing up any tree of objects)
-
Allow to omit
new
in initializers below the tree root.
So havenew
on the root, but not required to repeatnew
for each nested child or content object. -
Allow to indicate a default initialization property for a type (collection or single "content property"),
so that property name can be omitted in an initialization expression. E.g.new Grid { Children = { new Label { }, new Button { } } }
could be like:
new Grid { { new Label { }, new Button { } } }
or even:
new Grid { new Label { }, new Button { } }
and when combined with 1):
new Grid { Label { }, Button { } }
-
Allow to omit the parameter type when passing in a parameter value (SwiftUI uses
.
).
To be used when passing in an enum value or a class static member to a parameter.
(also useful outside expression trees) e.g.Alignment = Alignment.Left
could be:
Alignment = .Left
where
Alignment.Left
is either an enum value or a static class member.
When the . is entered, Intellisense starts just as if the full type name was entered before the .
Codegen versus Language Support
Some of the proposed improvements can be approximated by generating fluent + factory functions.
See these example functions and how they can be used in markup:
But the disadvantages of this codegen workaround are:
( )
instead of in{ }
causes loss of vertical lines between opening and closing character, and also of collapse/expand functionality in the editor.E.g. using static a factory class that contains the factory method
Label()
causes an error when you attempt to reference a static member of that class, e.g.Label.TextColorProperty
.So C# support would not just reduce the development effort and overhead of .NET UI frameworks, but even more importantly it would improve the development experience of everyone using those frameworks with markup in C#. With MAUI, UNO, WinUI and Blazor that is a LOT of developers who could benefit, even if only part of them choose to use C# for markup instead of XAML or HTML.