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

Elmish.WPF vs Elmish.Uno #364

Open
TysonMN opened this issue Mar 6, 2021 · 14 comments
Open

Elmish.WPF vs Elmish.Uno #364

TysonMN opened this issue Mar 6, 2021 · 14 comments

Comments

@TysonMN
Copy link
Member

TysonMN commented Mar 6, 2021

I just discovered that @xperiandri forked Elmish.WPF to create Elmish.Uno. That is great!

I don't know anything about Uno, but I have long thought that much of the code in Elmish.WPF should work for other Microsoft UI frameworks like UWP.

@xperiandri, if you don't mind, could you explain what Uno is and what code differences there are between Elmish.WPF and Elmish.Uno?

@xperiandri
Copy link

There are 2 main limitations of UWP (which is base of Uno):

  1. You don't create the first window explicitly, creating an application means creating a window.
  2. UWP does not support F# as the head project until it is integrated with WinUI in September-October 2021

There are 2 main differences to WPF:

  1. UWP's primary way of changing views is Frame that displays Pages. That means that some NavigationService is required so that you can switch pages within a Frame from Elmish program. It is available in the navigation branch, which also shows how to pass a parameter with submodelless approach.
  2. Because of the second limitation you can't call any platform logic in F#. Unless you use WinUI and .NET 5. But I haven't created a fork for that yet.

Elmish.Uno repository is a direct derivative of Elmish.WPF which has around a dozen of atomic commits that migrate Elmish.WPF to be usable with Uno.
Also I added ModelTypeChanged property to ViewModel in order to determine model change when it is designed as discriminated union. Having model as discriminated union I map its name to XAML visual state name 1 to 1 and trigger change by name.

We have one Elmish.Uno pre-production project working on WASM .NET 3.1 and another preproduction project for iOS.

@xperiandri
Copy link

xperiandri commented Mar 6, 2021

There are only a few commits related to the core:

  1. ModelTypeChanged event
  2. Derived ViewModel implementation in C# for UWP https://github.com/xperiandri/Elmish.Uno/blob/navigation/src/Elmish.Uno.Uwp/ViewModel.cs . As UWP requires ICustomPropertyProvider interface implementation for Bindings to work (interop from .NET to WinRT), DynamicObject does not work. This also forced me to create a Create method that creates ViewModel instead of calling a constructor.

The other commits port samples.

@xperiandri
Copy link

The other addition I want to be implemented after migration to .NET 5 is https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Data.ISupportIncrementalLoading?view=winrt-19041

Where binding will allow to pass a command DU case that will be dispatched if incremental loading is requested

@TysonMN
Copy link
Member Author

TysonMN commented Mar 7, 2021

Interesting. Thanks for sharing all that information.

Eventually I will take a close look at your changes.

Feel free to suggest ideas that you think would make it easier for you to maintain your project.

@xperiandri
Copy link

I was managed to migrate to 3.5.7, but not to 4.0.0 (too many changes and absence of wrapDispatch)

@TysonMN
Copy link
Member Author

TysonMN commented Mar 8, 2021

Yes, we removed wrapDispatch because mapMsg is more important, and they are mutually exclusive. It makes Binding<'model, 'msg> a (covariant) functor in 'msg.

How do you want to use wrapDispatch?

@TysonMN
Copy link
Member Author

TysonMN commented Mar 8, 2021

And now I discovered that @xperiandri also forked unoplatform/Elmish.Uno, which also forked Elmish.WPF (in 2019), quickly added four commits, and has seen no changes since. Let's try to figure out a way keep the present Uno fork of Elmish.WPF going.

@xperiandri
Copy link

Yes, @jeromelaban did the first prototype on top of version 2.
And I improved it and rebased it onto version 3.

@TysonMN
Copy link
Member Author

TysonMN commented Mar 8, 2021

Microsoft's Choose your Windows app platform documentation helped me better understand the difference between WPF and Uno. In short, UWP is sort of a successor of WPF. Then Uno is an extension of UWP that adds support for "iOS, Android, macOS, Linux and WebAssembly".

@xperiandri
Copy link

How do you want to use wrapDispatch?

This is what we do now

"Phone"      |> Binding.twoWay ((function
                                 | NoneUserInfo                         -> String.Empty
                                 | EmptyUserInfo    (phone, _)
                                 | NewUserInfo      (phone, _, _, _)
                                 | ExistingUserInfo (phone, _, _, _, _) -> phone),
                                InputPhone, throttle)
[<AutoOpen>]
module Dispatching =

    open System
    open Elmish
    open FSharp.Control.Reactive

    let asDispatchWrapper<'msg> (configure: IObservable<'msg> -> IObservable<'msg>)
                          (dispatch: Dispatch<'msg>) : Dispatch<'msg> =
        let subject = Subject.broadcast
        subject |> configure |> Observable.add dispatch
        fun msg -> async.Return (subject.OnNext msg) |> Async.Start

    let throttle<'msg> = Observable.throttle (TimeSpan.FromMilliseconds 500.) |> asDispatchWrapper<'msg>

@TysonMN
Copy link
Member Author

TysonMN commented Mar 8, 2021

Great. It is "just" throttling. I believe this can be added in a way that is compatible with mapMsg.

@xperiandri
Copy link

UWP is sort of a successor of WPF

WPF (full pack) -> Silverlight (added VisualStates, removed a lot of stuff) -> Silverlight on WIndows Phone (added additional thread (compositional) for smooth animations) -> WinRT (rewritten in C++ as COM on steroids with much better animation stack, similar to Silverlight) -> WinUI 3 (an attempt to reduce the gap to WPF)

@xperiandri
Copy link

@TysonMN will you have time this year to discuss and agree on a plan of aligning Elmish.Uno and Elmish.WPF cores so that I can simply do rebase on Elmish.WPF when you add new features and fixes?
Agenda:

  1. Collection merge function (I need to record the difference in animation for you)
  2. INotifyDataErrorInfo implementation
  3. Extending Binding static class in order to support ISupportIncrementalLoading (probably we can simply add conditional compilation to Elmish.WPF). This is a simplest way for me to migrate to v4
  4. Elmish.Uno migration to v4 (If we fix point 2 and 3, I will just drop what I have now and use v4 code)
  5. Throttling

@TysonMN
Copy link
Member Author

TysonMN commented Nov 27, 2021

I can discuss here in GutHub almost every day. Did you have something else in mind?

Throttling shouldn't be an issue any more. The "throttling / warpDispatch API" from v3 had been added back to v4.

I am definitely sticking with the linear-time collection merge code (increase of the previous quadratic-time collection merge code).

Uno can certainly add to the binding API. Is that what you mean by item 3?

I think I understand item 2.

Re item 4, my guess is that starting over with v4 is the right move.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants