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

[Sample] "SubModelSelectedItem" StaticVM equivalent? (+ a new sample proposition) #613

Closed
YkTru opened this issue Sep 16, 2024 · 9 comments

Comments

@YkTru
Copy link

YkTru commented Sep 16, 2024

Hello,

From this sample, I can't get a Static VM version to work.

I tried looking at the source code:

 static member subModelSelectedItem
      (subModelSeqBindingName : string,
       get : 'model -> 'id voption,
       set : 'id voption -> 'model -> 'msg)
      : string -> Binding<'model, 'msg> =
    Binding.SubModelSelectedItem.vopt subModelSeqBindingName
    >> Binding.addLazy (=)
    >> Binding.mapModel get
    >> Binding.mapMsgWithModel set
    >> Binding.addCaching

But I'm not sure how to translate the equivalent (especially subModelSeqBindingName : string)

Here's what I've got now:
DynamicVM
SelectedEntity“ |> Binding.subModelSelectedItem(”Entities”, (fun m -> m.Selected), Select)

StaticVM

    let selectedComponent_Binding =
        Binding.SubModelSelectedItem.vopt •???• 
        >> Binding.addLazy (=)
        >> Binding.mapModel m.Selected
        >> Binding.mapMsgWithModel •???• (why not just “mapMsg”? what's the difference?)
        >> Binding.addCaching
        >> Binding.boxT •???• (is this correct?)

Thank you very much

[edit] proposition for a new sample using Static VM + how to deal wit Union of different components (DataTemplateSelector, IValueConverter, SubModelSelectedItem)

@YkTru
Copy link
Author

YkTru commented Sep 16, 2024

@marner2 My intuitive guess would be to replace "subModelSeqBindingName : string" by ViewModelArgs is that right?

Should a SubModelSelectedItemT be added to the library, or is there another way around by composing?

@xperiandri? (I havent found any equivalent in ElmishUno )

@xperiandri
Copy link

Looks like it is not implemented correctly in ElmishUno
You need to modify subModelSelectedItem according to subModelOpt

@xperiandri
Copy link

Maybe you avoid its usage as subModelSelectedItem description suggests?

@YkTru
Copy link
Author

YkTru commented Sep 17, 2024

Do you mean this part?

  ///   Only use this if you are unable to use some kind of <c>SelectedValue</c>
  ///   or
  ///   <c>SelectedIndex</c> property with a normal <see cref="twoWay" />
  ///   binding. This binding is less type-safe. It will throw when initializing
  ///   the bindings if <paramref name="subModelSeqBindingName" />
  ///   does not correspond to a <see cref="subModelSeq" /> binding, and it will
  ///   throw at runtime if the inferred <c>'id</c> type does not match the
  ///   actual ID type used in that binding.

I didn't think of another way since I was trying to stick to the same API as the sample but for a static Vm, what would you suggest instead, Binding.SubModelT.opt or SubModelSeqKeyedT?

@YkTru YkTru changed the title [StaticVM] SubModelSelectedItem equivalent [Sample] "SubModelSelectedItem" StaticVM equivalent? ( + sample proposition ) Sep 17, 2024
@YkTru YkTru changed the title [Sample] "SubModelSelectedItem" StaticVM equivalent? ( + sample proposition ) [Sample] "SubModelSelectedItem" StaticVM equivalent? (+ a new sample proposition) Sep 17, 2024
@YkTru
Copy link
Author

YkTru commented Sep 17, 2024

I have created a simple, abstract, yet concrete example to illustrate where I am currently stuck, please feel free to edit the code:

https://github.com/YkTru/Test_SubModelSelectedItem — (Once I resolve the main issues, I plan to add a DataTemplateSelector.)

• This is the sample I am trying to partially adapt to a Static ViewModel.

• I’ve marked the sections where I am having trouble with "SelectedItem" using "###". I attempted to use SubModelSeqKeyedT without successs.
[Q1] Also, I assume I’ll need to use an IValueConverter here too (as for "SelectedItemText") to integrate pattern matching with WPF, correct?

[Q2] Since I am using Id for each component, should I be using SubModelSeqKeyed instead of SubModelT for TextBoxABC components? Any other things I might not be doing right?

[Q3] Does using a separate FsWPF file seem like a good approach to you? I’m considering creating another project named FsWPF.proj that references Core.proj instead, to serve as code-behind for behaviors, converters, DataTemplateSelector, etc. of which there are many (at least in my projects). Do you see a more "Elmish/Elm/FP" way to handle or interact with these WPF features?

[Q4] I think that once this sample is refined and corrected, it could offer valuable insights into several Elmish.WPF features—particularly a more complete example of how to use a Static VM—compared to the more basic sample, as well as the interaction with WPF using unions. What’s your opinion?

Thank you.

@YkTru YkTru closed this as completed Sep 17, 2024
@YkTru YkTru reopened this Sep 17, 2024
@YkTru
Copy link
Author

YkTru commented Sep 17, 2024

[update] In a desperate attempt, I tried to only bind to a single element as in the SubModelSelectedItem sample but still, at runtime, when I select any TextBoxA the border of the ListView goes red and nothing happens.

    type Model = {
        Id: Guid
        Components: Components list
        SelectedComponent: Guid option

        ATextBoxes: TextBoxA.Model list //# single Model

        TextBoxA_Model: TextBoxA.Model
        TextBoxB_Model: TextBoxB.Model
        TextBoxC_Model: TextBoxC.Model
    }

    // Sample: "SelectedEntity" |> Binding.subModelSelectedItem("Entities", (fun m -> m.Selected), Select)    
    let findTextBoxAById id components =
        components
        |> List.choose (function
            | Form.TextBoxA a when a.Id = id -> Some a
            | _ -> None)

    let selectedTextBoxAItem_Binding =
        Binding.SubModelSeqKeyedT.id TextBoxA_VM _.Id
        >> Binding.mapModel (fun (model: Form.Model) ->
            match model.SelectedComponent with
            | Some selectedId -> 
                findTextBoxAById selectedId model.Components
            | None -> []
        )
        >> Binding.mapMsg (fun (guid, msg) -> Form.Select (Some guid))    

member _.SelectedAItem
     with get() = base.Get() selectedTextBoxAItem_Binding
     and set(v) = base.Set(v) selectedTextBoxAItem_Binding

<ListView
    Height="400"
    HorizontalContentAlignment="Center"
    ItemsSource="{Binding Components}"
    SelectedItem="{Binding SelectedAItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

@marner2
Copy link
Collaborator

marner2 commented Sep 17, 2024

I don't have much time to review stuff in too much detail at the moment, but remember that in general "old-style" bindings work with the new static view models. They just cast your property to obj which only matters for intellisense. The subModelSeqBindingName argument would in this case be the actual name of the list property (use nameof if you can).

I can review this in more detail at a later point. Let me know if this helps.

I had originally avoided migrating this binding because of weird caveats with types, and the fact that the old one works just fine beings it's kind of a band-aid the way it is.

@YkTru
Copy link
Author

YkTru commented Sep 19, 2024

[update] I finally was able to pattern match submodels on a parent model, using a mix ("band-aid") of static and dynamic bindings as you proposed. (I haven't pushed yet, since I want to add a DataTemplateSelector)

@marner2: Do you think it would be worth opening a PR to propose this as a sample once I add the DataTemplateSelector? It could demonstrate some ElmishWPF techniques on how to build a basic form designer using pattern matching for different components/submodels. (In fact, I think it would be a good extension of the subModelSelectItem sample without adding too much complexity or cognitive overload.)

Whenever you have time, could you please update the "old-style" bindings in the PR sample to an entirely newer/modern static bindings style? (also, #606 (comment), you were looking to eventually revise the static bindings approach/helpers?

"In fact, I'm tempted to remove the model ones as you can always introduce it with a call to Bindings.mapMsgWithModel and just disregard the original msg (which is the obj parameter).
I'll try to look at that in more detail in the next few weeks, as I have time."

Thank you

@YkTru
Copy link
Author

YkTru commented Sep 19, 2024

(I made a PR)

@YkTru YkTru closed this as completed Sep 19, 2024
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

3 participants