Closed mdtauk closed 11 months ago
@mdtauk good point, I get hyper-focused sometimes on the .NET side of things from the Toolkit.
Though I think that also shows where XAML itself can shine as it's a well understood and powerful abstraction that doesn't need to tie-itself to the language driving it. 😉
Its mainly the verbosity of XAML, as well as the rigid syntax, and no separation of Styling from UI Layout - that makes it awkward to work with.
@michael-hawker
Having worked with various code based UI frameworks in the past in various languages, the power of XAML is really the ease in which one can copy and paste things around in the XML structure without having to re-work anything. With code, there's a lot of other syntax that gets in the way when trying to move things around, especially when code is needed to direct the relations of UI elements to one another as well.
Could you give/point to some example XAML and indicate a part that would be harder to move around if it were coded UI? I'm wondering if your experience is due to imperative coded UI versus declarative (like CSharpForMarkup). I'd like to try out an example and improve CSharpForMarkup if possible.
@VincentH-Net I really like the approach you take with CSharpForMarkup.
I am currently working on a huge new version of ReduxSimple, with simplified reducers, sub-reducers, rewritten selectors, effects and routing.
I would like to use your library in the samples of ReduxSimple because it can be a perfect match to combine a Redux architecture and a Functional UI framework. The thing is that I started my first sample app with UWP (before WPF and Xamarin) because I needed to start somewhere obviously. :) Do you think CSharpForMarkup can work with UWP?
@Odonno Glad to hear you like it!
Do you think CSharpForMarkup can work with UWP?
Yes, the approach I took with CSharpForMarkup for Xamarin Forms can be applied to any .NET UI framework that uses data binding.
Since CSharpForMarkup is just a thin set of helper functions directly on top of the UI framework, you could effectively create a close lookalike of these helpers for UWP. Some helpers for Forms are specific but most will have a close equivalent on UWP.
You're welcome to do a PR to add a UWP port on CSharpForMarkup :-) Simply copy XamarinFormsMarkupExtensions.cs to UwpMarkupExtensions.cs and refactor it to UWP.
You might want to consider porting your UWP sample to UNO since that virtually is 1 on 1 compatible with UWP. Now that is a PR I'd really love to see :-)
@VincentH-Net Good to know. I'll give a look at it once the 3.0 of ReduxSimple is finished.
UI defined in code can achieve the following now:
For example we can already write:
// in a ViewModel
let text = Mutable.create ""
let capitalizedText = text |> Signal.map (fun s -> s.ToUpper())
let add() = text.Value <- text.Value + "a"
// in a View
let label = Label()
capitalizedText.bind label.set_Text
StackLayout(
Views = [
label
Button(Text = "+A", Click = add)
]
)
Useful future tooling:
type FooLabel(bar:string) =
inherit Label(Text = "foo"+bar)
[<Preview>] // only used for live preview tooling
static member Sample = FooLabel("bar")
I like QML & Razor synax:
@UserControl
@Class ControlCatalog.Pages.ButtonPage
@Using System.Drawing
StackPanel {
Orientation:"Vertical"
Spacing:"4"
TextBlock{Classes:"h1" Text:"Button"}
TextBlock{Classes:"h2" Text:"A button control"}
StackPanel{
Orientation:"Horizontal"
Margin:"0,16,0,0"
HorizontalAlignment:"Center"
Spacing:"16"
StackPanel{
Orientation:"Vertical" Spacing:"8" Width:"150"
Button{Text: "Button"}
Button{Foreground:"White" Text:"Foreground"}
Button{Background:"@ThemeAccentBrush" Text:"Background"}
Button{IsEnabled:"False" Text:"Disabled"}
Button{
Text:"Re-themed"
Style.Resources {
SolidColorBrush {ThemeBorderMidBrush:"Red"}
SolidColorBrush {ThemeControlHighBrush:"DarkRed"}
}
}
}
StackPanel{
Orientation:"Vertical" Spacing:"8" Width:"150"
Button {BorderThickness:"0" Text:"No Border"}
Button {BorderBrush:"@ThemeAccentBrush" Text:"Border Color"}
Button {BorderBrush:"@ThemeAccentBrush" BorderThickness:"4" Text:"Thick Border"}
Button {BorderBrush:"@ThemeAccentBrush" BorderThickness:"4" IsEnabled:"False" Text:"Disabled"}
}
}
}
And QML binding syntax:
SliderBar { Id=“sld” Min=0 Max=100}
TextBlock { Text: sld.Value }
The grammar of QML is well refined, just liking poem. QML has several advantages:
The first 3 items can be adopted. By the way, the file extension may be ".csml", It means "csharp markup language". :)
I think the specialty of UI frameworks like SwiftUI and Jetpack Compose is putting logical operations like if conditions and loops while defining UI code. Swift and Kotlin has some language features, that makes this possible. This will be hard to do in C#.
@gulshan said:
I think the specialty of UI frameworks like SwiftUI and Jetpack Compose is putting logical operations like if conditions and loops while defining UI code. Swift and Kotlin has some language features, that makes this possible. This will be hard to do in C#.
Actually, it's not that hard. #CSharpForMarkup is now built-in in Xamarin Forms as the C# Markup feature, and makes it easy to combine declarative and procedural buildup of markup. It is currently in the 4.6 prerelease NuGet. The documentation will go live when 4.6 goes stable; for now see the merged Xamarin Forms PR for full documentation.
@surfsky In contrast to Razor-like approach C# Markup does not add / mix new language elements to C#, and avoids strings for data binding or property values, choosing typesafe, intellisense-supported C# features instead. However the markup structure reads similar to your example.
@VincentH-Net I followed the PR and I really admire what you did. But what I tried say is, Jetpack compose supports code like this-
Column {
people?.forEach { person ->
Padding(16.dp) {
Text(text = "${person.name} (${person.craft})")
}
}
}
We cannot put a loop or a conditional statement within a collection initializer in C#.
@gulshan said
I followed the PR and I really admire what you did. ... We cannot put a loop or a conditional statement within a collection initializer in C#
Thanks for the compliment!
Actually you can do this because #CSharpForMarkup has built-in helpers to mix-in logic with declarative markup: .Invoke()
and .Assign()
.
E.g. above could be:
new StackLayout { Spacing = 16 }
.Invoke(s => people?.ForEach(person => s.Children.Add(
new Label { Text = $"{person.Name} ({person.Craft})" }
)))
Or, if you want the label text to update to changes in person, you can add a calculated property and bind it like this:
class Person : BaseViewModel
{
public string Name { get; set; }
public string Craft { get; set; }
public string NameAndCraft => $"{Name} ({Craft})";
}
new StackLayout { Spacing = 16 }
.Invoke(s => people?.ForEach(person => s.Children.Add(
new Label { } .Bind (nameof(Person.NameAndCraft))
)))
Or, you could factor out the logic to a method that either returns a new StackLayout
or takes the StackLayout.Children
as parameter.
Or, if you want to support hot reload optimally, you could .Assign (out peopleStack)
and at the end of the Build() method call a void BuildPeopleStack()
method that sets peopleStack.Children
Note that in Forms you would actually use a BindableLayout or ListView or Collectionview and bind to the collection, so you would not need the foreach logic anyway - but that would defeat the purpose of this discussion.
So there are quite a few options to do this, both inline and in separate methods. All because the versatility of C#. No magic, new syntax or strings needed :-)
@VincentH-Net Actually SwiftUI and Jetpack Compose both use a little bit of code generation along with built-in language syntax, specially for "Container" view (with children views), like this-
I don't know if this is possible in C#. I think it will be something really nice to have in C#.
I think @VincentH-Net the challenge now is getting C # HotReload into VS. If this is achieved, the number of people using C # projects will be massive.
LiveSharp is great, and it's not expensive. But many do not know it, and it is a disadvantage. The simple fact of knowing that you have to install a third-party tool, and more being paid, leaves this option for a specific audience.
@luismts I shall say hot reload + hot restart.
With a language that's more suitable for DSLs the UI declaration can be just code.
We don't need yet another Razor/xaml thing IMHO..
The code below is a sample of (https://github.com/AvaloniaCommunity/Avalonia.FuncUI) with F#. Might be interesting... here are templates if you want to give it a spin.
module Counter =
type CounterState = {
count : int
}
let init = {
count = 0
}
type Msg =
| Increment
| Decrement
let update (msg: Msg) (state: CounterState) : CounterState =
match msg with
| Increment -> { state with count = state.count + 1 }
| Decrement -> { state with count = state.count - 1 }
let view (state: CounterState) (dispatch): IView =
DockPanel.create [
DockPanel.children [
Button.create [
Button.onClick (fun _ -> dispatch Increment)
Button.content "click to increment"
]
Button.create [
Button.onClick (fun _ -> dispatch Decrement)
Button.content "click to decrement"
]
TextBlock.create [
TextBlock.dock Dock.Top
TextBlock.text (sprintf "the count is %i" state.count)
]
]
]
Shameless plug, check out a reactive extension to C#/XAML that I wrote for last year's hackathon, called CSX. It lets you have a syntax like JSX suck as:
<StackPanel
Id="taskList"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2">
{
return person.Tasks.Select(todo => CreateToDoItem(todo));
}
</StackPanel>
<Grid.PointerReleased Handler={
completionRateTextBlock.Opacity = 1.0;
taskList.Visibility = taskList.Visibility == Visibility.Collapsed ?
Visibility.Visible : Visibility.Collapsed;
}/>
Xamarin is working on what it calls C# Markup
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/csharp-markup
Example
Grid grid = new Grid();
Label label = new Label { Text = "Code: " };
grid.Children.Add(label, 0, 1);
Entry entry = new Entry
{
Placeholder = "Enter number",
Keyboard = Keyboard.Numeric,
BackgroundColor = Color.AliceBlue,
TextColor = Color.Black,
FontSize = 15,
HeightRequest = 44,
Margin = fieldMargin
};
grid.Children.Add(entry, 0, 2);
Grid.SetColumnSpan(entry, 2);
entry.SetBinding(Entry.TextProperty, new Binding("RegistrationCode"));
Content = grid;
@VincentH-Net That looks really interesting.
I have created an proof of concept for a MVU pattern in UWP. Maybe this can extend this discussion.
using MvuTest.Controls;
using System;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.Xaml;
namespace MvuTest {
public class MainPage : MvuPage {
private TextBlock2 _tb;
private int _count;
protected override IUIElement2 Build() =>
this.StackPanel(
this.ToggleButton("Toggle it")
.Width(200)
.FontSize(30),
this.Button("Increment", (sender, e) => {
_tb.Text($"Count {++_count}");
}).HorizontalAlignment(HorizontalAlignment.Center),
(_tb = this.TextBlock("Count 0"))
.FontSize(20)
.Foreground(Colors.Red),
this.TextBox("Fons Sonnemans")
.Header("Name")
).Spacing(12)
.HorizontalAlignment(HorizontalAlignment.Center)
.VerticalAlignment(VerticalAlignment.Center);
}
}
What are the chances of getting C# Markup as a first class option for WinUI development?
Looking at the latest Google IO and WWDC events, we now see a trend which follows on from Flutter and React Native for Declarative UI
Swift and SwiftUI for macOS and iOS
Kotlin and Jetpack Compose for Android
Will a decision be made for WinUI to prefer C# and C# Markup - so push resources to it, feature it over Xaml in sample apps, templates, conference demos etc.
This also brings up some issues. WinUI and Reunion supports C++ and various other language abstractions - so Xaml will need to remain for those other languages right?
I have the feeling that this is not high on the priority list. I don't think that this is really bad. I love XAML. It is great, consistent and not very difficult. It is verbose though. I would love to have a C# markup solution. But I don't need it. It would be a bonus. I think that other WinUI features like input validation are more essential for its success.
I have the feeling that this is not high on the priority list. I don't think that this is really bad. I love XAML. It is great, consistent and not very difficult. It is verbose though. I would love to have a C# markup solution. But I don't need it. It would be a bonus. I think that other WinUI features like input validation are more essential for its success.
Sure it's not a priority in terms of functionality, but Microsoft is missing a shift in developers expectations, as every other platform and framework is moving this way.
Meeting developers where they are this is Microsoft's current mantra
As I said, just use C#. C# provides a concise way to specify views already.
As I said, just use C#. C# provides a concise way to specify views already.
Compared to some of the tools mentioned above, it's not quite nearly as concise. Various libs and tools have made it better but not nearly as pleasant. This discussion item outlines it well: https://github.com/dotnet/maui/discussions/119#discussioncomment-59504
@mdtauk I have been championing C# Markup for all .NET UI frameworks for a couple of years now, and built a Gen 1 for Xamarin Forms (in XCT now). I pushed for proper C# hot reload which is now coming. I also have a nearly finished next-gen C# Markup version for WinUI 3 and UNO on the shelf. A small snippet (source):
However, to deliver C# Markup in a way so it can compete with Flutter and SwiftUI, also some tooling is needed: proposal
This requires assigning / hiring at least one high level engineer to implement and support this - for one or more .NET UI frameworks.
The past 6 months I am just waiting for any of the UNO / WinUI / MAUI teams - or maybe a team that targets multiple .NET UI frameworks, like the XAML tooling team - to wake up to the outside world and come to the realization that using a single language for declarative markup and logic is not the future but the present - and has been for a while now.
All arguments were already clearly discussed with involved teams (most with MAUI and UNO, WinUI 3 team not so much yet - they reacted a bit confused when I mentioned C# markup in their community calls but they indicated they had too much work and I could add it myself after they go open source).
So, the waiting is for the moment when MS / UNO think this is worth at least a single engineer's time (note that MAUI MVU is also just a single person, who has other tasks as well). If they want to hire me I might even say yes ;-)
It might help if many devs make their wishes known to those teams - Twitter linked to GitHub issues seem to work well in that regard (that is how I got C# Markup into Forms)
@VincentH-Net I agree completely. It needs someone within Microsoft to decide it needs to be built into the tooling, and given priority.
People adopting MAUI will be a big push, as I suspect that team will extol the virtues of a move away from XAML files.
But MAUI is C#, and whilst C# Markup makes total sense there, it doesn't cover C++ development.
MAUI will also be a subset of WinUI's feature set, and so will be limiting in that way.
The removal of the XAML designer is another thing to hamper Xaml dev.
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 5 days.
Apple announced SwiftUI which replaces an older and much more verbose method of building UI for their iOS, iPadOS and macOS platforms.
This is not something that could be done by time of WinUI 3.0 and so is not a proposal per se, but XAML being XML based, is nothing if not verbose. A lot of effort has been made in recent years to make it possible to write less Xaml to do more. VisualStateTriggers being a massive one replacing the VisualStateManager. There is also a proposal to re-work the Grid panel control, to make it more powerful with less Xaml required.
XamlDirect currently exists aimed at middleware tools which can generate XAML from code, but is there some merit into looking at what SwiftUI is doing to perhaps create an alternative to Xaml Markup, with the same power and flexibility of Xaml, but similar to React Native, providing a less verbose version of Xaml.
What it could be called is anyone's guess - for the sake of this suggestion I call it X#, XamlSharp (perhaps inspired by C#'s use of the dot property syntax)
^ Example code is not a suggested syntax, but just an illustrative example
This is a place where anyone who has an interest in simplifying Xaml can share their thoughts, ideas, syntax suggestions