AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
25.64k stars 2.22k forks source link

Discussion: Compatibility with WPF, UWP and WinUI #5196

Closed robloo closed 3 years ago

robloo commented 3 years ago

Discussion: Compatibility with WPF, UWP and WinUI

I'm sure the core maintainers have ideas for improving compatiblity with the various XAML UI frameworks and dialects over time. Aside from WPF compatibility, I have not seen a full strategy summarized or discussed though so thought I would create this issue to better define things. The goal is really to have a clear and long-term strategy for:

  1. Defining how the Avalonia XAML and object model fits with the overall ecosystem
  2. Improving Avalonia compatiblity with WPF and UWP/WinUI
  3. Bringing more features from WPF/WinUI/UWP into Avalonia (that do not already have a better replacement)
  4. Defining the strategy for bringing over controls from both UWP, WinUI and other libraries

Defining how the Avalonia XAML and object model fits with the overall ecosystem

Avalonia uses a XAML dialect and object model closer to WPF. I gather this is mostly for historic reasons as Avalonia originated around the same time as UWP first appeared. It has also been stated several times that Avalonia is most compatible with WPF and the goal is to reduce the differences with WPF even further over time. However, Avalonia is already diverging in some key areas where UWP/WinUI make more sense (touch input). I considered for a while:

We are getting a lot of XAML dialects now, do all of these still make sense? (no… some like MAUI do not).

While being directly tied to either the WPF or WinUI object model would be great for compatibility, code sharing and even porting existing Windows apps to Avalonia, I do think it would hold the framework back long-term. A lot of good ideas exist in Avalonia that likely never will make it to WinUI for one reason or another. It's not a good idea to hold Avalonia back by Microsoft's development speed or direction (which has been strongly criticized over the last several years).

Improving Avalonia compatiblity with WPF and UWP/WinUI

So it seems Avalonia will never be a 1:1 clone of WPF, UWP or WinUI -- and it shouldn't be. The current approach of 'take what works best' should continue and ensure Avalonia is the best of both worlds. However, there still exists an opportunity (and need) to create compatiblity layers. Further combability is needed for apps that must target Window's native UI but also need to explore cross-platform support with Avalonia. Code-reuse is critically important to reduce costs and the maintenance burden long-term.

As the UI layer of UWP is turning into WinUI 3, there are only two compatibility layers that need to be considered:

Practically speaking, the goal of these compatiblity layers should not be to ensure WPF/WinUI code can run unmodified in Avalonia. Although that is a good target to shoot for it very likely is not possible without making unwanted changes to Avalonia itself. Instead, these compatiblity layers should implement functionality on top of Avalonia to make code sharing and porting easier between the various XAML frameworks. Conditional code, conditional XAML, namespace changes, etc will still be required but the compatiblity packs will make it possible to maintain a single code base that targets Avalonia+WPF or Avalonia+WinUI.

Conclusion

Putting it all together I think a good compatiblity strategy includes the following:

  1. Avalonia XAML / Object Model is and always will be its own dialect
    • This ensures Avalonia always uses the best ideas and is not tied down by past thinking or Microsoft’s development speed/direction
    • Wherever possible it should be a superset of existing WPF/WinUI concepts (but not as a sacrifice of functionality)
  2. Compatiblity layers should be planned for both WPF and WinUI
    • Separate Nugets from Avalonia itself (one for WPF, one for WinUI)
    • Support WPF and WinUI styling
    • Support DependencyProperty, DependencyObject, Visibility Enum, etc.
    • Derive some common controls from existing Avalonia ones: ListView : ListBox
    • Consider supporting the Microsoft.UI.Xaml namespaces with stubs forwarding to Avalonia-namespace controls. This would likely require code generation to really be practical and maintainable as enums and other classes/structs besides controls themselves would also have to move to the Microsoft namespaces.
      1. Avalonia XAML will default to following WPF concepts (where it does not hold things back)
        • This is for historic reasons (as Avalonia was based on WPF ideas in the beginning before UWP was widespread)
        • WPF is still considerably more powerful than UWP/WinUI in several areas
        • WinUI concepts will still be adopted where it makes sense to future-proof the design (touch input for example)
      2. Controls in Avalonia can follow a different strategy from compatiblity packs
    • Avalonia can essentially support all controls in WPF and UWP without much overlap and probably should out-of-the-box. This would ensure a lot of code re-use right away (without Compatiblity layers). For the most part Avalonia is already doing this bringing over controls from both WPF (TabControl) and UWP (DatePicker, etc.).
    • Avalonia should really only support the standard XAML controls Microsoft supports. Other controls – even some good ideas – should still be handled by third parties. This is a practical compromise considering the maintenance burden with dozens of controls.

Also see

grokys commented 3 years ago

Hi @robloo, thanks for starting this discussion.

I think you've got it pretty much spot on here. If I could go back in time there are definitely things I'd do to make Avalonia's API closer to WPF/UWP (FrameworkElement/UIElement etc - even though IMO this class separation is pretty much arbitrary and doesn't make much sense) but we've come too far now and I'm not sure that breaking existing Avalonia applications for slightly more WPF/UWP compatibility is a tradeoff we'd want to make.

I'm a bit time-limited right now, so I'll try to expand on the ideas below a little, but here's some initial thoughts:

Compatibility Layers

Regarding the compatibility layers you mentioned, there are a number of approaches we could take here that I can think of:

  1. Fork WPF and replace its win32 specific usages with Avalonia's backend code. This would be a very large project and we're not sure of the feasibility of it. WPF kinda assumes win32 throughout. Needs investigation - I did try a little while back but at that point I couldn't even get WPF itself building. This would result in separate "islands" running pretty much separate code, where you'd have a section of the app which is "WPF" and only a few things could be shared (probably layout and data context but not e.g. themes etc).
  2. Take WPF's API and see if we can implement Avalonia's interfaces on top of it. For example, make FrameworkElement implement IControl. This might be even more difficult than 1, but if possible would result in a tighter integration of the two worlds
  3. Add a compatibility library for easier porting. We could start off with an implementation of DependencyProperty which integrates with our AvaloniaProperty API. This is definitely possible and likely will appear at some point in the near future. I don't know how deep we could go with this, for example I don't really want to support both the Visibility enum and IsVisible property as that would be confusing. Maybe some concept of "attached properties" in XAML would help here in XAML but that's not going to help in code until C# adds attached properties.

New APIs/Breaking Existing APIs

We generally try to follow WPF's API when implementing something new that exists there and we try not to break Avalonia APIs where possible. I have questions about how strictly should we follow this? For example:

robloo commented 3 years ago

@grokys Great comments! This discussion could really branch out in almost any direction to quite some depth so I'll just focus on some of the things you said. I think each of the specific examples you brought up below deserve more discussion and would like to open up separate issues for each.

I'd do to make Avalonia's API closer to WPF/UWP (FrameworkElement/UIElement etc - even though IMO this class separation is pretty much arbitrary and doesn't make much sense) but we've come too far now and I'm not sure that breaking existing Avalonia applications for slightly more WPF/UWP compatibility is a tradeoff we'd want to make.

I definitely agree with this sentiment in general. We'll see if in practice there are some things that can be done to make it easier. Overall though, I'm a big fan of the changes you made. The only struggle is there is a lot of existing windows code and libraries.

  1. Fork WPF and replace its win32 specific usages with Avalonia's backend code

I realize that has been talked about for a while now and it's a really cool idea I wouldn't discount in any way. However, it is really a whole new project so I would consider it slightly out of scope from improving Avalonia itself. As I understand it, it is essentially running WPF on top of Avalonia's platform-specific rendering and input capabilities. This would be an extremely valuable project and you would probably get a lot of existing customers that way.

From a business standpoint this is also very interesting to consider and even Microsoft might find it valuable in the future. You might even be able to get outside investment to increase manpower to support this (Xamarin did as much when they broke away from Novell). The market for cross-platform WPF with no code changes is quite large (but dwindling as companies move to cross-platform frameworks).

Also, WPF's support for more modern features like touch-input, inking is something that still should be improved. Microsoft already did a bit of this but moving to a UWP API might be possible side-by-side with existing input events.

Anyway, I would still consider this a sister project to Avalonia itself (if started though it could quickly outpace Avalonia today). Avalonia's version of XAML and its object model should continue for the obvious benefits it brings (namely better and more modern features). I say that from a developer perspective.

  1. Take WPF's API and see if we can implement Avalonia's interfaces on top of it. For example, make FrameworkElement implement IControl

I think this could be step number two of the first idea. Get WPF running on Avalonia's rendering system first, then consider more tightly integrating the two (of course some level of integration will be required to get the first part done). As you said, this is likely a lot of work and apps may not leverage it choosing either: (1) run full WPF or (2) run with normal Avalonia.'

  1. Add a compatibility library for easier porting.

I think this is needed regardless of any of the other ideas for two reasons (1) WinUI differs from WPF and a WinUI-specific compatiblity layer would still be needed. (2) It can be done much more quickly providing support for apps to attempt to target Avalonia+WPF / Avalonia+WinUI in the near future.

Again, the goal of these compatiblity libraries is not for 1:1 code compatiblity. It is however to make code sharing sane using approaches like conditional code (#if directive). Right now the number of changes seems too high and it would be better to separate the code entirely to avoid errors. The cost of maintaining two separate code bases then goes up though.

We generally try to follow WPF's API when implementing something new that exists there and we try not to break Avalonia APIs where possible. I have questions about how strictly should we follow this?

I think this strategy has already been decided and its correct -- it's done case-by-case. As much as I would like drop-in code compatiblity, for the good of the framework we need to keep the future in mind and accept change for the better. This means breaking changes from WPF or even Avalonia when necessary. In practice this is a tough thing to balance though -- adding new functionality while maintaining as much compatiblity as possible. It's something GTK for example struggles with. Microsoft struggles with the opposite -- refusing to make breaking changes even when developers need them to improve efficiency or to modernize.

For the other points and examples I think they deserve more detail. Instead of getting lost in a general strategy discussion, I'll create new issues for them or add to existing ones.

robloo commented 3 years ago

@grokys Would you be kind enough to move this to Discussions? Would get rid of an open issue that isn't really an issue.