Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spec] Slim Renderer Architecture #28

Closed
StephaneDelcroix opened this issue May 19, 2020 · 87 comments
Closed

[Spec] Slim Renderer Architecture #28

StephaneDelcroix opened this issue May 19, 2020 · 87 comments

Comments

@StephaneDelcroix
Copy link
Contributor

StephaneDelcroix commented May 19, 2020

WARNING: this spec is still a WIP, we're still experimenting with this concept

Description

Slim renderers architecture benefits from multi-targetting and single-project features.

Example

EntryRenderer.cs

public partial class EntryRenderer {
   public static PropertyMapper<IView> ViewMapper = new PropertyMapper<IView> {
	
     // Add your own method to map to any property         
     [nameof(IView.BackgroundColor)] = MapBackgroundColor

   };
}

EntryRenderer.iOS.cs

// You don’t need to register a new renderer.
public partial class EntryRenderer
{
     // You know what method to call because you named it!
   public static void MapBackgroundColor (IViewRenderer renderer, IView view)
     {
        // You don’t need to call any base methods here or worry about order.
   
        // Every renderer is consistent; you know where the native view is.
          var nativeView = (NativeView)renderer.NativeView;
          var color = view.BackgroundColor;

          if (color != null) {

            // Phew! That was easy!	        
            nativeView.BackgroundColor = UIColor.FromRGB (204, 153, 255);
          }
     }
}

Standardization of renderers

All the default renderers will be ported to this architecture, for all platforms

Registration of renderers

The rendererRegistrar will exists on the dependency service and be accessed by serviceCollection.Get<IRendererRegistrar>(), allowing control to which renderer is associated to which control

Interfaces on renderers

Mapper concept

The property mapper is responsible for triggering actions in response property changes. A slim renderer itself does not subscribe to the property changes, but some declared actions are executed in response to changes.

The property mapper property of a control is public static and can be extended by user code.

The property mapper plays no role in the feedback loop (button clicked, text entered)

TODO: discuss what to use for mapper key. string or object ? It'd be nice to avoid string comparison in case when we can compare references (in case of BindableProperties)

How to use legacy custom renderers

How to use third-party controls depending on old renderers

How to complement existing renderers

The new extensibility model for this architecture is based on the property mapper. When you want to add support for a new property, it only requires mapping the new property. For the property to exists, subclassing the control is necessary, but subclassing the renderer is not.

Backward Compatibility

Wether we want to keep backward compatibility with existing custom renderers, or subclasses of old renderers will influence the architecture of this

Difficulty : very high

@ysmoradi
Copy link
Contributor

Xamarin forms wpf renderers and some of android renderers such as ButtonRenderer are fast, and we know what does "fast" mean here.
Are these renderers will be fast or not?
Thanks in advance.

@samhouts
Copy link
Member

@ysmoradi Yep! These new renderers will follow the fast renderer pattern (i.e., no wrapper view around the main view). We plan to do this for all platforms, not just Android and WPF.

@MichaelRumpler
Copy link
Contributor

Please don't try to stay backwards compatible at all costs. This is something new. It does not have to be compatible with XF. You can make something better.

@ugnivs
Copy link

ugnivs commented May 19, 2020

Why not to make UI framework with own set of controls without any kind of mappings and behavioral logic fully written on c# that would be rendered with Skia graphics library? As people use strongly customized design there is no need in trying to match platform design guidelines. The only need is possibility of flexible customizations. Please correct me if i'm missing something, but i don't understand why benefit is over Renderer architecture.

@pranshu-aggarwal
Copy link

With this approach, is it possible to write a cross-platform renderer instead of the platform-specific renderer? Like mapping Button control with skia-sharp control .

@h82258652
Copy link

Platform renderer is a bad design. As you see, there are lots of xamarin control libs that don't support UWP due to the platform limit.
Take an example, the shadow in UWP. You can't get a corner shadow from a corner button (of course, you can change the button template to do this, but that's another thing).

I know it is very difficult to build a cross platform render. But flutter told us this is feasible. In the long term, a cross-platform renderer is the best solution.

@Soul-Master
Copy link

I think render entire app as custom 2d canvas might work seamlessly for mobile app.

But it might not work for desktop app or complex app because there are so many user actions that need to be re-implemented like drag-drop, text selection, keyboard shortcut to manipulate text and so on.

Why not to make UI framework with own set of controls without any kind of mappings and behavioral logic fully written on c# that would be rendered with Skia graphics library? As people use strongly customized design there is no need in trying to match platform design guidelines. The only need is possibility of flexible customizations. Please correct me if i'm missing something, but i don't understand why benefit is over Renderer architecture.

@ugnivs
Copy link

ugnivs commented May 20, 2020

I think render entire app as custom 2d canvas might work seamlessly for mobile app.

But it might not work for desktop app or complex app because there are so many user actions that need to be re-implemented like drag-drop, text selection, keyboard shortcut to manipulate text and so on.

Why not to make UI framework with own set of controls without any kind of mappings and behavioral logic fully written on c# that would be rendered with Skia graphics library? As people use strongly customized design there is no need in trying to match platform design guidelines. The only need is possibility of flexible customizations. Please correct me if i'm missing something, but i don't understand why benefit is over Renderer architecture.

You're absolutely right about all of this stuff, but the team is not forced to choose the only one approach. I think this all about lack of time. I mean they just need to release a "brand new" fully crossplatform ui framework in a year together with .net 6. And and it's much less risky to take good old time-tested framework as the basis. It's ok and it should be. But i believe that in long time run custom 2d canvas rendering have much more benefits and really deserves to be called "cross platform". Xamarin forms is really good thing and it has a huge progress for today. But it's time to move on. Microsoft and xamarin teams have very clever engineers and they probably considering such an approach or maybe even have some connections with http://avaloniaui.net/ as a trump card

@filipoff2
Copy link

Why not to make UI framework with own set of controls without any kind of mappings and behavioral logic fully written on c# that would be rendered with Skia graphics library? As people use strongly customized design there is no need in trying to match platform design guidelines. The only need is possibility of flexible customizations. Please correct me if i'm missing something, but i don't understand why benefit is over Renderer architecture.

It could be cool to have 4-th render default grey one for Skia developers will 100% change it for sure to deliver rich design,
For back combability would leave those 3 as they are but add " draw it yourself dear developer"_skia_render and take 90% responsibility for it developer.

@velocitysystems
Copy link
Contributor

If the concept of renderers is to be maintained, can thought be given to eliminating the bridge between shared UI code and renderers via INotifyPropertyChanged and event handlers? i.e.

  • Instead of setting a property on the shared control and a PropertyChanged event being propagated, can the property be mapped and set directly on the platform renderer?
  • Instead of calling a method on the shared control and an event being fired and handled by the renderer, can the method be mapped and involved directly on the platform renderer?

INotifyPropertyChanged is great for MVVM design and loosely-couple view models, but has always felt clunky as a bridge mechanism between the shared UI code and platform renderers. This in turn would lead to better performance, less 'chattiness' between the shared UI and renderer layer and a better developer experience.

@freever
Copy link

freever commented May 20, 2020

This is long but worth watching for some "inside baseball" on Maui.
https://www.youtube.com/watch?v=_MGh3xipWm4

It sounds like the architecture of Maui will support both platform-rendered controls and canvas-drawn controls, and furthermore that the noble @Clancey will be continuing to work on a skia-based render set for Maui which will not only work in the MVU flavour of Maui but also for the MVVM pattern.

At first glance Maui seemed like a rebranding of Forms, but on closer inspection it is a restructuring of the Forms architecture to make its layers more loosely coupled and thereby support many of the things we are asking about in this thread. Fun times ahead.

@GalaxiaGuy
Copy link
Contributor

This is slightly off topic, but is something I've wanted to ask just because of its relevance to this exact thing:

How does memory work with SKCanvasView (or Skia in general)? Does each one always take up memory proportional to its size? Does this change if it overlaps others?

If, for example I had a gradient control (renderer written in Skia) and over the top of that I had a semi transparent button (renderer written in Skia) would that take up twice as much memory, or is the graphics context somehow shared? How about if Skia controls overlapped non-Skia controls?

I've considered implementing some fancy graphics controls in Forms using Skia before, but not understanding how the memory works has always caused enough concern that I haven't.

@h82258652
Copy link

@GalaxiaGuy I think using a skia control overlapped on a non-skia control, just like a winform control hosted on a wpf control. You can do this, but not the best.
If you have two controls rendered by SKCanvasView, the graphics context will not be shared. The best way is to composite the two rendered and draw it on a single canvas.
In my test, the SkiaSharp performance is not so bad if you just do some static things. And I try to do some animations, the CPU usage is a little high on my laptop.

@legistek
Copy link
Contributor

Why are so many people obsessed with Skia? A good rendering spec would be agnostic to the rendering engine used at the low level. If a particular platform renderer wants to use Skia (or Direct2D or OpenGL or whatever) that shouldn't be something the application layer should have to worry about.

@danielkatz
Copy link

danielkatz commented May 20, 2020

The biggest promise of XAML with WPF ages ago, was the idea of Lookless Controls where the actual graphics of the controls were deferred to templates. Xamarin Forms used XAML without this ability, and this was its weakest point, only years later partially fixed by the Drawing spec.
I don't think that we need yet another set of interfaces and abstractions over existing components in various OSs and frameworks, but a XAML-based truly lookless controls - templated with platform-agnostic visual primitives and platform-specific graphic rendering backends. And sure, the default template may as well be the actual native control, but the holy grail is the define-once-use-everywhere graphic templates.

@legistek
Copy link
Contributor

The biggest promise of XAML with WPF ages ago, was the idea of Lookless Controls where the actual graphics of the controls were deferred to templates. Xamarin Forms used XAML without this ability, and this was its weakest point, only years later partially fixed by the Drawing spec.

Agreed! And you really need a very small number of rendering primitives to accomplish probably 99% of everything an app needs:

  • Borders (incl. options for drop shadow and rounded edges)
  • Lines/Ellipses/Rectangles
  • Plain text rendering
  • Plain text input
  • Rich text rendering
  • Rich text input
  • HTML rendering
  • Image presenter
  • Audio/Video presenter
  • Solid and Linear / Radial Gradient brushes

The XF rendering platforms have become so bloated because whenever a new type of control is added to the framework it's done with a new renderer rather than building on top of existing primitives within the framework.

Yes a lot more logic would have to be moved into the framework layer, the most challenging being when it comes to items controls (VirtualizingStackPanel is critical to having a scalable items viewer but has to my knowledge never been effectively ported outside of WPF because it's so complex). But with WPF being open source a lot of that can be ported over into MAUI now and I think this is finally the time when that should start happening.

@ysmoradi
Copy link
Contributor

you really need a very small number of rendering primitives to accomplish probably 99% of everything an app needs.

Uno platform is using this approach.

@PureWeen
Copy link
Member

@velocitysystems

Instead of setting a property on the shared control and a PropertyChanged event being propagated, can the property be mapped and set directly on the platform renderer?

That's a big goal of this change as well. Once we're on the other side of these changes the renderers will have no idea what a BindableObject or INPC means

@legistek
Copy link
Contributor

That's a big goal of this change as well. Once we're on the other side of these changes the renderers will have no idea what a BindableObject or INPC means

So a method on the renderer will get invoked by the framework whenever a BindableProperty value changes instead of the renderer having to subscribe to PropertyChanged?

@PureWeen
Copy link
Member

@legistek right

This basically inverts the dependencies

So the renderers will just work against IButton.

And then System.Maui will add a reference to the renderers project opposed to right now how the renderers have a references to Xamarin.Forms.Core

I checked in a spike we have here
#66

So you can see what this might look like

@PureWeen
Copy link
Member

I'll be doing a stream today at 3:30 PDT time with @davidortinau and we'll be talking about the slim renderers

https://www.twitch.tv/microsoftdeveloper

Join us! Check it out! And ask questions!

@velocitysystems
Copy link
Contributor

@PureWeen Unfortunately I missed it. Will there be a recording available on YouTube?

@velocitysystems
Copy link
Contributor

That's a big goal of this change as well. Once we're on the other side of these changes the renderers will have no idea what a BindableObject or INPC means.

That is huge, a real substantial improvement. No doubt too with the move to Maui, the complex inheritance model used in many of the renderers will be removed in favour of a more compositional approach?

Going to review #66 today.

@velocitysystems
Copy link
Contributor

Looking at #66, it is nice to see the slim renderers are built and invoked with 'bait-and-switch' rather than using reflection. Just a few thoughts:

  • Will Slim renderers address the GC issues, especially on Android where there is a mismatch between the managed and native control lifecycle? This is especially noticeable in child views in virtualized layouts leading to the dreaded ObjectDisposedException.
  • Will Slim renderers lead to the deprecation of Effect? Effects can be useful, but ultimately they add complexity and yet another potential for latency to the layout lifecycle.
  • How would a 'two-way' property work with the new renderer design? E.g. Let's say I have a MediaElement with a Position (TimeSpan) property. Setter updates the current position, and the getter retrieves the current position from the native media player i.e. AVPlayer, MediaPlayer. Is there a design for mapping a getter with slim renderers?

@PureWeen
Copy link
Member

Will Slim renderers address the GC issues, especially on Android where there is a mismatch between the managed and native control lifecycle? This is especially noticeable in child views in virtualized layouts leading to the dreaded ObjectDisposedException.

We do have some ideas here!! We want to rework the disposal strategies a bit to hopefully resolve most if not all of the ODE exceptions. Right now we super aggressively dispose of everything in android/iOS but I'm fairly certain we can just rely on the GC to do what the GC does. If we just make sure to dereference everything and let the GC do the work that should help in a lot of these cases

Will Slim renderers lead to the deprecation of Effect? Effects can be useful, but ultimately they add complexity and yet another potential for latency to the layout lifecycle.

This is definitely a good thing to look into as we evolve this idea. Once we reach a final design for all this we'll take a look at effects. But, yes I could see effects being obsoleted as they are intended as a way to tap into native elements without having to go full renderer. Mappers basically obsolete effects

How would a 'two-way' property work with the new renderer design? E.g. Let's say I have a MediaElement with a Position (TimeSpan) property. Setter updates the current position, and the getter retrieves the current position from the native media player i.e. AVPlayer, MediaPlayer. Is there a design for mapping a getter with slim renderers?

We're still working this one out a bit. Correct me if I'm wrong @Clancey but the ActionMapper was our current approach for this yes? https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

@Clancey
Copy link
Contributor

Clancey commented May 21, 2020

How would a 'two-way' property work with the new renderer design? E.g. Let's say I have a MediaElement with a Position (TimeSpan) property. Setter updates the current position, and the getter retrieves the current position from the native media player i.e. AVPlayer, MediaPlayer. Is there a design for mapping a getter with slim renderers?

We're still working this one out a bit. Correct me if I'm wrong @Clancey but the ActionMapper was our current approach for this yes? https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

Not exactly. So the ActionMapper is the same thing as a PropertyMapper with the exception, they are not called during the SetElement phase. So, for things like WebView, GoBack. You don't want to call that during initialization but it's still something you need to communicate with the Renderer.

We already support 2 way mapping. i.e Entry. When the text value chances on the entry. the IEntry has a string Text {get;set;} and we simply set the value. So for media elements you have 2 options. One is simply set back the position/time when it changes. If you want to make it something you query instead. You can do that. The xplat views have access to the renderer. view.Renderer.NativeView as NativeMediaView You can now pull off any properties you want!

@PureWeen
Copy link
Member

Here are some videos from our streams during Build

@Clancey 's here will be more in depth
https://www.youtube.com/watch?v=_MGh3xipWm4

I touch on them a little bit here with David
https://www.youtube.com/watch?v=lAmwjfZY1IM

@Suprndm
Copy link

Suprndm commented Mar 12, 2021

OPPO phones manufactures phones that costs under 200$, that's way I precised the brand as an argument for good performances.

It’s much faster than Xamarin and many others. However, much slower, and much less power efficient, than Direct2D or nVidia’s nv_path_rendering.

Thanks for the clarification.

Raspberry Pi 4 has an SoC made with 28nm process, that’s comparable to Snapdragon 427 from 2016.

Not sure raspberry Pi was made to display rich user interfaces. But even if you'd want it, i'm pretty sure the framework I've worked on shows good perfs and those devices, As I rely on caching to avoid unecessary redrawing. With my spare time I managed to have such results.. As you said : Sure Microsoft has more resources.

Personnaly I see no disqualifers at using a renderer that runs smooths on all kinds of devices , that addresses the vast majority of the use cases, as a cross renderer. Especially when compared to what's actually proposed...
Getting inconsistency in the app design and app behavior between device targets is hell for app editors. Not even talking about perfs. I recommanded my clients to use flutter instead of XF because of that. I want to beleive in MAUI but looks like i'm going to still recommand flutter after all. Which i'm truly disapointed at. Will see the final product of course.

@Const-me
Copy link

OPPO phones manufactures phones that costs under 200$

Right, but they also manufacture phones which cost well above $1000.

Not sure raspberry Pi was made to display rich user interfaces

Not the case now, but it could be, even when rendering on a 4k display. Technically, the GPU is not too bad.

I see no disqualifers at using a renderer that runs smooths on all kinds of devices

My proof-of-concept library is not pixel perfect but it’s close. I’ve compared between Raspberry Pi 4 backed by GLES 3.1, and Windows 10 backed by Direct3D 12. It doesn’t use native controls. On the API surface it’s somewhat close to Skia (more specifically, I’ve tried to re-implement Direct2D), but unlike Skia and similar to D2D, it’s designed to leverage modern 3D GPUs. Under the hood it uses a third-party library called diligent engine.

Especially when compared to what's actually proposed

Indeed, what’s proposed is just horrible. If I would choose between 2 solutions, what’s proposed and Skia, I would pick Skia no questions asked. However, even ignoring the performance, with Skia these 3 use cases (integrating 3D-rendered content, video playback, custom effects) are all very hard. Personally I don’t care about custom effects, but the software I work on often does need 3D content and/or video.

@jlew11
Copy link

jlew11 commented Mar 17, 2021

@vibeeshan025
Copy link

Why we are not considering Silverlight like approach to drawing the controls in Framework level than, having wrappers around custom renderers (Is it because of apple's restrictions).
I support consistency over native look. It's really a pain in the a** to check and modify each and every platform. I believe WPF also uses a similar approach, though it looks like a native button, they just have an embedded Windows XP, 7 and 8 styles / theme hidden beneath.

@Const-me
Copy link

@vibeeshan025

Is it because of apple's restrictions

I believe Flutter is a counter-example.

I support consistency over native look.

Strongly agree.

Besides the consistency, .NET runtime currently runs on platforms which don’t have any native look at all, like embedded Linux. I would love to have officially supported GPU-targeted GUI framework which runs on top of OS kernel, bypassing X11/Wayland/XFCE desktop managers. I did it couple times myself (besides the one I linked above, for another projects I consumed nanovg instead) but an MS-supported option would be awesome. Even if I have to plug my own windowing and input support, that’s still relatively small amount of complexity compared to GPU integration, 2D rendering, and all the higher-level stuff on top of that.

I believe WPF also uses a similar approach

You’re correct, WPF re-implemented everything on top of DirectX 9.0c. At the time, DX9 was the most compatible way to access a 3D GPU on Windows. It has a few issues probably due to limitations of D3D9 and quirks of old GPUs https://jeremiahmorrill.wordpress.com/2011/02/14/a-critical-deep-dive-into-the-wpf-rendering-system/ but still pretty darn good in practice.

Only a few isolated WPF components integrate native controls, most notably the embeddable web browser.

@davidskuza
Copy link

If you want "consistency" then you can use Flutter, Web, QT or your custom renderer or anything. What is lacking is exactly native renderers. You have to write your app at least 3 times for Windows, MacOS and Linux if you want it to be native. I know most of Windows users doesn't care that their apps looks... bad, doesn't integrate with the OS and you have to learn every app but on other platforms, especially MacOS people do care. You choose Mac because it's nice and has nice apps. Yet another cross platform renderer is useless for most... Why use this then if I can just do that in web with millions of available resources and devs...

@Const-me
Copy link

@davidskuza

Flutter

Desktop support is still in beta: https://flutter.dev/desktop It has a non-trivial learning curve because it includes a purposedly-built programming language, i.e. harder to find developers.

Web

Requires a desktop environment, doesn’t work on bare metal. Electron apps tend to consume lots of memory. JavaScript is not always the best tool for the job: it’s slow, and very hard to integrate with native code, people usually do it with an embedded JSON RPC web server in the same process.

QT

While mature, widely used, and generally good quality, the usability is not great because C++. Also, for many use cases it requires a commercial version, which is very expensive.

your custom renderer

Extremely hard to do well. I know because I have made one: https://github.com/Const-me/Vrmac/

most of Windows users doesn't care that their apps looks

That was not always the case. As demonstrated by WPF, it is possible to re-create look and feel of native controls on top of a GPU-based renderer.

@davidskuza
Copy link

Desktop support is still in beta: https://flutter.dev/desktop It has a non-trivial learning curve because it includes a purposedly-built programming language, i.e. harder to find developers.

Good this is stable.

Requires a desktop environment, doesn’t work on bare metal. Electron apps tend to consume lots of memory. JavaScript is not always the best tool for the job: it’s slow, and very hard to integrate with native code, people usually do it with an embedded JSON RPC web server in the same process.

You know that non of the arguments are "valid" (can't find better word). Look around, Slack, VS Code, Teams, Discord, WhatsApp etc. Most of them built with web/electron because it's fast time to market and good enough performance. If any of your argument would be true those apps would be written in C, C++ or Rust.

Requires a desktop environment,

? does MAUI target embedded?

doesn’t work on bare metal

? MAUI also needs runtime?

JavaScript is not always the best tool for the job: it’s slow

I wouldn't say it's slow. Language it's not perfect either but what to do. Nothing is even close to perfect if you are working on it long enough. For now JavaScript happened to be the most universal "best tool for the job" ranging from UI, server side to embedded.

and very hard to integrate with native code, people usually do it with an embedded JSON RPC web server in the same process

Wow, never saw anybody doing like that. Literally if you don't know C/C++ env the easiest way is to build node addon... Node is the only platform when I have integrated native code and did not want to abandon the job. You don't even need to configure anything besides your source files...

Extremely hard to do well. I know because I have made one

That was not always the case. As demonstrated by WPF, it is possible to re-create look and feel of native controls on top of a GPU-based renderer.

Then you should probably know how many attempts at this were made and how many are successful. Also Microsoft recreating GUI they created in WPF doesn't even count. They built it, they control every aspect of it, they can even integrate it in the OS. They built in once for Win32 with software renderer then why they could not with DirectX.

I just wanted to say that there are people who would be happy for native UI library because I saw everybody who posted here wants MonoGame with UI on top.
Also with current state of the world even if such platform would exists (custom drawn controls) why as a business should I choose that if there is a web. The community, ecosystem. There are even people who don't even know C# exists but can code crossplatform apps.

Right now if you would want to build native app for every platform with native controls, UX and integrations you would probably have to use C/C++/Rust/JS for Linux, C# for Windows but if you build for Linux then it's better to stay with C++ anyway to share logic and on MacOS integrate using Swift. If MAUI would allow to use native UI/UX but code everything/most in C# then there is an argument and a huge one. wxWidgets would be probably the only competition with that possibility and I doubt if this would be done correctly anybody would even consider it... When I found this project I got so hyped that there will be such thing supported. (Okay, if React Native Windows would have been released then there is also that but with MVU and maybe if needed some tweaks to the language we would have first contender vs JavaScript).

After 2-3 years of stable Flutter I don't see people jumping to it because such platforms will always be inferior. People are more hyped for Jetpack Compose. And yet, Flutter is solving problem which is not solved as for web on mobile with low end phones isn't so performant in regions like India which is a massive market for mobile apps.

Also if you think that custom rendered controls would solve all your cross platform "consistency" problems then I think that will not be the case. You will be consistently below average besides single platform of choice (at most equal with web). If you search for custom UI's (there are software e.g. in music industry which were built that way) or also with web there are problems which cannot be solved universally anyway.
"Why does my font doesn't look native and sharp? Oh, you used custom renderer not the native one system provided. Use native one. You used native renderers everywhere? Why now this layout is different, there are bigger/smaller margins, spacings and paddings, looks ugly, whole app looks weird, you have to change that!".

@Const-me
Copy link

does MAUI target embedded?

MAUI does not exist yet, we’re discussing proposed architecture here. The .NET runtime does indeed target embedded, Microsoft even ships ARM Linux binaries. They depends on Linux kernel of course, but not much else (a Unicode-related OS package).

Language it's not perfect either but what to do.

I would like to be able to implement equivalent UX in cross-platform .NET.

many attempts at this were made and how many are successful

Some of them were. Flutter has successfully re-implemented native controls of iOS and Android. It’s not a rocket science, just GUI design and attention to details.

Microsoft recreating GUI they created in WPF doesn't even count

Why not? They were different people with decades of time between these projects. Win32 GUI (gdi32.dll, comctl32.dll, etc.) is in large parts a legacy from 16-bit Windows 3.x.

why as a business should I choose that if there is a web

That’s a great question. Here’s a few reasons.

I don’t believe HTML5 is an optimal substrate for rich GUI apps. It was designed for documents as opposed to GUI. For instance, data binding and data templates are important parts of MS XAML platforms. With modern web, technically we have react/angular/etc., but they are implemented by third parties on top of HTML DOM. These features are fundamentally complicated, and are way more usable when provided by the platform. In business terms, this means for many projects with complicated rich GUI, HTML/Electron will take more money to develop compared to XAML.

Web browsers don’t work on top of bare OS kernel, they need a desktop environment.

Web browsers are huge, not all people are happy downloading 100MB installer for a chat app.

3D graphics is limited to WebGL, which is not good enough compared to appropriate GPU APIs (Direct3D on Windows, Metal on OSX and iOS, Vulkan on most modern Linuxes including Android).

Hardware accelerated video is limited to HTML’s <video> element, which is OK for media consumption but some desktop software does authoring.

Many other use cases need to integrate with native APIs for various reasons. HTML/JavaScript doesn’t have low latency audio, has very limited support for custom input devices, doesn’t support custom peripherals, doesn’t support protected storage (Windows) or keychain services (Apple), and so on. These features are not too hard in modern .NET and don’t require writing a single line of C++, native interop is good.

if you would want to build native app for every platform with native controls

The success of Electron shows that’s not what many people want. They want consistent GUI across all platforms, while keeping software development costs reasonable (e.g. avoiding C++).

Another thing, among modern platforms, only OSX, iOS and Android have decent native controls.

On Windows everything is in XAML nowadays, the look and feel is completely defined with these styles and templates. Note the recent 0.5 milestone of WinUI 3.

On Linux there’re multiple competing desktop environments, with different native control libraries and UX conventions.

I don't see people jumping to it because such platforms will always be inferior

I think their main mistake was inventing Dart, instead of embedding something like .NET, Go, or JVM.

which cannot be solved universally anyway

They are all solvable, look at modern web browsers or game engines. However, they are very expensive to solve well across multiple platforms, too many edge cases: DPI scaling, display rotation, right to left languages, accessibility, and many others.

@davidskuza
Copy link

The .NET runtime does indeed target embedded, Microsoft even ships ARM Linux binaries. They depends on Linux kernel of course, but not much else (a Unicode-related OS package).

ARM is an architecture. What does it have to do with embedded? More modern than x86. Even in 2nd sentence you mention Linux...

I would like to be able to implement equivalent UX in cross-platform .NET.

Avalonia.

Some of them were. Flutter has successfully re-implemented native controls of iOS and Android. It’s not a rocket science, just GUI design and attention to details.

Yeah... go and try use new OS things. Oh, you can't. Best you get is "work in progress".

Why not? They were different people with decades of time between these projects. Win32 GUI (gdi32.dll, comctl32.dll, etc.) is in large parts a legacy from 16-bit Windows 3.x.

Oh, I forgot. Win32 GUI is legacy, doesn't change. You can work 10 years on your UI and still you won't be obsolete. Even more irrelevant.

I don’t believe HTML5 is an optimal substrate for rich GUI apps. It was designed for documents as opposed to GUI. For instance, data binding and data templates are important parts of MS XAML platforms.

Who cares what you believe? It has been done, it works, customers are happy enough and they decide what to we do. Not to mention more and more (all my current work) customers want web and doesn't care about desktop anymore (in general business trade). Now with COVID and remote work even more. I know companies which were "offline" first, "security" concerned but after of year of remote work they decided to go "online".

It was designed for documents as opposed to GUI.

So what? I don't get this argument. XAML is designed like HTML (but worse) and now you are happy because marketing told you another.

Web browsers don’t work on top of bare OS kernel, they need a desktop environment.

The availability of CI, test runners and crawlers? You run everything on Windows Server? Haha.

Web browsers are huge, not all people are happy downloading 100MB installer for a chat app.

But for .NET core they are. Not to mention PWA's or things like Neutrino which uses bundled browser with OS.

3D graphics is limited to WebGL, which is not good enough compared to appropriate GPU APIs (Direct3D on Windows, Metal on OSX and iOS, Vulkan on most modern Linuxes including Android).

There is WebGPU incoming. It's so good people extracted it from browser and they are using it from C++/Rust for common abstraction over all platforms. If you need more performance than that probably GCed language is not enough either.

Many other use cases need to integrate with native APIs for various reasons. HTML/JavaScript doesn’t have low latency audio, has very limited support for custom input devices, doesn’t support custom peripherals, doesn’t support protected storage (Windows) or keychain services (Apple), and so on. These features are not too hard in modern .NET and don’t require writing a single line of C++, native interop is good.

At most yet, faster than MAUI it seems. Web Audio? Web Serial? Web Usb? It for sure supports more, easily. But that are Web standards and you are talking about running on OS in things like Electron... you can have more than .NET in there. For sure this way is not limited.

The success of Electron shows that’s not what many people want. They want consistent GUI across all platforms, while keeping software development costs reasonable (e.g. avoiding C++).

What? It's not what "people" want. It's what developers want. You missed last 10 years of evolution or what? You are still on Windows XP, right? Oh no, that would be Windows 7.

I know more people avoiding .NET that anything else.

On Windows everything is in XAML nowadays, the look and feel is completely defined with these styles and templates. Note the recent 0.5 milestone of WinUI 3.

Yes, aka big mistake but we have to support it. Adoption of XAML around the world perfectly shows how much people like it. "MVU" is good confirmation about this statement. And no, your world and people using C# are not examples it's good if it's the only sensible option. Also "MVU" as it people here are calling happened to be so good dev experience that everyone want's to do it.

On Linux there’re multiple competing desktop environments, with different native control libraries and UX conventions.

AFAIK Gnome and KDE. Other things are just your "consistent" custom cross platform GUI.

I think their main mistake was inventing Dart, instead of embedding something like .NET, Go, or JVM.

They did but it was too slow for 120 fps.

They are all solvable, look at modern web browsers or game engines. However, they are very expensive to solve well across multiple platforms, too many edge cases: DPI scaling, display rotation, right to left languages, accessibility, and many others.

You just given the same examples as I did. Go render some text that looks everywhere the same. Impossible because browser renders font with system font renderer and there is always some differences. Starting with layouting for fonts which different engines do differently or bugs. Game engines are even more incosistent because they do not have features like an UI framework have. You see a few bitmaps on screens and you think they are consistent but run that game on e.g. 21:9 and half of UI doesn't render because it thinks screen ended, other half tries for some reason to stretch etc. They do everything often manually so if you did not tested that it crumbles. Refund. Funny enough the best scalable, crossplatform, complex game UIs were made with web and webkit, or Coherent...

@fubar-coder
Copy link

Sorry, this discussion seems OT. Can a moderator chime in and delete some of the comments above (and this one)?

@davidskuza
Copy link

Very welcoming community.

@saint4eva
Copy link

Desktop support is still in beta: https://flutter.dev/desktop It has a non-trivial learning curve because it includes a purposedly-built programming language, i.e. harder to find developers.

Good this is stable.

Requires a desktop environment, doesn’t work on bare metal. Electron apps tend to consume lots of memory. JavaScript is not always the best tool for the job: it’s slow, and very hard to integrate with native code, people usually do it with an embedded JSON RPC web server in the same process.

You know that non of the arguments are "valid" (can't find better word). Look around, Slack, VS Code, Teams, Discord, WhatsApp etc. Most of them built with web/electron because it's fast time to market and good enough performance. If any of your argument would be true those apps would be written in C, C++ or Rust.

Requires a desktop environment,

? does MAUI target embedded?

doesn’t work on bare metal

? MAUI also needs runtime?

JavaScript is not always the best tool for the job: it’s slow

I wouldn't say it's slow. Language it's not perfect either but what to do. Nothing is even close to perfect if you are working on it long enough. For now JavaScript happened to be the most universal "best tool for the job" ranging from UI, server side to embedded.

and very hard to integrate with native code, people usually do it with an embedded JSON RPC web server in the same process

Wow, never saw anybody doing like that. Literally if you don't know C/C++ env the easiest way is to build node addon... Node is the only platform when I have integrated native code and did not want to abandon the job. You don't even need to configure anything besides your source files...

Extremely hard to do well. I know because I have made one

That was not always the case. As demonstrated by WPF, it is possible to re-create look and feel of native controls on top of a GPU-based renderer.

Then you should probably know how many attempts at this were made and how many are successful. Also Microsoft recreating GUI they created in WPF doesn't even count. They built it, they control every aspect of it, they can even integrate it in the OS. They built in once for Win32 with software renderer then why they could not with DirectX.

I just wanted to say that there are people who would be happy for native UI library because I saw everybody who posted here wants MonoGame with UI on top.
Also with current state of the world even if such platform would exists (custom drawn controls) why as a business should I choose that if there is a web. The community, ecosystem. There are even people who don't even know C# exists but can code crossplatform apps.

Right now if you would want to build native app for every platform with native controls, UX and integrations you would probably have to use C/C++/Rust/JS for Linux, C# for Windows but if you build for Linux then it's better to stay with C++ anyway to share logic and on MacOS integrate using Swift. If MAUI would allow to use native UI/UX but code everything/most in C# then there is an argument and a huge one. wxWidgets would be probably the only competition with that possibility and I doubt if this would be done correctly anybody would even consider it... When I found this project I got so hyped that there will be such thing supported. (Okay, if React Native Windows would have been released then there is also that but with MVU and maybe if needed some tweaks to the language we would have first contender vs JavaScript).

After 2-3 years of stable Flutter I don't see people jumping to it because such platforms will always be inferior. People are more hyped for Jetpack Compose. And yet, Flutter is solving problem which is not solved as for web on mobile with low end phones isn't so performant in regions like India which is a massive market for mobile apps.

Also if you think that custom rendered controls would solve all your cross platform "consistency" problems then I think that will not be the case. You will be consistently below average besides single platform of choice (at most equal with web). If you search for custom UI's (there are software e.g. in music industry which were built that way) or also with web there are problems which cannot be solved universally anyway.
"Why does my font doesn't look native and sharp? Oh, you used custom renderer not the native one system provided. Use native one. You used native renderers everywhere? Why now this layout is different, there are bigger/smaller margins, spacings and paddings, looks ugly, whole app looks weird, you have to change that!".

C# and .NET are cross platform

@Charuwaka
Copy link

Charuwaka commented May 17, 2021

I have built several apps in xamarin forms, recently I switched to the flutter, what I instantly noticed is, ease of writing UI. I built a simple dashboard UI (refer below) within 1.5 days, if it is xamarin forms it would take me at least 3-4 days(as per my experience). Hot reload works like a charm in flutter(but most of the time it sucks in xamarin forms especially if your writing a custom renderer for a button, you cant see preview).

Screenshot 2021-05-17 at 1 52 53 PM

I don't want to write a custom renderer for even simple things(Shadows, Elevations, etc), which is a tedious task, please find a way to avoid custom renderers as much as possible. Writing animations also very simple which is not the case in xamarin forms.

From a backend perspective C# is pretty solid in terms of (MVVM, DI, Design patterns) hands down!

@brencode
Copy link

brencode commented May 19, 2021

I've been developing with Xamarin.Forms since its inception. Every client I've worked for has wanted as close to an identical UI as possible on all target platforms. Clients do not want or need native controls/widgets/views to be rendered typically. It is a rare edge case. All clients I've worked for have adopted Xamarin because existing .NET developers could use C#/.NET to build mobile apps, while being able to consume existing libraries without reinventing the wheel. Clients and developers I've spoken to want Microsoft to ditch the native UI approach, and to emulate the Flutter and UNO approach of rendering controls independently of the constraints of the platform. The majority of development time is spent trying to tweak the UI to make it look identical on both platforms for current Xamarin developers. With the release of Flutter 2.2, it is becoming increasingly difficult to rationalize further investment in MAUI until this becomes THE primary architecture for the platform. Mimicking the Flutter/UNO approach highly simplifies the development process on your end, and working prototypes are already alive and well that should be used to accelerate development. This is where developers want MS and the MAUI/Xamarin team to invest in. The holy grail for developers is for MS to emulate Flutter's architecture while giving we developers the massive advantage of being able to continue to use .NET and C# so we don't have to reinvent the wheel by rewriting libraries in an immature language like Dart. Finally, Microsoft is investing in working with Google to allow Flutter to target Windows.. MS should instead be investing in competing directly with Google by building MAUI the way its veteran developers want. If MAUI goes native UI first at launch, it will be obsolete the day it is released. If this happens, after seven years of using Xamarin/.NET to develop mobile apps, I will move on and invest in Flutter instead, because at least Google has its head on straight enough to build the tools we want and need.

@nickrandolph
Copy link
Contributor

@brencode there's room in the market for different solutions and different approaches. I agree that for the most part Flutter is dominating this space as Google seems to be investing heavily in marketing (they see this as a loss leader for their cloud platform). I see that Maui and Uno are attempting to solve same issue but coming from different directions. If you want 100% consistency of layout etc, then Uno is the answer. If you want a framework for rapidly scaffolding an application, the Maui with pieces like Shell will give you that jump start - it also is the way to go if your company/customer is fixated on not using third party frameworks (I don't understand this but it does exist with some orgs)

@giuseppenovielli
Copy link

@brencode but MAUI will be implement also with draw controls by https://github.com/dotnet/Microsoft.Maui.Graphics.Controls

@Charuwaka
Copy link

Charuwaka commented May 20, 2021

Xamarin is very good from a backend perspective, I can quickly build enterprise architecture patterns with ease, but when it comes to UI, I need to spend a lot of time to match UI pixel perfectly with a mockup. Please focus on the UI part that's all we want. why don't you guys use Skia Sharp to draw controls on canvas which can eliminate all UI renderers. let me show a simple example, I want to create a simple round corner Entry like below. see how much code I need to write for xamarin vs flutter.

6wSSE

Flutter way

TextField(
 decoration: new InputDecoration(
     border: new OutlineInputBorder(
       borderRadius: const BorderRadius.all(
         const Radius.circular(10.0),
       ),
     ),
     filled: true,
     hintStyle: new TextStyle(color: Colors.grey[800]),
     hintText: "Type in your text",
     fillColor: Colors.white70),
)

Xamarin Way

//UI
< controls: CustomEntry IsPassword = "True"
x: Name = "txtEmail"
Style = "{StaticResource EntryStyle}" > </controls:CustomEntry>

/ / Custom Entry
public class CustomEntry: Entry {}

//Android Shape

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" > 
    <stroke android:width="1dp" android:color="#e7e7e7" /> 
    <solid android:color="#fafafa" /> 
    <padding android:left="1dp" android:right="1dp" android:top="1dp" /> 
    <corners android:radius="5dp" />
</shape>

//Android Renderer
public class CustomEntryRenderer: EntryRenderer {
	public CustomEntryRenderer(Context context) : base(context) {
		AutoPackage = false;
	}
	protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) 
        { 
            base.OnElementChanged(e);
            if (Control != null) 
            { 
                Control.Background = Android.App.Application.Context.GetDrawable(Resource.Drawable.rounded_corners); 
                Control.Gravity = GravityFlags.CenterVertical; 
                Control.SetPadding(10, 0, 0, 0); } 
            }
        }
}

//iOS Renderer
public class CustomEntryRenderer: EntryRenderer {
	protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
		base.OnElementPropertyChanged(sender, e);
		Control.Layer.BorderWidth = 0;
		Control.BorderStyle = UITextBorderStyle.None;
	}
}

see how much code it took to show a simple round corner text field in xamarin forms vs flutter? , this is where lot of people going away from xamarin.

@saint4eva
Copy link

Xamarin is very good from a backend perspective, I can quickly build enterprise architecture patterns with ease, but when it comes to UI, I need to spend a lot of time to match UI pixel perfectly with a mockup. Please focus on the UI part that's all we want. why don't you guys use Skia Sharp to draw controls on canvas which can eliminate all UI renderers. let me show a simple example, I want to create a simple round corner Entry like below. see how much code I need to write for xamarin vs flutter.

6wSSE

Flutter way

TextField(
 decoration: new InputDecoration(
     border: new OutlineInputBorder(
       borderRadius: const BorderRadius.all(
         const Radius.circular(10.0),
       ),
     ),
     filled: true,
     hintStyle: new TextStyle(color: Colors.grey[800]),
     hintText: "Type in your text",
     fillColor: Colors.white70),
)

Xamarin Way

//UI
< controls: CustomEntry IsPassword = "True"
x: Name = "txtEmail"
Style = "{StaticResource EntryStyle}" > </controls:CustomEntry>

/ / Custom Entry
public class CustomEntry: Entry {}

//Android Shape

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" > 
    <stroke android:width="1dp" android:color="#e7e7e7" /> 
    <solid android:color="#fafafa" /> 
    <padding android:left="1dp" android:right="1dp" android:top="1dp" /> 
    <corners android:radius="5dp" />
</shape>

//Android Renderer
public class CustomEntryRenderer: EntryRenderer {
	public CustomEntryRenderer(Context context) : base(context) {
		AutoPackage = false;
	}
	protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) 
        { 
            base.OnElementChanged(e);
            if (Control != null) 
            { 
                Control.Background = Android.App.Application.Context.GetDrawable(Resource.Drawable.rounded_corners); 
                Control.Gravity = GravityFlags.CenterVertical; 
                Control.SetPadding(10, 0, 0, 0); } 
            }
        }
}

//iOS Renderer
public class CustomEntryRenderer: EntryRenderer {
	protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
		base.OnElementPropertyChanged(sender, e);
		Control.Layer.BorderWidth = 0;
		Control.BorderStyle = UITextBorderStyle.None;
	}
}

see how much code it took to show a simple round corner text field in xamarin forms vs flutter? , this is where lot of people going away from xamarin.

Try the .NET Maui C# MVU - Comet

https://github.com/dotnet/Comet

@saint4eva
Copy link

I've been developing with Xamarin.Forms since its inception. Every client I've worked for has wanted as close to an identical UI as possible on all target platforms. Clients do not want or need native controls/widgets/views to be rendered typically. It is a rare edge case. All clients I've worked for have adopted Xamarin because existing .NET developers could use C#/.NET to build mobile apps, while being able to consume existing libraries without reinventing the wheel. Clients and developers I've spoken to want Microsoft to ditch the native UI approach, and to emulate the Flutter and UNO approach of rendering controls independently of the constraints of the platform. The majority of development time is spent trying to tweak the UI to make it look identical on both platforms for current Xamarin developers. With the release of Flutter 2.2, it is becoming increasingly difficult to rationalize further investment in MAUI until this becomes THE primary architecture for the platform. Mimicking the Flutter/UNO approach highly simplifies the development process on your end, and working prototypes are already alive and well that should be used to accelerate development. This is where developers want MS and the MAUI/Xamarin team to invest in. The holy grail for developers is for MS to emulate Flutter's architecture while giving we developers the massive advantage of being able to continue to use .NET and C# so we don't have to reinvent the wheel by rewriting libraries in an immature language like Dart. Finally, Microsoft is investing in working with Google to allow Flutter to target Windows.. MS should instead be investing in competing directly with Google by building MAUI the way its veteran developers want. If MAUI goes native UI first at launch, it will be obsolete the day it is released. If this happens, after seven years of using Xamarin/.NET to develop mobile apps, I will move on and invest in Flutter instead, because at least Google has its head on straight enough to build the tools we want and need.

MAUI C# MVU - Comet. Also, .NET Maui will have support for drawn UI using GraphicsControl

https://github.com/dotnet/Comet

https://github.com/dotnet/Microsoft.Maui.Graphics.Controls

https://github.com/dotnet/Microsoft.Maui.Graphics

@GalaxiaGuy
Copy link
Contributor

I've seen this conversation happening in a few places, and I thought I'd share my own experience (despite the fact the plural of "anecdote" is not "data").

This does not match my experience with Xamarin. The clients I've worked with have mostly fallen into two categories:

Those that don't care about the UI details. Pixel perfect UI is not interesting to them compared to delivering functionality. For them, sharing business logic between platforms (and sometimes with a C# server) that can be delivered quickly is number one priority.

Those that want a native looking app. Most of these have avoided Forms (for example because they want to use native navigation patterns (Android supports a lot more patterns that are a challenge on iOS)). This has started to change now with some Forms embedding and the fact that I can use effects to apply some existing native styling code to Forms controls has made that much easier.

A final note that is finally getting more attention is accessibility. I've just started to scratch the surface of advanced accessibility stuff iOS and Android support natively, and being able to get access to that (even in Forms) is important. Re-implementing controls would involve a lot of work on that front.

(Bit of a cheap shot, but do your designers who care about the pixels being perfect for sighted users care about the screenreader announcements being perfect for blind users?)

@Jure-BB
Copy link

Jure-BB commented May 21, 2021

A final note that is finally getting more attention is accessibility. I've just started to scratch the surface of advanced accessibility stuff iOS and Android support natively, and being able to get access to that (even in Forms) is important. Re-implementing controls would involve a lot of work on that front.

(Bit of a cheap shot, but do your designers who care about the pixels being perfect for sighted users care about the screenreader announcements being perfect for blind users?)

Yes, accessibility is important. Issue with current platform specific controls is that they are highly coupled by design. Single control can contain behavior logic, drawing logic, user input handling and accessibility all tied to a single platform APIs. Customizing just a single aspect of a control in a multiplatform application means re-implementing same thing multiple times with vastly different APIs.

Providing unified abstractions over lower-level platform APIs and building controls on top, gives multiplatform developers ability to customize controls at much lower cost. Unified APIs enable developers to implement, for example, customized drawing or customized reactions to scroll input only once, instead of writing separate implementation for each platform.

Even though the cost of developing framework like this is higher in the beginning, the cost in the long run is probably smaller, as creating and maintaining loosely coupled multiplatform controls is much more cost effective for framework developers too. Look how basic Xamarin.Forms controls still are after so many years and how quickly Flutter controls are evolving. Most of Xamarin.Forms controls implement only functionality that is common on all platforms and are often missing functionality that is provided just by a single vendor. For controls build on top of unified abstractions of low-level APIs, this becomes a non-issue. Every functionality implemented in a control is instantly avaliable on all platforms. Framework controls also don't need to lag behind platform specific controls anymore, as framework can provide even controls or functionality that is not avaliable in any platform's UI framework.

If there is any issue with providing accessibility features for custom-drawn controls, it is up to platform vendors to provide better APIs for this kind of multiplatform frameworks.

@davidortinau davidortinau unpinned this issue May 26, 2021
@Redth Redth moved this from In progress to Done in Preview 2 Aug 5, 2021
@Redth Redth closed this as completed Sep 20, 2021
@dotnet dotnet deleted a comment from Rand-Random Jan 16, 2022
@dotnet dotnet deleted a comment from Solaiman100 Jan 16, 2022
@dotnet dotnet locked as resolved and limited conversation to collaborators Feb 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

No branches or pull requests