canton7 / Stylet

A very lightweight but powerful ViewModel-First MVVM framework for WPF for .NET Framework and .NET Core, inspired by Caliburn.Micro.
MIT License
988 stars 143 forks source link

Separation of ViewModel and View classes within Stylet #151

Closed haven1433 closed 4 years ago

haven1433 commented 4 years ago

It makes sense that my ViewModel would have access to the IWindowManager interface. But it seems strange that it has access to the WindowManager class. I'd prefer that my ViewModel's assembly not have references to any specific View types, making it easier to extend the app with a new View in the future.

Is it possible to break Stylet into two assemblies, one meant to be referenced by a ViewModel assembly (containing interfaces as well as the utility types such as Screen), and one meant to be referenced by View assemblies (containing things that the ViewModel shouldn't know about, such as the IoC types and the MessageBoxView)?

Would I be able to provide a pull request to add this separation, or would I need to create a fork?

canton7 commented 4 years ago

I'd prefer that my ViewModel's assembly not have references to any specific View types, making it easier to extend the app with a new View in the future.

I know that this is thrown around as an advantage of MVVM, but I've never seen it actually happen in practice. Like it or not, the VM always ends up being specifically designed to support its View. It's very unlikely that you'll end up with a different set of views, but have exactly the same number, and each has exactly the same fields. In situations where you have two UIs, that's typically for something like mobile/desktop or mobile/tablet, and the set of screens, their flow, and their contents are necessarily different.

For this reason I've always put the views and VMs together, next to each other in the same project, and I see a lot of other people doing the same.

I've had a request to split Stylet into 2 assemblies, where one references PresentationFramework and the other doesn't. Unfortunately this isn't possible, as Screen references UIElement (as part of IViewAware).

I'm somewhat reluctant to introduce this large of a breaking change (and the required version bump to 2.0) on the request of a single person, for a reason that I think is fundamentally flawed, I'm afraid.

haven1433 commented 4 years ago

I've had a request to split Stylet into 2 assemblies, where one references PresentationFramework and the other doesn't. Unfortunately this isn't possible, as Screen references UIElement (as part of IViewAware).

This is basically what I'm asking for. So I guess you can now say you've had 2 people ask for this :).

In situations where you have two UIs, that's typically for something like mobile/desktop or mobile/tablet, and the set of screens, their flow, and their contents are necessarily different.

Honestly, the future I'm most concerned about is a move to WinUI3 or Avalonia. It's a switch to a separate technology, not a new platform. In this case, I'd actually very much like to reuse the same ViewModel if at all possible, because I'd want the UI to be as close as possible to the original. It's my fear of changing technologies like this that make me want my ViewModel to be isolated from view-specific classes and references such as PresentationFramework.

I understand that this would be a breaking change and version bump, which is why I thought a fork might be necessary. Thanks for bringing up the issue with IViewAware / UIElement, I'll probably have to either rip it out or add an abstraction layer where the user still has access to the UI classes, but at their own risk instead of forced by the framework.

Thanks for building such a cool tool :) do you have any recommendations on naming if I go forward with a fork?

canton7 commented 4 years ago

Honestly, the future I'm most concerned about is a move to WinUI3 or Avalonia.

In that case, there's not much point deriving from Screen: most of the functionality it provides relies on Stylet being in charge of things. If you switch to Avalonia, almost none of that stuff will work. Really your only option is to use your own ViewModel base class, which doesn't provide any of the extra stuff that Stylet and Avalonia give you.

I doubt any of the other Stylet types -- IWindowManager, etc -- will work in an Avalonia world either. If you really want a set of ViewModels which work across both technologies, you're going to have to define your own abstractions, and then write a set of adapters for Stylet and Avalonia. The Stylet adapters can live in your Stylet-specific assembly, which means there's no point in splitting Stylet in two.

I really do think you're putting your effort in the wrong place here. Switching out one half of the presentation layer to use a different technology is a bit like switching your database: it's technically possible if you've got the right abstractions in place, but 1) it very rarely happens, and 2) it's significantly more effort than you'd think. Pick the right technology at this point and commit to it. If you need to change it later, that's fine: you'll need to rewrite a bunch of stuff, but you were going to have to rewrite it anyway, and at least you don't have to undo a bunch of almost-certainly-incorrect abstractions in the process. In order words, compared to the pain of switching UI technology, moving some types between a couple of assemblies is not a significant cost.

do you have any recommendations on naming if I go forward with a fork?

If it's just for you, I'd rather you kept it to yourself 🙂. If you want to go ahead and publish something, please don't use the Stylet name or branding, to avoid confusion.