How to bind two way on SelectedItem?
I have the ItemsSource bound with a Binding.subBindingSeq.
Now SelectedItem from Datagrid return a ViewModel
I can read the value of the item model with CurrentModel, but how set the relative ViewModel in the setter?
Is this related to #63?
I don't think...
My issue is that i can't set the "ViewModel selected item" by the "model slected item".
In #63 hare used SelectedValue+SelectedValuePath, but i use Syncfusion SfDatagrid that seems to haven't this properties
@felipeleon73 If you can provide a minimal repro solution, I'm happy to take a look at it! :)
This is my repo.
The problem is in Program.fs in
let bindings model dispatch =
[
"Count" |> Binding.oneWay (fun m -> m.Count)
"Selected" |> Binding.twoWay
(fun m -> unbox m.Selected) //<-----------here is the issue! m.Selected is a Model, expect a ViewModel
(fun (v:ViewModel<_,_>) m -> Update v.CurrentModel)
"Items" |> Binding.subBindingSeq
id
(fun m -> m.Items)
(fun c -> c.Id)
itemBindings
]
Maybe i've misunderstood something in the use of subBindingSeq
Not sure if subBindingSeq is involved in your problem. You鈥檙e not supposed to work with ViewModel<_,_> as such. Try this (untested) :
F#
"Selected" |> Bindings.twoWay
(fun m -> Option.toObj m.Selected)
(fun v _ -> Update (Option.ofObj v))
There, v should be a Nullable of Item.
@JDiLenarda is partly right. AFAIK it should look like this (boxing/unboxing needed because Item can't be null, and note that we're dispatching Select, not Update):
f#
"Selected" |> Binding.twoWay
(fun m -> m.Selected |> Option.map box |> Option.toObj)
(fun v m -> v |> Option.ofObj |> Option.map unbox |> Select )
However, this throws on the last line when selecting an item, because v is of type ViewModel<_,_> at runtime. I'm not immediately sure why. I'll need to investigate. Busy the next few days if anyone else wants to have a look.
Nevermind, suddenly made sense to me. The list items are indeed ViewModel<_,_> instances because of using subBindingSeq for the ItemsSource binding. However, that means that you can't bind directly to a SelectedItem property like this. But that's not recommended anyway, because you get duplicated state in your model (if you update an item that happens to be selected, you'll have to update it in Model.Selected in addition to Model.Items).
The solution is to use SelectedIndex, which the SfDataGrid control supports.
Thanx.
The Selectedindex trick works perfectly in most cases... unless the DataGrid is filtered or sorted.
You believe it is possible to implement a mechanism to set and retrive del selected item using the unique key shared by the model and the view model?
If you sort or filter the DataGrid, I would guess the best option is to do it in the Elmish model. I.e., pass sort/filter commands to the update function, and sort/filter the collection in the model. But that requires the control to support that somehow... Which I kind of doubt it does.
Other than that, I don't have any good ideas at the moment if the control does not support SelectedValuePath or another means of specifying the model member you wish to use when selecting.
Hmm... There might be a way to use the unique key as you suggest. I need to think a bit. Busy these next days though, so can't promise when I'll get to it.
@felipeleon73, I think I found a way to achieve what you want. Please check out the subModelSelectedItem branch and use the new Binding.subModelSelectedItem. It takes care of converting from/to the model IDs, so the Elmish usage is very simple.
I have also added a dedicated sample for this binding.
Note that (as the new binding function documentation describes) it's not as type-safe as a normal twoWay binding used with SelectedValue or SelectedIndex, so those are still preferred if possible.
Let me know what you think. If you like it and it works fine for you after you have tested it, I can merge and release it.
Perfect!
Thank you very much! Today i make some test.
Really really great solution!
Works like a charm!
Will be released as 2.0.0-beta-11, currently in the pipeline.