diff --git a/src/Elmish.WPF/Binding.fs b/src/Elmish.WPF/Binding.fs index c95c56d9..87727208 100644 --- a/src/Elmish.WPF/Binding.fs +++ b/src/Elmish.WPF/Binding.fs @@ -8,2951 +8,765 @@ open System.Collections.ObjectModel module Binding = - open BindingData - - let internal mapData f binding = - { Name = binding.Name - Data = binding.Data |> f } - - /// Boxes the output parameter. - /// Allows using a strongly-typed submodel binding (from a module ending in "T") - /// in a binding list (rather than in a view model class member as normal). - let boxT (binding: Binding<'b, 'msg, 't>) = BindingData.boxT |> mapData <| binding - - /// Unboxes the output parameter - let unboxT (binding: Binding<'b, 'msg>): Binding<'b, 'msg, 't> = BindingData.unboxT |> mapData <| binding - - /// Maps the model of a binding via a contravariant mapping. - let mapModel (f: 'a -> 'b) (binding: Binding<'b, 'msg, 't>) = f |> mapModel |> mapData <| binding - - /// Maps the message of a binding with access to the model via a covariant mapping. - let mapMsgWithModel (f: 'a -> 'model -> 'b) (binding: Binding<'model, 'a, 't>) = f |> mapMsgWithModel |> mapData <| binding - - /// Maps the message of a binding via a covariant mapping. - let mapMsg (f: 'a -> 'b) (binding: Binding<'model, 'a, 't>) = f |> mapMsg |> mapData <| binding - - /// Sets the message of a binding with access to the model. - let setMsgWithModel (f: 'model -> 'b) (binding: Binding<'model, 'a, 't>) = f |> setMsgWithModel |> mapData <| binding - - /// Sets the message of a binding. - let setMsg (msg: 'b) (binding: Binding<'model, 'a, 't>) = msg |> setMsg |> mapData <| binding - - - /// Restricts the binding to models that satisfy the predicate after some model satisfies the predicate. - let addSticky (predicate: 'model -> bool) (binding: Binding<'model, 'msg, 't>) = predicate |> addSticky |> mapData <| binding - - /// - /// Adds caching to the given binding. The cache holds a single value and - /// is invalidated after the given binding raises the - /// PropertyChanged event. - /// - /// The binding to which caching is added. - let addCaching (binding: Binding<'model, 'msg, 't>) : Binding<'model, 'msg, 't> = - binding - |> mapData addCaching - - /// - /// Adds validation to the given binding using INotifyDataErrorInfo. - /// - /// Returns the errors associated with the given model. - /// The binding to which validation is added. - let addValidation (validate: 'model -> string list) (binding: Binding<'model, 'msg, 't>) : Binding<'model, 'msg, 't> = - binding - |> mapData (addValidation validate) - - /// - /// Adds laziness to the updating of the given binding. If the models are considered equal, - /// then updating of the given binding is skipped. - /// - /// Updating skipped when this function returns true. - /// The binding to which the laziness is added. - let addLazy (equals: 'model -> 'model -> bool) (binding: Binding<'model, 'msg, 't>) : Binding<'model, 'msg, 't> = - binding - |> mapData (addLazy equals) - - /// - /// Alters the message stream via the given function. - /// Ideally suited for use with Reactive Extensions. - /// - /// open FSharp.Control.Reactive - /// let delay dispatch = - /// let subject = Subject.broadcast - /// let observable = subject :> System.IObservable<_> - /// observable - /// |> Observable.delay (System.TimeSpan.FromSeconds 1.0) - /// |> Observable.subscribe dispatch - /// |> ignore - /// subject.OnNext - /// - /// // ... - /// - /// binding |> Binding.alterMsgStream delay - /// - /// - /// The function that can alter the message stream. - /// The binding of the altered message stream. - let alterMsgStream (alteration: ('b -> unit) -> 'a -> unit) (binding: Binding<'model, 'a, 't>) : Binding<'model, 'b, 't> = - binding - |> mapData (alterMsgStream alteration) - - - /// - /// Strongly-typed bindings that update the view from the model. - /// - module OneWayT = - - /// Elemental instance of a one-way binding. - let id<'a, 'msg> : string -> Binding<'a, 'msg, 'a> = - OneWay.id - |> createBindingT - - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let opt x : Binding<'a option, 'msg, System.Nullable<'a>> = - x - |> id - |> mapModel Option.toNullable - - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let vopt x : Binding<'a voption, 'msg, System.Nullable<'a>> = - x - |> id - |> mapModel ValueOption.toNullable - - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let optobj<'a, 'msg when 'a : null> : string -> Binding<'a option, 'msg, 'a> = - id<'a, 'msg> - >> mapModel Option.toObj - - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let voptobj<'a, 'msg when 'a : null> : string -> Binding<'a voption, 'msg, 'a> = - id<'a, 'msg> - >> mapModel ValueOption.toObj - - /// - /// Strongly-typed bindings that update the model from the view. - /// - module OneWayToSourceT = - - /// Elemental instance of a one-way-to-source binding. - let id<'model, 'a> : string -> Binding<'model, 'a, 'a> = - OneWayToSource.id - |> createBindingT - - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let optobj<'a, 'model when 'a : null> : string -> Binding<'model, 'a option, 'a> = - id<'model, 'a> - >> mapMsg Option.ofObj - - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let voptobj<'a, 'model when 'a : null> : string -> Binding<'model, 'a voption, 'a> = - id<'model, 'a> - >> mapMsg ValueOption.ofObj - - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let opt x : Binding<'model, 'a option, System.Nullable<'a>> = - x - |> id - |> mapMsg Option.ofNullable - - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let vopt x : Binding<'model, 'a voption, System.Nullable<'a>> = - x - |> id - |> mapMsg ValueOption.ofNullable - - /// - /// Strongly-typed bindings that update both ways - /// - module TwoWayT = - - /// Elemental instance of a two-way binding. - let id<'a> : string -> Binding<'a, 'a, 'a> = - TwoWay.id - |> createBindingT - - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let opt x : Binding<'a option, 'a option, System.Nullable<'a>> = - x - |> id - |> mapMsg Option.ofNullable - |> mapModel Option.toNullable - - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let vopt x : Binding<'a voption, 'a voption, System.Nullable<'a>> = - x - |> id - |> mapMsg ValueOption.ofNullable - |> mapModel ValueOption.toNullable - - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let optobj<'a when 'a : null> : string -> Binding<'a option, 'a option, 'a> = - id<'a> - >> mapModel Option.toObj - >> mapMsg Option.ofObj - - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let voptobj<'a when 'a : null> : string -> Binding<'a voption, 'a voption, 'a> = - id<'a> - >> mapMsg ValueOption.ofObj - >> mapModel ValueOption.toObj - - /// - /// The strongly-typed counterpart of Binding.oneWaySeq with parameter getId. - /// Exposes an ObservableCollection of child items for binding. - /// Allows a more efficient update than would be possible without using ids. - /// - module OneWaySeqT = - - /// - /// Elemental instance of a OneWaySeqT binding - /// - /// Defines whether an item is "equal" and needs to be updated if the ids are the same - /// Unique identifier for each item in the list (for efficient updates). - let id itemEquals (getId: 'a -> 'id) : string -> Binding<_, 'msg, _> = - OneWaySeq.create itemEquals getId - |> createBindingT - - /// - /// Strongly-typed bindings that dispatch messages from the view. - /// - module CmdT = + open BindingData - /// - /// Elemental instance of a Command binding. - /// Creates a Command binding that only passes the CommandParameter) - /// - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - /// Indicates whether the command can execute. - let id<'model> uiBoundCmdParam canExec - : string -> Binding<'model, obj, ICommand> = - Cmd.createWithParam - (fun p _ -> ValueSome p) - canExec - uiBoundCmdParam - |> createBindingT + let internal mapData f binding = + { Name = binding.Name + Data = binding.Data |> f } + + /// Boxes the output parameter. + /// Allows using a strongly-typed submodel binding (from a module ending in "T") + /// in a binding list (rather than in a view model class member as normal). + let boxT (binding: Binding<'b, 'msg, 't>) = BindingData.boxT |> mapData <| binding + + /// Unboxes the output parameter + let unboxT (binding: Binding<'b, 'msg>) : Binding<'b, 'msg, 't> = + BindingData.unboxT |> mapData <| binding + + /// Maps the model of a binding via a contravariant mapping. + let mapModel (f: 'a -> 'b) (binding: Binding<'b, 'msg, 't>) = f |> mapModel |> mapData <| binding + + /// Maps the message of a binding with access to the model via a covariant mapping. + let mapMsgWithModel (f: 'a -> 'model -> 'b) (binding: Binding<'model, 'a, 't>) = + f |> mapMsgWithModel |> mapData <| binding + + /// Maps the message of a binding via a covariant mapping. + let mapMsg (f: 'a -> 'b) (binding: Binding<'model, 'a, 't>) = f |> mapMsg |> mapData <| binding + + /// Sets the message of a binding with access to the model. + let setMsgWithModel (f: 'model -> 'b) (binding: Binding<'model, 'a, 't>) = + f |> setMsgWithModel |> mapData <| binding + + /// Sets the message of a binding. + let setMsg (msg: 'b) (binding: Binding<'model, 'a, 't>) = msg |> setMsg |> mapData <| binding + + + /// Restricts the binding to models that satisfy the predicate after some model satisfies the predicate. + let addSticky (predicate: 'model -> bool) (binding: Binding<'model, 'msg, 't>) = + predicate |> addSticky |> mapData <| binding /// - /// Creates a Command binding that depends only on the model (not the - /// CommandParameter). + /// Adds caching to the given binding. The cache holds a single value and + /// is invalidated after the given binding raises the + /// PropertyChanged event. /// - /// Indicates whether the command can execute. - /// Returns the message to dispatch. - let model - canExec - (exec: 'model -> 'msg) - : string -> Binding<'model, 'msg, ICommand> = - id false (fun _ m -> m |> canExec) - >> mapMsgWithModel (fun _ y -> y |> exec) - >> addLazy (fun m1 m2 -> canExec m1 = canExec m2) + /// The binding to which caching is added. + let addCaching (binding: Binding<'model, 'msg, 't>) : Binding<'model, 'msg, 't> = binding |> mapData addCaching /// - /// Creates a Command binding that dispatches the specified message. + /// Adds validation to the given binding using INotifyDataErrorInfo. /// - /// Indicates whether the command can execute. - /// The message to dispatch. - let set - canExec - (msg: 'msg) - : string -> Binding<'model, 'msg, ICommand> = - id false (fun _ m -> m |> canExec) - >> setMsg msg + /// Returns the errors associated with the given model. + /// The binding to which validation is added. + let addValidation + (validate: 'model -> string list) + (binding: Binding<'model, 'msg, 't>) + : Binding<'model, 'msg, 't> = + binding |> mapData (addValidation validate) /// - /// Creates a Command binding that depends only on the model (not the - /// CommandParameter) and always executes. + /// Adds laziness to the updating of the given binding. If the models are considered equal, + /// then updating of the given binding is skipped. /// - /// Returns the message to dispatch. - let modelAlways - (exec: 'model -> 'msg) - : string -> Binding<'model, 'msg, ICommand> = - model (fun _ -> true) exec + /// Updating skipped when this function returns true. + /// The binding to which the laziness is added. + let addLazy (equals: 'model -> 'model -> bool) (binding: Binding<'model, 'msg, 't>) : Binding<'model, 'msg, 't> = + binding |> mapData (addLazy equals) /// - /// Creates a Command binding that dispatches the specified message - /// and always executes. - /// - /// The message to dispatch. - let setAlways - (msg: 'msg) - : string -> Binding<'model, 'msg, ICommand> = - set (fun _ -> true) msg - - module OneWay = - - /// Elemental instance of a one-way binding. - let id<'a, 'msg> : string -> Binding<'a, 'msg> = - OneWay.id - |> createBinding - - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let opt<'a, 'msg> : string -> Binding<'a option, 'msg> = - id - >> mapModel Option.box - - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let vopt<'a, 'msg> : string -> Binding<'a voption, 'msg> = - id - >> mapModel ValueOption.box - - - module OneWayToSource = - - /// Elemental instance of a one-way-to-source binding. - let id<'model, 'a> : string -> Binding<'model, 'a> = - OneWayToSource.id - |> createBinding - - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let vopt<'model, 'a> : string -> Binding<'model, 'a voption> = - id<'model, obj> - >> mapMsg ValueOption.unbox - - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let opt<'model, 'a> : string -> Binding<'model, 'a option> = - id<'model, obj> - >> mapMsg Option.unbox - - - module TwoWay = - - /// Elemental instance of a two-way binding. - let id<'a> : string -> Binding<'a, 'a> = - TwoWay.id - |> createBinding - - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let vopt<'a> : string -> Binding<'a voption, 'a voption> = - id - >> mapModel ValueOption.box - >> mapMsg ValueOption.unbox - - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - let opt<'a> : string -> Binding<'a option, 'a option> = - id - >> mapModel Option.box - >> mapMsg Option.unbox - - - module SubModelSelectedItem = - - /// Creates a two-way binding to a SelectedItem-like property where - /// the ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF view - /// models to/from their corresponding IDs, so the Elmish user code only has - /// to work with the IDs. + /// Alters the message stream via the given function. + /// Ideally suited for use with Reactive Extensions. + /// + /// open FSharp.Control.Reactive + /// let delay dispatch = + /// let subject = Subject.broadcast + /// let observable = subject :> System.IObservable<_> + /// observable + /// |> Observable.delay (System.TimeSpan.FromSeconds 1.0) + /// |> Observable.subscribe dispatch + /// |> ignore + /// subject.OnNext /// - /// Only use this if you are unable to use some kind of SelectedValue - /// or SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when initializing - /// the bindings if - /// does not correspond to a binding, and it will - /// throw at runtime if the inferred 'id type does not match the - /// actual ID type used in that binding. - let vopt subModelSeqBindingName : string -> Binding<'id voption, 'id voption> = - SubModelSelectedItem.create subModelSeqBindingName - |> createBinding - >> mapModel (ValueOption.map box) - >> mapMsg (ValueOption.map unbox) - - /// Creates a two-way binding to a SelectedItem-like property where - /// the ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF view - /// models to/from their corresponding IDs, so the Elmish user code only has - /// to work with the IDs. + /// // ... /// - /// Only use this if you are unable to use some kind of SelectedValue - /// or SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when initializing - /// the bindings if - /// does not correspond to a binding, and it will - /// throw at runtime if the inferred 'id type does not match the - /// actual ID type used in that binding. - let opt subModelSeqBindingName : string -> Binding<'id option, 'id option> = - vopt subModelSeqBindingName - >> mapModel ValueOption.ofOption - >> mapMsg ValueOption.toOption - - - module Cmd = - - let internal createWithParam exec canExec autoRequery = - Cmd.createWithParam exec canExec autoRequery - |> createBinding - - let internal create exec canExec = - createWithParam - (fun _ -> exec) - (fun _ -> canExec) - false - >> addLazy (fun m1 m2 -> canExec m1 = canExec m2) - - - module OneWaySeq = + /// binding |> Binding.alterMsgStream delay + /// + /// + /// The function that can alter the message stream. + /// The binding of the altered message stream. + let alterMsgStream + (alteration: ('b -> unit) -> 'a -> unit) + (binding: Binding<'model, 'a, 't>) + : Binding<'model, 'b, 't> = + binding |> mapData (alterMsgStream alteration) - let internal create get itemEquals getId = - OneWaySeq.create itemEquals getId - |> BindingData.mapModel get - |> createBinding + /// + /// Strongly-typed bindings that update the view from the model. + /// + module OneWayT = + + /// Elemental instance of a one-way binding. + let id<'a, 'msg> : string -> Binding<'a, 'msg, 'a> = OneWay.id |> createBindingT + + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let opt x : Binding<'a option, 'msg, System.Nullable<'a>> = x |> id |> mapModel Option.toNullable + + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let vopt x : Binding<'a voption, 'msg, System.Nullable<'a>> = + x |> id |> mapModel ValueOption.toNullable + + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let optobj<'a, 'msg when 'a: null> : string -> Binding<'a option, 'msg, 'a> = + id<'a, 'msg> >> mapModel Option.toObj + + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let voptobj<'a, 'msg when 'a: null> : string -> Binding<'a voption, 'msg, 'a> = + id<'a, 'msg> >> mapModel ValueOption.toObj - module SubModel = + /// + /// Strongly-typed bindings that update the model from the view. + /// + module OneWayToSourceT = + + /// Elemental instance of a one-way-to-source binding. + let id<'model, 'a> : string -> Binding<'model, 'a, 'a> = + OneWayToSource.id |> createBindingT + + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let optobj<'a, 'model when 'a: null> : string -> Binding<'model, 'a option, 'a> = + id<'model, 'a> >> mapMsg Option.ofObj + + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let voptobj<'a, 'model when 'a: null> : string -> Binding<'model, 'a voption, 'a> = + id<'model, 'a> >> mapMsg ValueOption.ofObj + + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let opt x : Binding<'model, 'a option, System.Nullable<'a>> = x |> id |> mapMsg Option.ofNullable + + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let vopt x : Binding<'model, 'a voption, System.Nullable<'a>> = + x |> id |> mapMsg ValueOption.ofNullable /// - /// Creates a binding to a sub-model/component. You typically bind this - /// to the DataContext of a UserControl or similar. + /// Strongly-typed bindings that update both ways /// - /// Returns the bindings for the sub-model. - let vopt (bindings: unit -> Binding<'model, 'msg> list) - : string -> Binding<'model voption, 'msg> = - SubModel.create - (fun args -> DynamicViewModel<'model, 'msg>(args, bindings ())) - IViewModel.updateModel - |> createBinding + module TwoWayT = + + /// Elemental instance of a two-way binding. + let id<'a> : string -> Binding<'a, 'a, 'a> = TwoWay.id |> createBindingT + + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let opt x : Binding<'a option, 'a option, System.Nullable<'a>> = + x + |> id + |> mapMsg Option.ofNullable + |> mapModel Option.toNullable + + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let vopt x : Binding<'a voption, 'a voption, System.Nullable<'a>> = + x + |> id + |> mapMsg ValueOption.ofNullable + |> mapModel ValueOption.toNullable + + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let optobj<'a when 'a: null> : string -> Binding<'a option, 'a option, 'a> = + id<'a> + >> mapModel Option.toObj + >> mapMsg Option.ofObj + + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let voptobj<'a when 'a: null> : string -> Binding<'a voption, 'a voption, 'a> = + id<'a> + >> mapMsg ValueOption.ofObj + >> mapModel ValueOption.toObj /// - /// Creates a binding to a sub-model/component. You typically bind this - /// to the DataContext of a UserControl or similar. + /// The strongly-typed counterpart of Binding.oneWaySeq with parameter getId. + /// Exposes an ObservableCollection of child items for binding. + /// Allows a more efficient update than would be possible without using ids. /// - /// Returns the bindings for the sub-model. - let opt (bindings: unit -> Binding<'model, 'msg> list) - : string -> Binding<'model option, 'msg> = - vopt bindings - >> mapModel ValueOption.ofOption + module OneWaySeqT = + + /// + /// Elemental instance of a OneWaySeqT binding + /// + /// Defines whether an item is "equal" and needs to be updated if the ids are the same + /// Unique identifier for each item in the list (for efficient updates). + let id itemEquals (getId: 'a -> 'id) : string -> Binding<_, 'msg, _> = + OneWaySeq.create itemEquals getId + |> createBindingT /// - /// Creates a binding to a sub-model/component. You typically bind this - /// to the DataContext of a UserControl or similar. + /// Strongly-typed bindings that dispatch messages from the view. /// - /// Returns the bindings for the sub-model. - let required (bindings: unit -> Binding<'model, 'msg> list) - : string -> Binding<'model, 'msg> = - vopt bindings - >> mapModel ValueSome - - /// - /// The strongly-typed counterpart of module SubModel. - /// For creating bindings to child view models that have their own bindings. - /// Typically bound from WPF using DataContext and Binding. - /// Can be used in binding lists if boxed using . - /// - module SubModelT = - - /// Exposes an optional view model member for binding. - let opt - (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) - : (string -> Binding<'bindingModel voption, 'msg, #IViewModel<'bindingModel, 'msg>>) - = - SubModel.create createVm IViewModel.updateModel - |> createBindingT - - /// Exposes a non-optional view model member for binding. - let req - (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) - : (string -> Binding<'bindingModel, 'msg, #IViewModel<'bindingModel, 'msg>>) - = - SubModel.create createVm IViewModel.updateModel - |> createBindingT - >> mapModel ValueSome + module CmdT = + + /// + /// Elemental instance of a Command binding. + /// Creates a Command binding that only passes the CommandParameter) + /// + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + /// Indicates whether the command can execute. + let id<'model> uiBoundCmdParam canExec : string -> Binding<'model, obj, ICommand> = + Cmd.createWithParam (fun p _ -> ValueSome p) canExec uiBoundCmdParam + |> createBindingT + + /// + /// Creates a Command binding that depends only on the model (not the + /// CommandParameter). + /// + /// Indicates whether the command can execute. + /// Returns the message to dispatch. + let model canExec (exec: 'model -> 'msg) : string -> Binding<'model, 'msg, ICommand> = + id false (fun _ m -> m |> canExec) + >> mapMsgWithModel (fun _ y -> y |> exec) + >> addLazy (fun m1 m2 -> canExec m1 = canExec m2) + + /// + /// Creates a Command binding that dispatches the specified message. + /// + /// Indicates whether the command can execute. + /// The message to dispatch. + let set canExec (msg: 'msg) : string -> Binding<'model, 'msg, ICommand> = + id false (fun _ m -> m |> canExec) >> setMsg msg + + /// + /// Creates a Command binding that depends only on the model (not the + /// CommandParameter) and always executes. + /// + /// Returns the message to dispatch. + let modelAlways (exec: 'model -> 'msg) : string -> Binding<'model, 'msg, ICommand> = model (fun _ -> true) exec + + /// + /// Creates a Command binding that dispatches the specified message + /// and always executes. + /// + /// The message to dispatch. + let setAlways (msg: 'msg) : string -> Binding<'model, 'msg, ICommand> = set (fun _ -> true) msg + + module OneWay = + + /// Elemental instance of a one-way binding. + let id<'a, 'msg> : string -> Binding<'a, 'msg> = OneWay.id |> createBinding + + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let opt<'a, 'msg> : string -> Binding<'a option, 'msg> = + id >> mapModel Option.box + + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let vopt<'a, 'msg> : string -> Binding<'a voption, 'msg> = + id >> mapModel ValueOption.box + + + module OneWayToSource = + + /// Elemental instance of a one-way-to-source binding. + let id<'model, 'a> : string -> Binding<'model, 'a> = + OneWayToSource.id |> createBinding + + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let vopt<'model, 'a> : string -> Binding<'model, 'a voption> = + id<'model, obj> >> mapMsg ValueOption.unbox + + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let opt<'model, 'a> : string -> Binding<'model, 'a option> = + id<'model, obj> >> mapMsg Option.unbox + + + module TwoWay = + + /// Elemental instance of a two-way binding. + let id<'a> : string -> Binding<'a, 'a> = TwoWay.id |> createBinding + + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let vopt<'a> : string -> Binding<'a voption, 'a voption> = + id + >> mapModel ValueOption.box + >> mapMsg ValueOption.unbox + + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + let opt<'a> : string -> Binding<'a option, 'a option> = + id + >> mapModel Option.box + >> mapMsg Option.unbox + + + module SubModelSelectedItem = + + /// Creates a two-way binding to a SelectedItem-like property where + /// the ItemsSource-like property is a + /// binding. Automatically converts the dynamically created Elmish.WPF view + /// models to/from their corresponding IDs, so the Elmish user code only has + /// to work with the IDs. + /// + /// Only use this if you are unable to use some kind of SelectedValue + /// or SelectedIndex property with a normal + /// binding. This binding is less type-safe. It will throw when initializing + /// the bindings if + /// does not correspond to a binding, and it will + /// throw at runtime if the inferred 'id type does not match the + /// actual ID type used in that binding. + let vopt subModelSeqBindingName : string -> Binding<'id voption, 'id voption> = + SubModelSelectedItem.create subModelSeqBindingName + |> createBinding + >> mapModel (ValueOption.map box) + >> mapMsg (ValueOption.map unbox) + + /// Creates a two-way binding to a SelectedItem-like property where + /// the ItemsSource-like property is a + /// binding. Automatically converts the dynamically created Elmish.WPF view + /// models to/from their corresponding IDs, so the Elmish user code only has + /// to work with the IDs. + /// + /// Only use this if you are unable to use some kind of SelectedValue + /// or SelectedIndex property with a normal + /// binding. This binding is less type-safe. It will throw when initializing + /// the bindings if + /// does not correspond to a binding, and it will + /// throw at runtime if the inferred 'id type does not match the + /// actual ID type used in that binding. + let opt subModelSeqBindingName : string -> Binding<'id option, 'id option> = + vopt subModelSeqBindingName + >> mapModel ValueOption.ofOption + >> mapMsg ValueOption.toOption + + + module Cmd = + + let internal createWithParam exec canExec autoRequery = + Cmd.createWithParam exec canExec autoRequery + |> createBinding + + let internal create exec canExec = + createWithParam (fun _ -> exec) (fun _ -> canExec) false + >> addLazy (fun m1 m2 -> canExec m1 = canExec m2) + + + module OneWaySeq = + + let internal create get itemEquals getId = + OneWaySeq.create itemEquals getId + |> BindingData.mapModel get + |> createBinding + + + module SubModel = + + /// + /// Creates a binding to a sub-model/component. You typically bind this + /// to the DataContext of a UserControl or similar. + /// + /// Returns the bindings for the sub-model. + let vopt (bindings: unit -> Binding<'model, 'msg> list) : string -> Binding<'model voption, 'msg> = + SubModel.create (fun args -> DynamicViewModel<'model, 'msg>(args, bindings ())) IViewModel.updateModel + |> createBinding + + /// + /// Creates a binding to a sub-model/component. You typically bind this + /// to the DataContext of a UserControl or similar. + /// + /// Returns the bindings for the sub-model. + let opt (bindings: unit -> Binding<'model, 'msg> list) : string -> Binding<'model option, 'msg> = + vopt bindings >> mapModel ValueOption.ofOption + + /// + /// Creates a binding to a sub-model/component. You typically bind this + /// to the DataContext of a UserControl or similar. + /// + /// Returns the bindings for the sub-model. + let required (bindings: unit -> Binding<'model, 'msg> list) : string -> Binding<'model, 'msg> = + vopt bindings >> mapModel ValueSome /// - /// Exposes a 'a seq (IEnumerable<'a>) view model member for binding. - /// Used rarely; usually, you want to expose an ObservableCollection<'a> - /// using SubModelSeqKeyedT or SubModelSeqUnkeyedT. + /// The strongly-typed counterpart of module SubModel. + /// For creating bindings to child view models that have their own bindings. + /// Typically bound from WPF using DataContext and Binding. + /// Can be used in binding lists if boxed using . /// - let seq - (createVm: ViewModelArgs<'bindingModel, 'msg> -> #seq<#IViewModel<'bindingModel, 'msg>>) - : (string -> Binding<'bindingModel, 'msg, #seq<#IViewModel<'bindingModel, 'msg>>>) - = - SubModel.create createVm (fun (vms, m) -> vms |> Seq.iter (fun vm -> IViewModel.updateModel (vm, m))) - |> createBindingT - >> mapModel ValueSome - - /// - /// The strongly-typed counterpart of Binding.subModelSeq without parameter getId. - /// Exposes an ObservableCollection of child view models for binding. - /// Identifies elements by index; - /// if possible, use SubModelSeqKeyedT (which uses parameter getId) instead. - /// Typically bound from WPF using DataContext and Binding. - /// Can be used in binding lists if boxed using . - /// - module SubModelSeqUnkeyedT = + module SubModelT = + + /// Exposes an optional view model member for binding. + let opt + (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) + : (string -> Binding<'bindingModel voption, 'msg, #IViewModel<'bindingModel, 'msg>>) = + SubModel.create createVm IViewModel.updateModel + |> createBindingT + + /// Exposes a non-optional view model member for binding. + let req + (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) + : (string -> Binding<'bindingModel, 'msg, #IViewModel<'bindingModel, 'msg>>) = + SubModel.create createVm IViewModel.updateModel + |> createBindingT + >> mapModel ValueSome + + /// + /// Exposes a 'a seq (IEnumerable<'a>) view model member for binding. + /// Used rarely; usually, you want to expose an ObservableCollection<'a> + /// using SubModelSeqKeyedT or SubModelSeqUnkeyedT. + /// + let seq + (createVm: ViewModelArgs<'bindingModel, 'msg> -> #seq<#IViewModel<'bindingModel, 'msg>>) + : (string -> Binding<'bindingModel, 'msg, #seq<#IViewModel<'bindingModel, 'msg>>>) = + SubModel.create createVm (fun (vms, m) -> + vms + |> Seq.iter (fun vm -> IViewModel.updateModel (vm, m))) + |> createBindingT + >> mapModel ValueSome /// - /// Creates an elemental SubModelSeqUnkeyedT binding. + /// The strongly-typed counterpart of Binding.subModelSeq without parameter getId. + /// Exposes an ObservableCollection of child view models for binding. + /// Identifies elements by index; + /// if possible, use SubModelSeqKeyedT (which uses parameter getId) instead. + /// Typically bound from WPF using DataContext and Binding. + /// Can be used in binding lists if boxed using . /// - /// - /// The function applied to every element of the bound ObservableCollection - /// to create a child view model. - /// - let id - (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) - : (string -> Binding<'bindingModelCollection, int * 'msg, ObservableCollection<#IViewModel<'bindingModel, 'msg>>>) - = - SubModelSeqUnkeyed.create createVm IViewModel.updateModel - |> createBindingT - - /// - /// The strongly-typed counterpart of Binding.subModelSeq with parameter getId. - /// Exposes an ObservableCollection of child view models for binding. - /// Typically bound from WPF using DataContext and Binding. - /// Can be used in binding lists if boxed using . - /// - module SubModelSeqKeyedT = + module SubModelSeqUnkeyedT = + + /// + /// Creates an elemental SubModelSeqUnkeyedT binding. + /// + /// + /// The function applied to every element of the bound ObservableCollection + /// to create a child view model. + /// + let id + (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) + : (string -> Binding<'bindingModelCollection, int * 'msg, ObservableCollection<#IViewModel<'bindingModel, 'msg>>>) = + SubModelSeqUnkeyed.create createVm IViewModel.updateModel + |> createBindingT /// - /// Creates an elemental SubModelSeqUnkeyedT binding. + /// The strongly-typed counterpart of Binding.subModelSeq with parameter getId. + /// Exposes an ObservableCollection of child view models for binding. + /// Typically bound from WPF using DataContext and Binding. + /// Can be used in binding lists if boxed using . /// - /// - /// The function applied to every element of the bound ObservableCollection - /// to create a child view model. - /// - /// - /// The function applied to every element of the bound ObservableCollection - /// to get a key used to identify that element. - /// Should not return duplicate keys for different elements. - /// - let id - (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) - (getId: 'bindingModel -> 'id) - : (string -> Binding<'bindingModelCollection, 'id * 'msg, ObservableCollection<#IViewModel<'bindingModel, 'msg>>>) - = - SubModelSeqKeyed.create createVm IViewModel.updateModel getId (IViewModel.currentModel >> getId) - |> createBindingT - - /// - /// The strongly-typed counterpart of Binding.subModelWin. - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (either in code - /// or in XAML). - /// - /// Can be used in binding lists if boxed using . - /// - module SubModelWinT = + module SubModelSeqKeyedT = + + /// + /// Creates an elemental SubModelSeqUnkeyedT binding. + /// + /// + /// The function applied to every element of the bound ObservableCollection + /// to create a child view model. + /// + /// + /// The function applied to every element of the bound ObservableCollection + /// to get a key used to identify that element. + /// Should not return duplicate keys for different elements. + /// + let id + (createVm: ViewModelArgs<'bindingModel, 'msg> -> #IViewModel<'bindingModel, 'msg>) + (getId: 'bindingModel -> 'id) + : (string -> Binding<'bindingModelCollection, 'id * 'msg, ObservableCollection<#IViewModel<'bindingModel, 'msg>>>) = + SubModelSeqKeyed.create createVm IViewModel.updateModel getId (IViewModel.currentModel >> getId) + |> createBindingT /// - /// Creates an elemental SubModelWinT binding. + /// The strongly-typed counterpart of Binding.subModelWin. /// Like , but uses the WindowState wrapper /// to show/hide/close a new window that will have the specified bindings as /// its DataContext. /// /// You do not need to set the DataContext yourself (either in code /// or in XAML). - /// The window can only be closed/hidden by changing the return value of - /// , and cannot be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it - /// or displaying relevant feedback to the user). + /// + /// Can be used in binding lists if boxed using . /// - /// Gets the window state and a sub-model. - /// Returns the view model for the window. - /// - /// The function used to get and configure the window. - /// - /// - /// Specifies whether the window will be shown modally (using - /// Window.ShowDialog, blocking the rest of the app) or non-modally (using - /// Window.Show). - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - let id - (getState: 'model -> WindowState<'bindingModel>) - (createVM: ViewModelArgs<'bindingModel, 'bindingMsg> -> #IViewModel<'bindingModel, 'bindingMsg>) - getWindow isModal onCloseRequested = - SubModelWin.create getState createVM IViewModel.updateModel Func2.id2 getWindow isModal onCloseRequested - |> createBindingT - + module SubModelWinT = + + /// + /// Creates an elemental SubModelWinT binding. + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (either in code + /// or in XAML). + /// The window can only be closed/hidden by changing the return value of + /// , and cannot be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it + /// or displaying relevant feedback to the user). + /// + /// Gets the window state and a sub-model. + /// Returns the view model for the window. + /// + /// The function used to get and configure the window. + /// + /// + /// Specifies whether the window will be shown modally (using + /// Window.ShowDialog, blocking the rest of the app) or non-modally (using + /// Window.Show). + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + let id + (getState: 'model -> WindowState<'bindingModel>) + (createVM: ViewModelArgs<'bindingModel, 'bindingMsg> -> #IViewModel<'bindingModel, 'bindingMsg>) + getWindow + isModal + onCloseRequested + = + SubModelWin.create getState createVM IViewModel.updateModel Func2.id2 getWindow isModal onCloseRequested + |> createBindingT + + + module SelectedIndex = + /// Prebuilt binding intended for use with Selector.SelectedIndex. + let vopt = + TwoWay.id + >> mapModel (ValueOption.defaultValue -1) + >> mapMsg (fun i -> if i < 0 then ValueNone else ValueSome i) + + /// Prebuilt binding intended for use with Selector.SelectedIndex. + let opt = + vopt + >> mapModel ValueOption.ofOption + >> mapMsg ValueOption.toOption + + + module SubModelWin = + + let internal create getState createViewModel updateViewModel toMsg getWindow isModal onCloseRequested = + SubModelWin.create getState createViewModel updateViewModel toMsg getWindow isModal onCloseRequested + |> createBinding + + + module SubModelSeqUnkeyed = + + let internal create createViewModel updateViewModel = + SubModelSeqUnkeyed.create createViewModel updateViewModel + |> createBinding + + + module SubModelSeqKeyed = + + let internal create createViewModel updateViewModel bmToId vmToId = + SubModelSeqKeyed.create createViewModel updateViewModel bmToId vmToId + |> createBinding - module SelectedIndex = - /// Prebuilt binding intended for use with Selector.SelectedIndex. - let vopt = - TwoWay.id - >> mapModel (ValueOption.defaultValue -1) - >> mapMsg (fun i -> if i < 0 then ValueNone else ValueSome i) - - /// Prebuilt binding intended for use with Selector.SelectedIndex. - let opt = - vopt - >> mapModel ValueOption.ofOption - >> mapMsg ValueOption.toOption +module Bindings = - module SubModelWin = + /// Maps the model of a list of bindings via a contravariant mapping. + let mapModel (f: 'a -> 'b) (bindings: Binding<'b, 'msg> list) = + f |> Binding.mapModel |> List.map <| bindings - let internal create getState createViewModel updateViewModel toMsg getWindow isModal onCloseRequested = - SubModelWin.create getState createViewModel updateViewModel toMsg getWindow isModal onCloseRequested - |> createBinding + /// Maps the message of a list of bindings with access to the model via a covariant mapping. + let mapMsgWithModel (f: 'a -> 'model -> 'b) (bindings: Binding<'model, 'a> list) = + f |> Binding.mapMsgWithModel |> List.map + <| bindings + /// Maps the message of a list of bindings via a covariant mapping. + let mapMsg (f: 'a -> 'b) (bindings: Binding<'model, 'a> list) = + f |> Binding.mapMsg |> List.map <| bindings - module SubModelSeqUnkeyed = - let internal create createViewModel updateViewModel = - SubModelSeqUnkeyed.create createViewModel updateViewModel - |> createBinding +[] +type Binding private () = + /// + /// Creates a binding intended for use with Selector.SelectedIndex. + /// + /// Gets the selected index from the model. + /// Returns the message to dispatch. + static member selectedIndex(get: 'model -> int voption, set: int voption -> 'msg) = + Binding.SelectedIndex.vopt + >> Binding.mapModel get + >> Binding.mapMsg set - module SubModelSeqKeyed = + /// + /// Creates a binding intended for use with Selector.SelectedIndex. + /// + /// Gets the selected index from the model. + /// Returns the message to dispatch. + static member selectedIndex(get: 'model -> int option, set: int option -> 'msg) = + Binding.SelectedIndex.opt + >> Binding.mapModel get + >> Binding.mapMsg set - let internal create createViewModel updateViewModel bmToId vmToId = - SubModelSeqKeyed.create createViewModel updateViewModel bmToId vmToId - |> createBinding + /// Creates a one-way binding. + /// Gets the value from the model. + static member oneWay(get: 'model -> 'a) : string -> Binding<'model, 'msg> = + Binding.OneWay.id<'a, 'msg> + >> Binding.addLazy (=) + >> Binding.mapModel get -module Bindings = - /// Maps the model of a list of bindings via a contravariant mapping. - let mapModel (f: 'a -> 'b) (bindings: Binding<'b, 'msg> list) = f |> Binding.mapModel |> List.map <| bindings + /// + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between the optional source value and an + /// unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + static member oneWayOpt(get: 'model -> 'a option) : string -> Binding<'model, 'msg> = + Binding.OneWay.opt<'a, 'msg> + >> Binding.addLazy (=) + >> Binding.mapModel get - /// Maps the message of a list of bindings with access to the model via a covariant mapping. - let mapMsgWithModel (f: 'a -> 'model -> 'b) (bindings: Binding<'model, 'a> list) = f |> Binding.mapMsgWithModel |> List.map <| bindings - /// Maps the message of a list of bindings via a covariant mapping. - let mapMsg (f: 'a -> 'b) (bindings: Binding<'model, 'a> list) = f |> Binding.mapMsg |> List.map <| bindings + /// + /// Creates a one-way binding to an optional value. The binding + /// automatically converts between the optional source value and an + /// unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + static member oneWayOpt(get: 'model -> 'a voption) : string -> Binding<'model, 'msg> = + Binding.OneWay.vopt<'a, 'msg> + >> Binding.addLazy (=) + >> Binding.mapModel get -[] -type Binding private () = + /// + /// Creates a lazily evaluated one-way binding. + /// will be called only when the output of changes, + /// as determined by . This may have better + /// performance than for expensive computations (but + /// may be less performant for non-expensive functions due to additional + /// overhead). + /// + /// Gets the value from the model. + /// + /// Indicates whether two intermediate values are equal. Good candidates are + /// elmEq and refEq. + /// + /// Transforms the value into the final type. + static member oneWayLazy + ( + get: 'model -> 'a, + equals: 'a -> 'a -> bool, + map: 'a -> 'b + ) : string -> Binding<'model, 'msg> = + Binding.OneWay.id<'b, 'msg> + >> Binding.mapModel map + >> Binding.addLazy equals + >> Binding.mapModel get + >> Binding.addCaching - /// - /// Creates a binding intended for use with Selector.SelectedIndex. - /// - /// Gets the selected index from the model. - /// Returns the message to dispatch. - static member selectedIndex - (get: 'model -> int voption, - set: int voption -> 'msg) = - Binding.SelectedIndex.vopt - >> Binding.mapModel get - >> Binding.mapMsg set - - /// - /// Creates a binding intended for use with Selector.SelectedIndex. - /// - /// Gets the selected index from the model. - /// Returns the message to dispatch. - static member selectedIndex - (get: 'model -> int option, - set: int option -> 'msg) = - Binding.SelectedIndex.opt - >> Binding.mapModel get - >> Binding.mapMsg set - - - /// Creates a one-way binding. - /// Gets the value from the model. - static member oneWay - (get: 'model -> 'a) - : string -> Binding<'model, 'msg> = - Binding.OneWay.id<'a, 'msg> - >> Binding.addLazy (=) - >> Binding.mapModel get - - - /// - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between the optional source value and an - /// unwrapped (possibly - /// null) value on the view side. - /// - /// Gets the value from the model. - static member oneWayOpt - (get: 'model -> 'a option) - : string -> Binding<'model, 'msg> = - Binding.OneWay.opt<'a, 'msg> - >> Binding.addLazy (=) - >> Binding.mapModel get - - - /// - /// Creates a one-way binding to an optional value. The binding - /// automatically converts between the optional source value and an - /// unwrapped (possibly - /// null) value on the view side. - /// - /// Gets the value from the model. - static member oneWayOpt - (get: 'model -> 'a voption) - : string -> Binding<'model, 'msg> = - Binding.OneWay.vopt<'a, 'msg> - >> Binding.addLazy (=) - >> Binding.mapModel get - - - /// - /// Creates a lazily evaluated one-way binding. - /// will be called only when the output of changes, - /// as determined by . This may have better - /// performance than for expensive computations (but - /// may be less performant for non-expensive functions due to additional - /// overhead). - /// - /// Gets the value from the model. - /// - /// Indicates whether two intermediate values are equal. Good candidates are - /// elmEq and refEq. - /// - /// Transforms the value into the final type. - static member oneWayLazy - (get: 'model -> 'a, - equals: 'a -> 'a -> bool, - map: 'a -> 'b) - : string -> Binding<'model, 'msg> = - Binding.OneWay.id<'b, 'msg> - >> Binding.mapModel map - >> Binding.addLazy equals - >> Binding.mapModel get - >> Binding.addCaching - - - /// - /// Creates a lazily evaluated one-way binding to an optional value. The - /// binding automatically converts between the optional source value and an - /// unwrapped (possibly null) value on the view side. will be called only when the output of changes, as determined by . - /// - /// This may have better performance than a non-lazy binding for expensive - /// computations (but may be less performant for non-expensive functions due - /// to additional overhead). - /// - /// Gets the intermediate value from the model. - /// - /// Indicates whether two intermediate values are equal. Good candidates are - /// elmEq and refEq. - /// - /// Transforms the intermediate value into the final - /// type. - static member oneWayOptLazy - (get: 'model -> 'a, - equals: 'a -> 'a -> bool, - map: 'a -> 'b option) - : string -> Binding<'model, 'msg> = - Binding.OneWay.opt<'b, 'msg> - >> Binding.mapModel map - >> Binding.addLazy equals - >> Binding.mapModel get - >> Binding.addCaching - - - /// - /// Creates a lazily evaluated one-way binding to an optional value. The - /// binding automatically converts between the optional source value and an - /// unwrapped (possibly null) value on the view side. will be called only when the output of changes, as determined by . - /// - /// This may have better performance than a non-lazy binding for expensive - /// computations (but may be less performant for non-expensive functions due - /// to additional overhead). - /// - /// Gets the value from the model. - /// - /// Indicates whether two intermediate values are equal. Good candidates are - /// elmEq and refEq. - /// - /// Transforms the intermediate value into the final - /// type. - static member oneWayOptLazy - (get: 'model -> 'a, - equals: 'a -> 'a -> bool, - map: 'a -> 'b voption) - : string -> Binding<'model, 'msg> = - Binding.OneWay.vopt<'b, 'msg> - >> Binding.mapModel map - >> Binding.addLazy equals - >> Binding.mapModel get - >> Binding.addCaching - - - /// Creates a one-way-to-source binding. - /// Returns the message to dispatch. - static member oneWayToSource - (set: 'a -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.OneWayToSource.id<'model, 'a> - >> Binding.mapMsgWithModel set - - /// - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - /// - /// Returns the message to dispatch. - static member oneWayToSourceOpt - (set: 'a option -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.OneWayToSource.opt - >> Binding.mapMsgWithModel set - - /// - /// Creates a one-way-to-source binding to an optional value. The binding - /// automatically converts between a missing value in the model and - /// a null value in the view. - /// - /// Returns the message to dispatch. - static member oneWayToSourceOpt - (set: 'a voption -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.OneWayToSource.vopt - >> Binding.mapMsgWithModel set - - - /// - /// Creates a one-way binding to a sequence of items, each uniquely - /// identified by the value returned by . The - /// binding will not be updated if the output of - /// does not change, as determined by . - /// The binding is backed by a persistent ObservableCollection, so - /// only changed items (as determined by ) - /// will be replaced. If the items are complex and you want them updated - /// instead of replaced, consider using . - /// - /// Gets the intermediate value from the model. - /// - /// Indicates whether two intermediate values are equal. Good candidates are - /// elmEq and refEq. - /// - /// Transforms the value into the final collection. - /// - /// Indicates whether two collection items are equal. Good candidates are - /// elmEq, refEq, or simply (=). - /// - /// Gets a unique identifier for a collection - /// item. - static member oneWaySeqLazy - (get: 'model -> 'a, - equals: 'a -> 'a -> bool, - map: 'a -> #seq<'b>, - itemEquals: 'b -> 'b -> bool, - getId: 'b -> 'id) - : string -> Binding<'model, 'msg> = - Binding.OneWaySeq.create map itemEquals getId - >> Binding.addLazy equals - >> Binding.mapModel get - - - /// - /// Creates a one-way binding to a sequence of items, each uniquely - /// identified by the value returned by . The - /// binding will not be updated if the output of - /// is referentially equal. This is the same as calling - /// with equals = refEq and - /// map = id. The binding is backed by a persistent - /// ObservableCollection, so only changed items (as determined by - /// ) will be replaced. If the items are - /// complex and you want them updated instead of replaced, consider using - /// . - /// - /// Gets the collection from the model. - /// - /// Indicates whether two collection items are equal. Good candidates are - /// elmEq, refEq, or simply (=). - /// - /// Gets a unique identifier for a collection - /// item. - static member oneWaySeq - (get: 'model -> #seq<'a>, - itemEquals: 'a -> 'a -> bool, - getId: 'a -> 'id) - : string -> Binding<'model, 'msg> = - Binding.OneWaySeq.create id itemEquals getId - >> Binding.addLazy refEq - >> Binding.mapModel get - - - /// Creates a two-way binding. - /// Gets the value from the model. - /// Returns the message to dispatch. - static member twoWay - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - - /// Creates a two-way binding. - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWay - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWay (get, set) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between the optional source value and an - /// unwrapped (possibly null) value on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - static member twoWayOpt - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - - /// - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between the optional source value and an - /// unwrapped (possibly null) value on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOpt - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOpt (get, set) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between the optional source value and an - /// unwrapped (possibly null) value on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - static member twoWayOpt - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - - /// - /// Creates a two-way binding to an optional value. The binding - /// automatically converts between the optional source value and an - /// unwrapped (possibly null) value on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOpt - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOpt (get, set) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation messages from the updated model. - /// - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> string list) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation validate - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation messages from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> string list, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> string voption) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> ValueOption.toList) - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> string voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> string option) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> Option.toList) - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> string option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> Result<'ignored, string>) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> ValueOption.ofError >> ValueOption.toList) - - /// - /// Creates a two-way binding with validation using - /// INotifyDataErrorInfo. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'model -> 'msg, - validate: 'model -> Result<'ignored, string>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation messages from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> string list) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation validate - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation messages from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> string list, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> string voption) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> ValueOption.toList) - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> string voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> string option) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> Option.toList) - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> string option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> Result<'ignored, string>) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> ValueOption.ofError >> ValueOption.toList) - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'model -> 'msg, - validate: 'model -> Result<'ignored, string>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation messages from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> string list) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation validate - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation messages from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> string list, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> string voption) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> ValueOption.toList) - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> string voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> string option) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> Option.toList) - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> string option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> Result<'ignored, string>) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addValidation (validate >> ValueOption.ofError >> ValueOption.toList) - - /// - /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts between - /// the optional source value and an unwrapped (possibly null) value - /// on the view side. - /// - /// Gets the value from the model. - /// Returns the message to dispatch. - /// - /// Returns the validation message from the updated model. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'model -> 'msg, - validate: 'model -> Result<'ignored, string>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a Command binding that depends only on the model (not the - /// CommandParameter) and can always execute. - /// - /// Returns the message to dispatch. - static member cmd - (exec: 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - (exec >> ValueSome) - (fun _ -> true) - - /// - /// Creates a Command binding that depends only on the model (not the - /// CommandParameter) and can always execute. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmd - (exec: 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmd exec - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns true. - /// - /// Returns the message to dispatch. - /// Indicates whether the command can execute. - static member cmdIf - (exec: 'model -> 'msg, - canExec: 'model -> bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - (exec >> ValueSome) - canExec - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns true. - /// - /// Returns the message to dispatch. - /// Indicates whether the command can execute. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdIf - (exec: 'model -> 'msg, - canExec: 'model -> bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdIf (exec, canExec) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns ValueSome. - /// - /// Returns the message to dispatch. - static member cmdIf - (exec: 'model -> 'msg voption) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - exec - (exec >> ValueOption.isSome) - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns ValueSome. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdIf - (exec: 'model -> 'msg voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdIf exec - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns Some. - /// - /// Returns the message to dispatch. - static member cmdIf - (exec: 'model -> 'msg option) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - (exec >> ValueOption.ofOption) - (exec >> Option.isSome) - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns Some. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdIf - (exec: 'model -> 'msg option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdIf exec - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns Ok. - /// - /// This overload allows more easily re-using the same validation functions - /// for inputs and commands. - /// - /// Returns the message to dispatch. - static member cmdIf - (exec: 'model -> Result<'msg, 'ignored>) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - (exec >> ValueOption.ofOk) - (exec >> Result.isOk) - - /// - /// Creates a conditional Command binding that depends only on the - /// model (not the CommandParameter) and can execute if - /// returns Ok. - /// - /// This overload allows more easily re-using the same validation functions - /// for inputs and commands. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdIf - (exec: 'model -> Result<'msg, 'ignored>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdIf exec - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a Command binding that depends on the - /// CommandParameter - /// and can always execute. - /// - /// Returns the message to dispatch. - static member cmdParam - (exec: obj -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p model -> exec p model |> ValueSome) - (fun _ _ -> true) - false - - /// - /// Creates a Command binding that depends on the - /// CommandParameter - /// and can always execute. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParam - (exec: obj -> 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParam exec - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a Command binding that depends on the - /// CommandParameter - /// and can execute if returns true. - /// - /// Returns the message to dispatch. - /// Indicates whether the command can execute. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - static member cmdParamIf - (exec: obj -> 'model -> 'msg, - canExec: obj -> 'model -> bool, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p m -> exec p m |> ValueSome) - canExec - (defaultArg uiBoundCmdParam false) - - /// - /// Creates a Command binding that depends on the - /// CommandParameter - /// and can execute if returns true. - /// - /// Returns the message to dispatch. - /// Indicates whether the command can execute. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> 'msg, - canExec: obj -> 'model -> bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, canExec) - >> Binding.alterMsgStream wrapDispatch - - /// - /// Creates a Command binding that depends on the - /// CommandParameter - /// and can execute if returns true. - /// - /// Returns the message to dispatch. - /// Indicates whether the command can execute. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> 'msg, - canExec: obj -> 'model -> bool, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, canExec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns ValueSome. - /// - /// Returns the message to dispatch. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - static member cmdParamIf - (exec: obj -> 'model -> 'msg voption, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - exec - (fun p m -> exec p m |> ValueOption.isSome) - (defaultArg uiBoundCmdParam false) - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns ValueSome. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> 'msg voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf exec - >> Binding.alterMsgStream wrapDispatch - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns ValueSome. - /// - /// Returns the message to dispatch. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> 'msg voption, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns Some. - /// - /// Returns the message to dispatch. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - static member cmdParamIf - (exec: obj -> 'model -> 'msg option, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p m -> exec p m |> ValueOption.ofOption) - (fun p m -> exec p m |> Option.isSome) - (defaultArg uiBoundCmdParam false) - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns Some. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> 'msg option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf exec - >> Binding.alterMsgStream wrapDispatch - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns Some. - /// - /// Returns the message to dispatch. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> 'msg option, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns Ok. - /// - /// This overload allows more easily re-using the same validation functions - /// for inputs and commands. - /// - /// Returns the message to dispatch. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - static member cmdParamIf - (exec: obj -> 'model -> Result<'msg, 'ignored>, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p m -> exec p m |> ValueOption.ofOk) - (fun p m -> exec p m |> Result.isOk) - (defaultArg uiBoundCmdParam false) - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns Ok. - /// - /// This overload allows more easily re-using the same validation functions - /// for inputs and commands. - /// - /// Returns the message to dispatch. - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> Result<'msg, 'ignored>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf exec - >> Binding.alterMsgStream wrapDispatch - - /// - /// Creates a conditional Command binding that depends on the - /// CommandParameter - /// and can execute if returns Ok. - /// - /// This overload allows more easily re-using the same validation functions - /// for inputs and commands. - /// - /// Returns the message to dispatch. - /// - /// If true, CanExecuteChanged will trigger every time WPF's - /// CommandManager - /// detects UI changes that could potentially influence the command's - /// ability to execute. This will likely lead to many more triggers than - /// necessary, but is needed if you have bound the CommandParameter - /// to another UI property. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member cmdParamIf - (exec: obj -> 'model -> Result<'msg, 'ignored>, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a binding to a sub-model/component that has its own bindings and - /// message type. You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// Gets the sub-model from the model. - /// - /// Converts the models to the model used by the bindings. - /// - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - [] - static member subModel - (getSubModel: 'model -> 'subModel, - toBindingModel: 'model * 'subModel -> 'bindingModel, - toMsg: 'bindingMsg -> 'msg, - bindings: unit -> Binding<'bindingModel, 'bindingMsg> list) - : string -> Binding<'model, 'msg> = - Binding.SubModel.required bindings - >> Binding.mapModel (fun m -> toBindingModel (m, getSubModel m)) - >> Binding.mapMsg toMsg - - /// - /// Creates a binding to a sub-model/component that has its own bindings and - /// message type. You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// Gets the sub-model from the model. - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - [] - static member subModel - (getSubModel: 'model -> 'subModel, - toMsg: 'subMsg -> 'msg, - bindings: unit -> Binding<'model * 'subModel, 'subMsg> list) - : string -> Binding<'model, 'msg> = - Binding.SubModel.required bindings - >> Binding.mapModel (fun m -> (m, getSubModel m)) - >> Binding.mapMsg toMsg - - - /// - /// Creates a binding to a sub-model/component that has its own bindings. - /// You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// Gets the sub-model from the model. - /// Returns the bindings for the sub-model. - [ Binding<'model, 'msg> list\". To avoid a compile error when upgrading, replace this method call with its implementation.")>] - static member subModel - (getSubModel: 'model -> 'subModel, - bindings: unit -> Binding<'model * 'subModel, 'msg> list) - : string -> Binding<'model, 'msg> = - Binding.SubModel.required bindings - >> Binding.mapModel (fun m -> (m, getSubModel m)) - - - /// - /// Creates a binding to a sub-model/component that has its own bindings and - /// message type, and may not exist. If it does not exist, bindings to this - /// model will return null unless is - /// true, in which case the last non-null model will be - /// returned. You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// The 'sticky' part is useful if you want to e.g. animate away a - /// UserControl when the model is missing, but don't want the data - /// used by that control to be cleared once the animation starts. (The - /// animation must be triggered using another binding since this will never - /// return null.) - /// - /// Gets the sub-model from the model. - /// - /// Converts the models to the model used by the bindings. - /// - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// If true, when the model is missing, the last non-null - /// model will be returned instead of null. - /// - [] - static member subModelOpt - (getSubModel: 'model -> 'subModel voption, - toBindingModel: 'model * 'subModel -> 'bindingModel, - toMsg: 'bindingMsg -> 'msg, - bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, - ?sticky: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModel.vopt bindings - >> if (defaultArg sticky false) then Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) else id - >> Binding.mapModel (fun m -> getSubModel m |> ValueOption.map (fun sub -> toBindingModel (m, sub))) - >> Binding.mapMsg toMsg - - - /// - /// Creates a binding to a sub-model/component that has its own bindings and - /// message type, and may not exist. If it does not exist, bindings to this - /// model will return null unless is - /// true, in which case the last non-null model will be - /// returned. You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// The 'sticky' part is useful if you want to e.g. animate away a - /// UserControl when the model is missing, but don't want the data - /// used by that control to be cleared once the animation starts. (The - /// animation must be triggered using another binding since this will never - /// return null.) - /// - /// Gets the sub-model from the model. - /// - /// Converts the models to the model used by the bindings. - /// - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// If true, when the model is missing, the last non-null - /// model will be returned instead of null. - /// - [] - static member subModelOpt - (getSubModel: 'model -> 'subModel option, - toBindingModel: 'model * 'subModel -> 'bindingModel, - toMsg: 'bindingMsg -> 'msg, - bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, - ?sticky: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModel.opt bindings - >> if (defaultArg sticky false) then Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) else id - >> Binding.mapModel (fun m -> getSubModel m |> Option.map (fun sub -> toBindingModel (m, sub))) - >> Binding.mapMsg toMsg - - /// - /// Creates a binding to a sub-model/component that has its own bindings and - /// message type, and may not exist. If it does not exist, bindings to this - /// model will return null unless is - /// true, in which case the last non-null model will be - /// returned. You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// The 'sticky' part is useful if you want to e.g. animate away a - /// UserControl when the model is missing, but don't want the data - /// used by that control to be cleared once the animation starts. (The - /// animation must be triggered using another binding since this will never - /// return null.) - /// - /// Gets the sub-model from the model. - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// If true, when the model is missing, the last non-null - /// model will be returned instead of null. - /// - [] - static member subModelOpt - (getSubModel: 'model -> 'subModel voption, - toMsg: 'subMsg -> 'msg, - bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, - ?sticky: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModel.vopt bindings - >> if (defaultArg sticky false) then Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) else id - >> Binding.mapModel (fun m -> getSubModel m |> ValueOption.map (fun sub -> (m, sub))) - >> Binding.mapMsg toMsg - - - /// - /// Creates a binding to a sub-model/component that has its own bindings and - /// message type, and may not exist. If it does not exist, bindings to this - /// model will return null unless is - /// true, in which case the last non-null model will be - /// returned. You typically bind this to the DataContext of a - /// UserControl or similar. - /// - /// The 'sticky' part is useful if you want to e.g. animate away a - /// UserControl when the model is missing, but don't want the data - /// used by that control to be cleared once the animation starts. (The - /// animation must be triggered using another binding since this will never - /// return null.) - /// - /// Gets the sub-model from the model. - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// If true, when the model is missing, the last non-null - /// model will be returned instead of null. - /// - [] - static member subModelOpt - (getSubModel: 'model -> 'subModel option, - toMsg: 'subMsg -> 'msg, - bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, - ?sticky: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModel.opt bindings - >> if (defaultArg sticky false) then Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) else id - >> Binding.mapModel (fun m -> getSubModel m |> Option.map (fun sub -> (m, sub))) - >> Binding.mapMsg toMsg - - - /// - /// Creates a binding to a sub-model/component that has its own bindings, - /// and may not exist. If it does not exist, bindings to this model will - /// return null unless is true, in - /// which case the last non-null model will be returned. You - /// typically bind this to the DataContext of a UserControl or - /// similar. - /// - /// The 'sticky' part is useful if you want to e.g. animate away a - /// UserControl when the model is missing, but don't want the data - /// used by that control to be cleared once the animation starts. (The - /// animation must be triggered using another binding since this will never - /// return null.) - /// - /// Gets the sub-model from the model. - /// Returns the bindings for the sub-model. - /// - /// If true, when the model is missing, the last non-null - /// model will be returned instead of null. - /// - [ Binding<'model, 'msg> list\". To avoid a compile error when upgrading, replace this method call with (a specialization of) its implementation.")>] - static member subModelOpt - (getSubModel: 'model -> 'subModel voption, - bindings: unit -> Binding<'model * 'subModel, 'msg> list, - ?sticky: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModel.vopt bindings - >> if (defaultArg sticky false) then Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) else id - >> Binding.mapModel (fun m -> getSubModel m |> ValueOption.map (fun sub -> (m, sub))) - - - /// - /// Creates a binding to a sub-model/component that has its own bindings, - /// and may not exist. If it does not exist, bindings to this model will - /// return null unless is true, in - /// which case the last non-null model will be returned. You - /// typically bind this to the DataContext of a UserControl or - /// similar. - /// - /// The 'sticky' part is useful if you want to e.g. animate away a - /// UserControl when the model is missing, but don't want the data - /// used by that control to be cleared once the animation starts. (The - /// animation must be triggered using another binding since this will never - /// return null.) - /// - /// Gets the sub-model from the model. - /// Returns the bindings for the sub-model. - /// - /// If true, when the model is missing, the last non-null - /// model will be returned instead of null. - /// - [ Binding<'model, 'msg> list\". To avoid a compile error when upgrading, replace this method call with (a specialization of) its implementation.")>] - static member subModelOpt - (getSubModel: 'model -> 'subModel option, - bindings: unit -> Binding<'model * 'subModel, 'msg> list, - ?sticky: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModel.opt bindings - >> if (defaultArg sticky false) then Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) else id - >> Binding.mapModel (fun m -> getSubModel m |> Option.map (fun sub -> (m, sub))) - - - /// - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (neither in code - /// nor XAML). - /// - /// The window can only be closed/hidden by changing the return value of - /// , and can not be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it, - /// or displaying relevant feedback to the user.) - /// - /// If you don't need a sub-model, you can use - /// WindowState<unit> to just control the Window visibility, - /// and pass fst to . - /// - /// Gets the window state and a sub-model. - /// - /// Converts the models to the model used by the bindings. - /// - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// The function used to get and configure the window. - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - /// - /// Specifies whether the window will be shown modally (using - /// window.ShowDialog, blocking the rest of the app) or non-modally (using - /// window.Show). - /// - static member subModelWin - (getState: 'model -> WindowState<'subModel>, - toBindingModel: 'model * 'subModel -> 'bindingModel, - toMsg: 'bindingMsg -> 'msg, - bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, - getWindow: 'model -> Dispatch<'msg> -> #Window, - ?onCloseRequested: 'msg, - ?isModal: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModelWin.create - (fun m -> getState m |> WindowState.map (fun sub -> toBindingModel (m, sub))) - (fun args -> DynamicViewModel<'bindingModel, 'bindingMsg>(args, bindings ())) - IViewModel.updateModel - (fun _ -> toMsg) - (fun m d -> upcast getWindow m d) - (defaultArg isModal false) - (fun _ -> defaultArg (onCloseRequested |> Option.map ValueSome) ValueNone) - - - /// - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (neither in code - /// nor XAML). - /// - /// The window can only be closed/hidden by changing the return value of - /// , and can not be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it, - /// or displaying relevant feedback to the user.) - /// - /// If you don't need a sub-model, you can use - /// WindowState<unit> to just control the Window visibility, - /// and pass fst to . - /// - /// Gets the window state and a sub-model. - /// - /// Converts the models to the model used by the bindings. - /// - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// The function used to get and configure the window. - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - /// - /// Specifies whether the window will be shown modally (using - /// window.ShowDialog, blocking the rest of the app) or non-modally (using - /// window.Show). - /// - static member subModelWin - (getState: 'model -> WindowState<'subModel>, - toBindingModel: 'model * 'subModel -> 'bindingModel, - toMsg: 'bindingMsg -> 'msg, - bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, - getWindow: unit -> #Window, - ?onCloseRequested: 'msg, - ?isModal: bool) - : string -> Binding<'model, 'msg> = - Binding.subModelWin( - getState, - toBindingModel, - toMsg, - bindings, - (fun _ _ -> getWindow ()), - ?onCloseRequested = onCloseRequested, - ?isModal = isModal - ) - - - /// - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (neither in code - /// nor XAML). - /// - /// The window can only be closed/hidden by changing the return value of - /// , and can not be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it, - /// or displaying relevant feedback to the user.) - /// - /// Gets the window state and a sub-model. - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// The function used to get and configure the window. - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - /// - /// Specifies whether the window will be shown modally (using - /// window.ShowDialog, blocking the rest of the app) or non-modally (using - /// window.Show). - /// - static member subModelWin - (getState: 'model -> WindowState<'subModel>, - toMsg: 'subMsg -> 'msg, - bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, - getWindow: 'model -> Dispatch<'msg> -> #Window, - ?onCloseRequested: 'msg, - ?isModal: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModelWin.create - (fun m -> getState m |> WindowState.map (fun sub -> (m, sub))) - (fun args -> DynamicViewModel<'model * 'subModel, 'subMsg>(args, bindings ())) - IViewModel.updateModel - (fun _ -> toMsg) - (fun m d -> upcast getWindow m d) - (defaultArg isModal false) - (fun _ -> defaultArg (onCloseRequested |> Option.map ValueSome) ValueNone) - - - /// - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (neither in code - /// nor XAML). - /// - /// The window can only be closed/hidden by changing the return value of - /// , and can not be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it, - /// or displaying relevant feedback to the user.) - /// - /// Gets the window state and a sub-model. - /// - /// Converts the messages used in the bindings to parent model messages - /// (e.g. a parent message union case that wraps the child message type). - /// - /// Returns the bindings for the sub-model. - /// - /// The function used to get and configure the window. - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - /// - /// Specifies whether the window will be shown modally (using - /// window.ShowDialog, blocking the rest of the app) or non-modally (using - /// window.Show). - /// - static member subModelWin - (getState: 'model -> WindowState<'subModel>, - toMsg: 'subMsg -> 'msg, - bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, - getWindow: unit -> #Window, - ?onCloseRequested: 'msg, - ?isModal: bool) - : string -> Binding<'model, 'msg> = - Binding.subModelWin( - getState, - toMsg, - bindings, - (fun _ _ -> getWindow ()), - ?onCloseRequested = onCloseRequested, - ?isModal = isModal - ) - - - /// - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (neither in code - /// nor XAML). - /// - /// The window can only be closed/hidden by changing the return value of - /// , and can not be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it, - /// or displaying relevant feedback to the user.) - /// - /// Gets the window state and a sub-model. - /// Returns the bindings for the sub-model. - /// - /// The function used to get and configure the window. - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - /// - /// Specifies whether the window will be shown modally (using - /// window.ShowDialog, blocking the rest of the app) or non-modally (using - /// window.Show). - /// - static member subModelWin - (getState: 'model -> WindowState<'subModel>, - bindings: unit -> Binding<'model * 'subModel, 'msg> list, - getWindow: 'model -> Dispatch<'msg> -> #Window, - ?onCloseRequested: 'msg, - ?isModal: bool) - : string -> Binding<'model, 'msg> = - Binding.SubModelWin.create - (fun m -> getState m |> WindowState.map (fun sub -> (m, sub))) - (fun args -> DynamicViewModel<'model * 'subModel, 'msg>(args, bindings ())) - IViewModel.updateModel - (fun _ -> id) - (fun m d -> upcast getWindow m d) - (defaultArg isModal false) - (fun _ -> defaultArg (onCloseRequested |> Option.map ValueSome) ValueNone) - - - /// - /// Like , but uses the WindowState wrapper - /// to show/hide/close a new window that will have the specified bindings as - /// its DataContext. - /// - /// You do not need to set the DataContext yourself (neither in code - /// nor XAML). - /// - /// The window can only be closed/hidden by changing the return value of - /// , and can not be directly closed by the - /// user. External close attempts (the Close/X button, Alt+F4, or System - /// Menu -> Close) will cause the message specified by - /// to be dispatched. You should supply - /// and react to this in a manner that - /// will not confuse a user trying to close the window (e.g. by closing it, - /// or displaying relevant feedback to the user.) - /// - /// Gets the window state and a sub-model. - /// Returns the bindings for the sub-model. - /// - /// The function used to get and configure the window. - /// - /// - /// The message to be dispatched on external close attempts (the Close/X - /// button, Alt+F4, or System Menu -> Close). - /// - /// - /// Specifies whether the window will be shown modally (using - /// window.ShowDialog, blocking the rest of the app) or non-modally (using - /// window.Show). - /// - static member subModelWin - (getState: 'model -> WindowState<'subModel>, - bindings: unit -> Binding<'model * 'subModel, 'msg> list, - getWindow: unit -> #Window, - ?onCloseRequested: 'msg, - ?isModal: bool) - : string -> Binding<'model, 'msg> = - Binding.subModelWin( - getState, - bindings, - (fun _ _ -> getWindow ()), - ?onCloseRequested = onCloseRequested, - ?isModal = isModal - ) - - static member subModelSeq // TODO: make into function - (getBindings: unit -> Binding<'model, 'msg> list) - : string -> Binding<'model seq, int * 'msg> = - Binding.SubModelSeqUnkeyed.create - (fun args -> DynamicViewModel<'model, 'msg>(args, getBindings ())) - IViewModel.updateModel - - static member subModelSeq // TODO: make into function - (getBindings: unit -> Binding<'model, 'msg> list, - getId: 'model -> 'id) - : string -> Binding<'model seq, 'id * 'msg> = - Binding.SubModelSeqKeyed.create - (fun args -> DynamicViewModel<'model, 'msg>(args, getBindings ())) - IViewModel.updateModel - getId - (IViewModel.currentModel >> getId) - - - /// - /// Creates a binding to a sequence of sub-models, each uniquely identified - /// by the value returned by . The sub-models have - /// their own bindings and message type. You typically bind this to the - /// ItemsSource of an ItemsControl, ListView, - /// TreeView, etc. - /// - /// Gets the sub-models from the model. - /// - /// Converts the models to the model used by the bindings. - /// - /// Gets a unique identifier for a sub-model. - /// - /// Converts the sub-model ID and messages used in the bindings to parent - /// model messages (e.g. a parent message union case that wraps the - /// sub-model ID and message type). - /// - /// Returns the bindings for the sub-model. - static member subModelSeq - (getSubModels: 'model -> #seq<'subModel>, - toBindingModel: 'model * 'subModel -> 'bindingModel, - getId: 'bindingModel -> 'id, - toMsg: 'id * 'bindingMsg -> 'msg, - bindings: unit -> Binding<'bindingModel, 'bindingMsg> list) - : string -> Binding<'model, 'msg> = - Binding.SubModelSeqKeyed.create - (fun args -> DynamicViewModel<'bindingModel, 'bindingMsg>(args, bindings ())) - IViewModel.updateModel - getId - (IViewModel.currentModel >> getId) - >> Binding.mapModel (fun m -> getSubModels m |> Seq.map (fun sub -> toBindingModel (m, sub))) - >> Binding.mapMsg toMsg - - - /// - /// Creates a binding to a sequence of sub-models, each uniquely identified - /// by the value returned by . The sub-models have - /// their own bindings and message type. You typically bind this to the - /// ItemsSource of an ItemsControl, ListView, - /// TreeView, etc. - /// - /// Gets the sub-models from the model. - /// Gets a unique identifier for a sub-model. - /// - /// Converts the sub-model ID and messages used in the bindings to parent - /// model messages (e.g. a parent message union case that wraps the - /// sub-model ID and message type). - /// - /// Returns the bindings for the sub-model. - static member subModelSeq - (getSubModels: 'model -> #seq<'subModel>, - getId: 'subModel -> 'id, - toMsg: 'id * 'subMsg -> 'msg, - bindings: unit -> Binding<'model * 'subModel, 'subMsg> list) - : string -> Binding<'model, 'msg> = - Binding.SubModelSeqKeyed.create - (fun args -> DynamicViewModel<'model * 'subModel, 'subMsg>(args, bindings ())) - IViewModel.updateModel - (snd >> getId) - (IViewModel.currentModel >> snd >> getId) - >> Binding.mapModel (fun m -> getSubModels m |> Seq.map (fun sub -> (m, sub))) - >> Binding.mapMsg toMsg - - - /// - /// Creates a binding to a sequence of sub-models, each uniquely identified - /// by the value returned by . The sub-models have - /// their own bindings. You typically bind this to the ItemsSource of - /// an - /// ItemsControl, ListView, TreeView, etc. - /// - /// Gets the sub-models from the model. - /// Gets a unique identifier for a sub-model. - /// Returns the bindings for the sub-model. - static member subModelSeq - (getSubModels: 'model -> #seq<'subModel>, - getId: 'subModel -> 'id, - bindings: unit -> Binding<'model * 'subModel, 'msg> list) - : string -> Binding<'model, 'msg> = - Binding.SubModelSeqKeyed.create - (fun args -> DynamicViewModel<'model * 'subModel, 'msg>(args, bindings ())) - IViewModel.updateModel - (snd >> getId) - (IViewModel.currentModel >> snd >> getId) - >> Binding.mapModel (fun m -> getSubModels m |> Seq.map (fun sub -> (m, sub))) - >> Binding.mapMsg snd - - - /// - /// Creates a two-way binding to a SelectedItem-like property where - /// the - /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF view - /// models to/from their corresponding IDs, so the Elmish user code only has - /// to work with the IDs. - /// - /// Only use this if you are unable to use some kind of SelectedValue - /// or - /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when initializing - /// the bindings if - /// does not correspond to a binding, and it will - /// throw at runtime if the inferred 'id type does not match the - /// actual ID type used in that binding. - /// - /// - /// The name of the binding used as the items - /// source. - /// - /// Gets the selected sub-model/sub-binding ID from the - /// model. - /// - /// Returns the message to dispatch on selections/de-selections. - /// - 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 - - /// - /// Creates a two-way binding to a SelectedItem-like property where - /// the - /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF view - /// models to/from their corresponding IDs, so the Elmish user code only has - /// to work with the IDs. - /// - /// Only use this if you are unable to use some kind of SelectedValue - /// or - /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when initializing - /// the bindings if - /// does not correspond to a binding, and it will - /// throw at runtime if the inferred 'id type does not match the - /// actual ID type used in that binding. - /// - /// - /// The name of the binding used as the items - /// source. - /// - /// Gets the selected sub-model/sub-binding ID from the - /// model. - /// - /// Returns the message to dispatch on selections/de-selections. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id voption, - set: 'id voption -> 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.subModelSelectedItem (subModelSeqBindingName, get, set) - >> Binding.alterMsgStream wrapDispatch - - - /// - /// Creates a two-way binding to a SelectedItem-like property where - /// the - /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF view - /// models to/from their corresponding IDs, so the Elmish user code only has - /// to work with the IDs. - /// - /// Only use this if you are unable to use some kind of SelectedValue - /// or - /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when initializing - /// the bindings if - /// does not correspond to a binding, and it will - /// throw at runtime if the inferred 'id type does not match the - /// actual ID type used in that binding. - /// - /// - /// The name of the binding used as the items - /// source. - /// - /// Gets the selected sub-model/sub-binding ID from the - /// model. - /// - /// Returns the message to dispatch on selections/de-selections. - /// - static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id option, - set: 'id option -> 'model -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.SubModelSelectedItem.opt subModelSeqBindingName - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsgWithModel set - >> Binding.addCaching - - /// - /// Creates a two-way binding to a SelectedItem-like property where - /// the - /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF view - /// models to/from their corresponding IDs, so the Elmish user code only has - /// to work with the IDs. - /// - /// Only use this if you are unable to use some kind of SelectedValue - /// or - /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when initializing - /// the bindings if - /// does not correspond to a binding, and it will - /// throw at runtime if the inferred 'id type does not match the - /// actual ID type used in that binding. - /// - /// - /// The name of the binding used as the items - /// source. - /// - /// Gets the selected sub-model/sub-binding ID from the - /// model. - /// - /// Returns the message to dispatch on selections/de-selections. - /// - /// - /// Wraps the dispatch function with additional behavior, such as - /// throttling, debouncing, or limiting. - /// - [] - static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id option, - set: 'id option -> 'model -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.subModelSelectedItem (subModelSeqBindingName, get, set) - >> Binding.alterMsgStream wrapDispatch + /// + /// Creates a lazily evaluated one-way binding to an optional value. The + /// binding automatically converts between the optional source value and an + /// unwrapped (possibly null) value on the view side. will be called only when the output of changes, as determined by . + /// + /// This may have better performance than a non-lazy binding for expensive + /// computations (but may be less performant for non-expensive functions due + /// to additional overhead). + /// + /// Gets the intermediate value from the model. + /// + /// Indicates whether two intermediate values are equal. Good candidates are + /// elmEq and refEq. + /// + /// Transforms the intermediate value into the final + /// type. + static member oneWayOptLazy + ( + get: 'model -> 'a, + equals: 'a -> 'a -> bool, + map: 'a -> 'b option + ) : string -> Binding<'model, 'msg> = + Binding.OneWay.opt<'b, 'msg> + >> Binding.mapModel map + >> Binding.addLazy equals + >> Binding.mapModel get + >> Binding.addCaching -// Some members are implemented as extensions to help overload resolution -[] -module Extensions = + /// + /// Creates a lazily evaluated one-way binding to an optional value. The + /// binding automatically converts between the optional source value and an + /// unwrapped (possibly null) value on the view side. will be called only when the output of changes, as determined by . + /// + /// This may have better performance than a non-lazy binding for expensive + /// computations (but may be less performant for non-expensive functions due + /// to additional overhead). + /// + /// Gets the value from the model. + /// + /// Indicates whether two intermediate values are equal. Good candidates are + /// elmEq and refEq. + /// + /// Transforms the intermediate value into the final + /// type. + static member oneWayOptLazy + ( + get: 'model -> 'a, + equals: 'a -> 'a -> bool, + map: 'a -> 'b voption + ) : string -> Binding<'model, 'msg> = + Binding.OneWay.vopt<'b, 'msg> + >> Binding.mapModel map + >> Binding.addLazy equals + >> Binding.mapModel get + >> Binding.addCaching - type Binding with /// Creates a one-way-to-source binding. /// Returns the message to dispatch. - static member oneWayToSource - (set: 'a -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.OneWayToSource.id<'model, 'a> - >> Binding.mapMsg set + static member oneWayToSource(set: 'a -> 'model -> 'msg) : string -> Binding<'model, 'msg> = + Binding.OneWayToSource.id<'model, 'a> + >> Binding.mapMsgWithModel set /// /// Creates a one-way-to-source binding to an optional value. The binding @@ -2960,11 +774,9 @@ module Extensions = /// a null value in the view. /// /// Returns the message to dispatch. - static member oneWayToSourceOpt - (set: 'a option -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.OneWayToSource.opt - >> Binding.mapMsg set + static member oneWayToSourceOpt(set: 'a option -> 'model -> 'msg) : string -> Binding<'model, 'msg> = + Binding.OneWayToSource.opt + >> Binding.mapMsgWithModel set /// /// Creates a one-way-to-source binding to an optional value. The binding @@ -2972,24 +784,84 @@ module Extensions = /// a null value in the view. /// /// Returns the message to dispatch. - static member oneWayToSourceOpt - (set: 'a voption -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.OneWayToSource.vopt - >> Binding.mapMsg set + static member oneWayToSourceOpt(set: 'a voption -> 'model -> 'msg) : string -> Binding<'model, 'msg> = + Binding.OneWayToSource.vopt + >> Binding.mapMsgWithModel set + + + /// + /// Creates a one-way binding to a sequence of items, each uniquely + /// identified by the value returned by . The + /// binding will not be updated if the output of + /// does not change, as determined by . + /// The binding is backed by a persistent ObservableCollection, so + /// only changed items (as determined by ) + /// will be replaced. If the items are complex and you want them updated + /// instead of replaced, consider using . + /// + /// Gets the intermediate value from the model. + /// + /// Indicates whether two intermediate values are equal. Good candidates are + /// elmEq and refEq. + /// + /// Transforms the value into the final collection. + /// + /// Indicates whether two collection items are equal. Good candidates are + /// elmEq, refEq, or simply (=). + /// + /// Gets a unique identifier for a collection + /// item. + static member oneWaySeqLazy + ( + get: 'model -> 'a, + equals: 'a -> 'a -> bool, + map: 'a -> #seq<'b>, + itemEquals: 'b -> 'b -> bool, + getId: 'b -> 'id + ) : string -> Binding<'model, 'msg> = + Binding.OneWaySeq.create map itemEquals getId + >> Binding.addLazy equals + >> Binding.mapModel get + + + /// + /// Creates a one-way binding to a sequence of items, each uniquely + /// identified by the value returned by . The + /// binding will not be updated if the output of + /// is referentially equal. This is the same as calling + /// with equals = refEq and + /// map = id. The binding is backed by a persistent + /// ObservableCollection, so only changed items (as determined by + /// ) will be replaced. If the items are + /// complex and you want them updated instead of replaced, consider using + /// . + /// + /// Gets the collection from the model. + /// + /// Indicates whether two collection items are equal. Good candidates are + /// elmEq, refEq, or simply (=). + /// + /// Gets a unique identifier for a collection + /// item. + static member oneWaySeq + ( + get: 'model -> #seq<'a>, + itemEquals: 'a -> 'a -> bool, + getId: 'a -> 'id + ) : string -> Binding<'model, 'msg> = + Binding.OneWaySeq.create id itemEquals getId + >> Binding.addLazy refEq + >> Binding.mapModel get /// Creates a two-way binding. /// Gets the value from the model. /// Returns the message to dispatch. - static member twoWay - (get: 'model -> 'a, - set: 'a -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set + static member twoWay(get: 'model -> 'a, set: 'a -> 'model -> 'msg) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set /// Creates a two-way binding. /// Gets the value from the model. @@ -3000,12 +872,13 @@ module Extensions = /// [] static member twoWay - (get: 'model -> 'a, - set: 'a -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWay (get, set) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWay (get, set) + >> Binding.alterMsgStream wrapDispatch /// @@ -3016,13 +889,14 @@ module Extensions = /// Gets the value from the model. /// Returns the message to dispatch. static member twoWayOpt - (get: 'model -> 'a option, - set: 'a option -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set /// /// Creates a two-way binding to an optional value. The binding @@ -3037,12 +911,13 @@ module Extensions = /// [] static member twoWayOpt - (get: 'model -> 'a option, - set: 'a option -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOpt (get, set) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOpt (get, set) + >> Binding.alterMsgStream wrapDispatch /// @@ -3053,13 +928,14 @@ module Extensions = /// Gets the value from the model. /// Returns the message to dispatch. static member twoWayOpt - (get: 'model -> 'a voption, - set: 'a voption -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set /// /// Creates a two-way binding to an optional value. The binding @@ -3074,12 +950,13 @@ module Extensions = /// [] static member twoWayOpt - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOpt (get, set) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOpt (get, set) + >> Binding.alterMsgStream wrapDispatch /// @@ -3092,15 +969,16 @@ module Extensions = /// Returns the validation messages from the updated model. /// static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> string list) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation validate + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> string list + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation validate /// /// Creates a two-way binding with validation using @@ -3117,13 +995,14 @@ module Extensions = /// [] static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> string list, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> string list, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// @@ -3136,15 +1015,16 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> string voption) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> ValueOption.toList) + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> string voption + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation (validate >> ValueOption.toList) /// /// Creates a two-way binding with validation using @@ -3161,13 +1041,14 @@ module Extensions = /// [] static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> string voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> string voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// @@ -3180,15 +1061,16 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> string option) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> Option.toList) + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> string option + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation (validate >> Option.toList) /// /// Creates a two-way binding with validation using @@ -3205,13 +1087,14 @@ module Extensions = /// [] static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> string option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> string option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// @@ -3224,15 +1107,20 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> Result<'ignored, string>) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.id<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> ValueOption.ofError >> ValueOption.toList) + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> Result<'ignored, string> + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation ( + validate + >> ValueOption.ofError + >> ValueOption.toList + ) /// /// Creates a two-way binding with validation using @@ -3249,20 +1137,21 @@ module Extensions = /// [] static member twoWayValidate - (get: 'model -> 'a, - set: 'a -> 'msg, - validate: 'model -> Result<'ignored, string>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a, + set: 'a -> 'model -> 'msg, + validate: 'model -> Result<'ignored, string>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3270,21 +1159,22 @@ module Extensions = /// Returns the validation messages from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> string list) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation validate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> string list + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation validate /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3297,20 +1187,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> string list, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> string list, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3318,21 +1209,22 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> string voption) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> ValueOption.toList) + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> string voption + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation (validate >> ValueOption.toList) /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3345,20 +1237,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> string voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> string voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3366,21 +1259,22 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> string option) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> Option.toList) + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> string option + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation (validate >> Option.toList) /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3393,20 +1287,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> string option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> string option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3414,21 +1309,26 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> Result<'ignored, string>) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.vopt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> ValueOption.ofError >> ValueOption.toList) + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> Result<'ignored, string> + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation ( + validate + >> ValueOption.ofError + >> ValueOption.toList + ) /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3441,20 +1341,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a voption, - set: 'a voption -> 'msg, - validate: 'model -> Result<'ignored, string>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a voption, + set: 'a voption -> 'model -> 'msg, + validate: 'model -> Result<'ignored, string>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3462,21 +1363,22 @@ module Extensions = /// Returns the validation messages from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> string list) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation validate + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> string list + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation validate /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3489,20 +1391,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> string list, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> string list, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3510,21 +1413,22 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> string voption) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> ValueOption.toList) + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> string voption + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation (validate >> ValueOption.toList) /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3537,20 +1441,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> string voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> string voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3558,21 +1463,22 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> string option) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> Option.toList) + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> string option + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation (validate >> Option.toList) /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3585,20 +1491,21 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> string option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> string option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3606,21 +1513,26 @@ module Extensions = /// Returns the validation message from the updated model. /// static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> Result<'ignored, string>) - : string -> Binding<'model, 'msg> = - Binding.TwoWay.opt<'a> - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addValidation (validate >> ValueOption.ofError >> ValueOption.toList) + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> Result<'ignored, string> + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addValidation ( + validate + >> ValueOption.ofError + >> ValueOption.toList + ) /// /// Creates a two-way binding to an optional value with validation using - /// INotifyDataErrorInfo. The binding automatically converts - /// between the optional source value and an unwrapped (possibly - /// null) value on the view side. + /// INotifyDataErrorInfo. The binding automatically converts between + /// the optional source value and an unwrapped (possibly null) value + /// on the view side. /// /// Gets the value from the model. /// Returns the message to dispatch. @@ -3633,30 +1545,27 @@ module Extensions = /// [] static member twoWayOptValidate - (get: 'model -> 'a option, - set: 'a option -> 'msg, - validate: 'model -> Result<'ignored, string>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.twoWayOptValidate (get, set, validate) - >> Binding.alterMsgStream wrapDispatch + ( + get: 'model -> 'a option, + set: 'a option -> 'model -> 'msg, + validate: 'model -> Result<'ignored, string>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch /// - /// Creates a Command binding that dispatches the specified message - /// and can always execute. + /// Creates a Command binding that depends only on the model (not the + /// CommandParameter) and can always execute. /// /// Returns the message to dispatch. - static member cmd - (exec: 'msg) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - (fun _ -> exec |> ValueSome) - (fun _ -> true) + static member cmd(exec: 'model -> 'msg) : string -> Binding<'model, 'msg> = + Binding.Cmd.create (exec >> ValueSome) (fun _ -> true) /// - /// Creates a Command binding that dispatches the specified message - /// and can always execute. + /// Creates a Command binding that depends only on the model (not the + /// CommandParameter) and can always execute. /// /// Returns the message to dispatch. /// @@ -3665,30 +1574,30 @@ module Extensions = /// [] static member cmd - (exec: 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmd exec - >> Binding.alterMsgStream wrapDispatch + ( + exec: 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmd exec + >> Binding.alterMsgStream wrapDispatch /// - /// Creates a Command binding that dispatches the specified message - /// and can execute if returns true. + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns true. /// /// Returns the message to dispatch. /// Indicates whether the command can execute. - static member cmdIf - (exec: 'msg, - canExec: 'model -> bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.create - (fun _ -> exec |> ValueSome) - canExec + static member cmdIf(exec: 'model -> 'msg, canExec: 'model -> bool) : string -> Binding<'model, 'msg> = + Binding.Cmd.create (exec >> ValueSome) canExec /// - /// Creates a Command binding that dispatches the specified message - /// and can execute if returns true. + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns true. /// /// Returns the message to dispatch. /// Indicates whether the command can execute. @@ -3698,12 +1607,112 @@ module Extensions = /// [] static member cmdIf - (exec: 'msg, - canExec: 'model -> bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdIf (exec, canExec) - >> Binding.alterMsgStream wrapDispatch + ( + exec: 'model -> 'msg, + canExec: 'model -> bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdIf (exec, canExec) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns ValueSome. + /// + /// Returns the message to dispatch. + static member cmdIf(exec: 'model -> 'msg voption) : string -> Binding<'model, 'msg> = + Binding.Cmd.create exec (exec >> ValueOption.isSome) + + /// + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns ValueSome. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdIf + ( + exec: 'model -> 'msg voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdIf exec + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns Some. + /// + /// Returns the message to dispatch. + static member cmdIf(exec: 'model -> 'msg option) : string -> Binding<'model, 'msg> = + Binding.Cmd.create (exec >> ValueOption.ofOption) (exec >> Option.isSome) + + /// + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns Some. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdIf + ( + exec: 'model -> 'msg option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdIf exec + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns Ok. + /// + /// This overload allows more easily re-using the same validation functions + /// for inputs and commands. + /// + /// Returns the message to dispatch. + static member cmdIf(exec: 'model -> Result<'msg, 'ignored>) : string -> Binding<'model, 'msg> = + Binding.Cmd.create (exec >> ValueOption.ofOk) (exec >> Result.isOk) + + /// + /// Creates a conditional Command binding that depends only on the + /// model (not the CommandParameter) and can execute if + /// returns Ok. + /// + /// This overload allows more easily re-using the same validation functions + /// for inputs and commands. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdIf + ( + exec: 'model -> Result<'msg, 'ignored>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdIf exec + >> Binding.alterMsgStream wrapDispatch /// @@ -3712,13 +1721,8 @@ module Extensions = /// and can always execute. /// /// Returns the message to dispatch. - static member cmdParam - (exec: obj -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p _ -> exec p |> ValueSome) - (fun _ _ -> true) - false + static member cmdParam(exec: obj -> 'model -> 'msg) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam (fun p model -> exec p model |> ValueSome) (fun _ _ -> true) false /// /// Creates a Command binding that depends on the @@ -3732,19 +1736,21 @@ module Extensions = /// [] static member cmdParam - (exec: obj -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParam exec - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParam exec + >> Binding.alterMsgStream wrapDispatch /// - /// Creates a conditional Command binding that depends on the + /// Creates a Command binding that depends on the /// CommandParameter - /// and can execute if returns ValueSome. + /// and can execute if returns true. /// /// Returns the message to dispatch. + /// Indicates whether the command can execute. /// /// If true, CanExecuteChanged will trigger every time WPF's /// CommandManager @@ -3754,38 +1760,41 @@ module Extensions = /// to another UI property. /// static member cmdParamIf - (exec: obj -> 'msg voption, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p _ -> exec p) - (fun p _ -> exec p |> ValueOption.isSome) - (defaultArg uiBoundCmdParam false) + ( + exec: obj -> 'model -> 'msg, + canExec: obj -> 'model -> bool, + ?uiBoundCmdParam: bool + ) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam (fun p m -> exec p m |> ValueSome) canExec (defaultArg uiBoundCmdParam false) /// - /// Creates a conditional Command binding that depends on the + /// Creates a Command binding that depends on the /// CommandParameter - /// and can execute if returns ValueSome. + /// and can execute if returns true. /// /// Returns the message to dispatch. + /// Indicates whether the command can execute. /// /// Wraps the dispatch function with additional behavior, such as /// throttling, debouncing, or limiting. /// [] static member cmdParamIf - (exec: obj -> 'msg voption, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf exec - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg, + canExec: obj -> 'model -> bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, canExec) + >> Binding.alterMsgStream wrapDispatch /// - /// Creates a conditional Command binding that depends on the + /// Creates a Command binding that depends on the /// CommandParameter - /// and can execute if returns ValueSome. + /// and can execute if returns true. /// /// Returns the message to dispatch. + /// Indicates whether the command can execute. /// /// If true, CanExecuteChanged will trigger every time WPF's /// CommandManager @@ -3800,18 +1809,20 @@ module Extensions = /// [] static member cmdParamIf - (exec: obj -> 'msg voption, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg, + canExec: obj -> 'model -> bool, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, canExec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns Some. + /// and can execute if returns ValueSome. /// /// Returns the message to dispatch. /// @@ -3823,18 +1834,16 @@ module Extensions = /// to another UI property. /// static member cmdParamIf - (exec: obj -> 'msg option, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p _ -> exec p |> ValueOption.ofOption) - (fun p _ -> exec p |> Option.isSome) - (defaultArg uiBoundCmdParam false) + ( + exec: obj -> 'model -> 'msg voption, + ?uiBoundCmdParam: bool + ) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam exec (fun p m -> exec p m |> ValueOption.isSome) (defaultArg uiBoundCmdParam false) /// /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns Some. + /// and can execute if returns ValueSome. /// /// Returns the message to dispatch. /// @@ -3843,16 +1852,17 @@ module Extensions = /// [] static member cmdParamIf - (exec: obj -> 'msg option, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf exec - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf exec + >> Binding.alterMsgStream wrapDispatch /// /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns Some. + /// and can execute if returns ValueSome. /// /// Returns the message to dispatch. /// @@ -3869,21 +1879,19 @@ module Extensions = /// [] static member cmdParamIf - (exec: obj -> 'msg option, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg voption, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns Ok. - /// - /// This overload allows more easily re-using the same validation - /// functions for inputs and commands. + /// and can execute if returns Some. /// /// Returns the message to dispatch. /// @@ -3895,21 +1903,19 @@ module Extensions = /// to another UI property. /// static member cmdParamIf - (exec: obj -> Result<'msg, 'ignored>, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p _ -> exec p |> ValueOption.ofOk) - (fun p _ -> exec p |> Result.isOk) - (defaultArg uiBoundCmdParam false) + ( + exec: obj -> 'model -> 'msg option, + ?uiBoundCmdParam: bool + ) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam + (fun p m -> exec p m |> ValueOption.ofOption) + (fun p m -> exec p m |> Option.isSome) + (defaultArg uiBoundCmdParam false) /// /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns Ok. - /// - /// This overload allows more easily re-using the same validation - /// functions for inputs and commands. + /// and can execute if returns Some. /// /// Returns the message to dispatch. /// @@ -3918,19 +1924,17 @@ module Extensions = /// [] static member cmdParamIf - (exec: obj -> Result<'msg, 'ignored>, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf exec - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf exec + >> Binding.alterMsgStream wrapDispatch /// /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns Ok. - /// - /// This overload allows more easily re-using the same validation - /// functions for inputs and commands. + /// and can execute if returns Some. /// /// Returns the message to dispatch. /// @@ -3947,21 +1951,24 @@ module Extensions = /// [] static member cmdParamIf - (exec: obj -> Result<'msg, 'ignored>, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> 'msg option, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch /// - /// Creates a Command binding that depends on the + /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns true. + /// and can execute if returns Ok. + /// + /// This overload allows more easily re-using the same validation functions + /// for inputs and commands. /// /// Returns the message to dispatch. - /// Indicates whether the command can execute. /// /// If true, CanExecuteChanged will trigger every time WPF's /// CommandManager @@ -3971,42 +1978,46 @@ module Extensions = /// to another UI property. /// static member cmdParamIf - (exec: obj -> 'msg, - canExec: obj -> bool, - ?uiBoundCmdParam: bool) - : string -> Binding<'model, 'msg> = - Binding.Cmd.createWithParam - (fun p _ -> exec p |> ValueSome) - (fun p _ -> canExec p) - (defaultArg uiBoundCmdParam false) + ( + exec: obj -> 'model -> Result<'msg, 'ignored>, + ?uiBoundCmdParam: bool + ) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam + (fun p m -> exec p m |> ValueOption.ofOk) + (fun p m -> exec p m |> Result.isOk) + (defaultArg uiBoundCmdParam false) /// - /// Creates a Command binding that depends on the + /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns true. + /// and can execute if returns Ok. + /// + /// This overload allows more easily re-using the same validation functions + /// for inputs and commands. /// /// Returns the message to dispatch. - /// Indicates whether the command can execute. /// /// Wraps the dispatch function with additional behavior, such as /// throttling, debouncing, or limiting. /// [] static member cmdParamIf - (exec: obj -> 'msg, - canExec: obj -> bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, canExec) - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> Result<'msg, 'ignored>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf exec + >> Binding.alterMsgStream wrapDispatch /// - /// Creates a Command binding that depends on the + /// Creates a conditional Command binding that depends on the /// CommandParameter - /// and can execute if returns true. + /// and can execute if returns Ok. + /// + /// This overload allows more easily re-using the same validation functions + /// for inputs and commands. /// /// Returns the message to dispatch. - /// Indicates whether the command can execute. /// /// If true, CanExecuteChanged will trigger every time WPF's /// CommandManager @@ -4021,32 +2032,793 @@ module Extensions = /// [] static member cmdParamIf - (exec: obj -> 'msg, - canExec: obj -> bool, - uiBoundCmdParam: bool, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.cmdParamIf (exec, canExec, uiBoundCmdParam) - >> Binding.alterMsgStream wrapDispatch + ( + exec: obj -> 'model -> Result<'msg, 'ignored>, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a binding to a sub-model/component that has its own bindings and + /// message type. You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// Gets the sub-model from the model. + /// + /// Converts the models to the model used by the bindings. + /// + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + [] + static member subModel + ( + getSubModel: 'model -> 'subModel, + toBindingModel: 'model * 'subModel -> 'bindingModel, + toMsg: 'bindingMsg -> 'msg, + bindings: unit -> Binding<'bindingModel, 'bindingMsg> list + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.required bindings + >> Binding.mapModel (fun m -> toBindingModel (m, getSubModel m)) + >> Binding.mapMsg toMsg + + /// + /// Creates a binding to a sub-model/component that has its own bindings and + /// message type. You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// Gets the sub-model from the model. + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + [] + static member subModel + ( + getSubModel: 'model -> 'subModel, + toMsg: 'subMsg -> 'msg, + bindings: unit -> Binding<'model * 'subModel, 'subMsg> list + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.required bindings + >> Binding.mapModel (fun m -> (m, getSubModel m)) + >> Binding.mapMsg toMsg + + + /// + /// Creates a binding to a sub-model/component that has its own bindings. + /// You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// Gets the sub-model from the model. + /// Returns the bindings for the sub-model. + [ Binding<'model, 'msg> list\". To avoid a compile error when upgrading, replace this method call with its implementation.")>] + static member subModel + ( + getSubModel: 'model -> 'subModel, + bindings: unit -> Binding<'model * 'subModel, 'msg> list + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.required bindings + >> Binding.mapModel (fun m -> (m, getSubModel m)) + + + /// + /// Creates a binding to a sub-model/component that has its own bindings and + /// message type, and may not exist. If it does not exist, bindings to this + /// model will return null unless is + /// true, in which case the last non-null model will be + /// returned. You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// The 'sticky' part is useful if you want to e.g. animate away a + /// UserControl when the model is missing, but don't want the data + /// used by that control to be cleared once the animation starts. (The + /// animation must be triggered using another binding since this will never + /// return null.) + /// + /// Gets the sub-model from the model. + /// + /// Converts the models to the model used by the bindings. + /// + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// If true, when the model is missing, the last non-null + /// model will be returned instead of null. + /// + [] + static member subModelOpt + ( + getSubModel: 'model -> 'subModel voption, + toBindingModel: 'model * 'subModel -> 'bindingModel, + toMsg: 'bindingMsg -> 'msg, + bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, + ?sticky: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.vopt bindings + >> if (defaultArg sticky false) then + Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) + else + id + >> Binding.mapModel (fun m -> + getSubModel m + |> ValueOption.map (fun sub -> toBindingModel (m, sub))) + >> Binding.mapMsg toMsg + + + /// + /// Creates a binding to a sub-model/component that has its own bindings and + /// message type, and may not exist. If it does not exist, bindings to this + /// model will return null unless is + /// true, in which case the last non-null model will be + /// returned. You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// The 'sticky' part is useful if you want to e.g. animate away a + /// UserControl when the model is missing, but don't want the data + /// used by that control to be cleared once the animation starts. (The + /// animation must be triggered using another binding since this will never + /// return null.) + /// + /// Gets the sub-model from the model. + /// + /// Converts the models to the model used by the bindings. + /// + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// If true, when the model is missing, the last non-null + /// model will be returned instead of null. + /// + [] + static member subModelOpt + ( + getSubModel: 'model -> 'subModel option, + toBindingModel: 'model * 'subModel -> 'bindingModel, + toMsg: 'bindingMsg -> 'msg, + bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, + ?sticky: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.opt bindings + >> if (defaultArg sticky false) then + Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) + else + id + >> Binding.mapModel (fun m -> + getSubModel m + |> Option.map (fun sub -> toBindingModel (m, sub))) + >> Binding.mapMsg toMsg + + /// + /// Creates a binding to a sub-model/component that has its own bindings and + /// message type, and may not exist. If it does not exist, bindings to this + /// model will return null unless is + /// true, in which case the last non-null model will be + /// returned. You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// The 'sticky' part is useful if you want to e.g. animate away a + /// UserControl when the model is missing, but don't want the data + /// used by that control to be cleared once the animation starts. (The + /// animation must be triggered using another binding since this will never + /// return null.) + /// + /// Gets the sub-model from the model. + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// If true, when the model is missing, the last non-null + /// model will be returned instead of null. + /// + [] + static member subModelOpt + ( + getSubModel: 'model -> 'subModel voption, + toMsg: 'subMsg -> 'msg, + bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, + ?sticky: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.vopt bindings + >> if (defaultArg sticky false) then + Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) + else + id + >> Binding.mapModel (fun m -> + getSubModel m + |> ValueOption.map (fun sub -> (m, sub))) + >> Binding.mapMsg toMsg + + + /// + /// Creates a binding to a sub-model/component that has its own bindings and + /// message type, and may not exist. If it does not exist, bindings to this + /// model will return null unless is + /// true, in which case the last non-null model will be + /// returned. You typically bind this to the DataContext of a + /// UserControl or similar. + /// + /// The 'sticky' part is useful if you want to e.g. animate away a + /// UserControl when the model is missing, but don't want the data + /// used by that control to be cleared once the animation starts. (The + /// animation must be triggered using another binding since this will never + /// return null.) + /// + /// Gets the sub-model from the model. + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// If true, when the model is missing, the last non-null + /// model will be returned instead of null. + /// + [] + static member subModelOpt + ( + getSubModel: 'model -> 'subModel option, + toMsg: 'subMsg -> 'msg, + bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, + ?sticky: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.opt bindings + >> if (defaultArg sticky false) then + Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) + else + id + >> Binding.mapModel (fun m -> getSubModel m |> Option.map (fun sub -> (m, sub))) + >> Binding.mapMsg toMsg + + + /// + /// Creates a binding to a sub-model/component that has its own bindings, + /// and may not exist. If it does not exist, bindings to this model will + /// return null unless is true, in + /// which case the last non-null model will be returned. You + /// typically bind this to the DataContext of a UserControl or + /// similar. + /// + /// The 'sticky' part is useful if you want to e.g. animate away a + /// UserControl when the model is missing, but don't want the data + /// used by that control to be cleared once the animation starts. (The + /// animation must be triggered using another binding since this will never + /// return null.) + /// + /// Gets the sub-model from the model. + /// Returns the bindings for the sub-model. + /// + /// If true, when the model is missing, the last non-null + /// model will be returned instead of null. + /// + [ Binding<'model, 'msg> list\". To avoid a compile error when upgrading, replace this method call with (a specialization of) its implementation.")>] + static member subModelOpt + ( + getSubModel: 'model -> 'subModel voption, + bindings: unit -> Binding<'model * 'subModel, 'msg> list, + ?sticky: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.vopt bindings + >> if (defaultArg sticky false) then + Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) + else + id + >> Binding.mapModel (fun m -> + getSubModel m + |> ValueOption.map (fun sub -> (m, sub))) + + + /// + /// Creates a binding to a sub-model/component that has its own bindings, + /// and may not exist. If it does not exist, bindings to this model will + /// return null unless is true, in + /// which case the last non-null model will be returned. You + /// typically bind this to the DataContext of a UserControl or + /// similar. + /// + /// The 'sticky' part is useful if you want to e.g. animate away a + /// UserControl when the model is missing, but don't want the data + /// used by that control to be cleared once the animation starts. (The + /// animation must be triggered using another binding since this will never + /// return null.) + /// + /// Gets the sub-model from the model. + /// Returns the bindings for the sub-model. + /// + /// If true, when the model is missing, the last non-null + /// model will be returned instead of null. + /// + [ Binding<'model, 'msg> list\". To avoid a compile error when upgrading, replace this method call with (a specialization of) its implementation.")>] + static member subModelOpt + ( + getSubModel: 'model -> 'subModel option, + bindings: unit -> Binding<'model * 'subModel, 'msg> list, + ?sticky: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModel.opt bindings + >> if (defaultArg sticky false) then + Binding.addLazy (fun previous next -> previous.IsSome && next.IsNone) + else + id + >> Binding.mapModel (fun m -> getSubModel m |> Option.map (fun sub -> (m, sub))) + + + /// + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (neither in code + /// nor XAML). + /// + /// The window can only be closed/hidden by changing the return value of + /// , and can not be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it, + /// or displaying relevant feedback to the user.) + /// + /// If you don't need a sub-model, you can use + /// WindowState<unit> to just control the Window visibility, + /// and pass fst to . + /// + /// Gets the window state and a sub-model. + /// + /// Converts the models to the model used by the bindings. + /// + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// The function used to get and configure the window. + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + /// + /// Specifies whether the window will be shown modally (using + /// window.ShowDialog, blocking the rest of the app) or non-modally (using + /// window.Show). + /// + static member subModelWin + ( + getState: 'model -> WindowState<'subModel>, + toBindingModel: 'model * 'subModel -> 'bindingModel, + toMsg: 'bindingMsg -> 'msg, + bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, + getWindow: 'model -> Dispatch<'msg> -> #Window, + ?onCloseRequested: 'msg, + ?isModal: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModelWin.create + (fun m -> + getState m + |> WindowState.map (fun sub -> toBindingModel (m, sub))) + (fun args -> DynamicViewModel<'bindingModel, 'bindingMsg>(args, bindings ())) + IViewModel.updateModel + (fun _ -> toMsg) + (fun m d -> upcast getWindow m d) + (defaultArg isModal false) + (fun _ -> defaultArg (onCloseRequested |> Option.map ValueSome) ValueNone) + + + /// + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (neither in code + /// nor XAML). + /// + /// The window can only be closed/hidden by changing the return value of + /// , and can not be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it, + /// or displaying relevant feedback to the user.) + /// + /// If you don't need a sub-model, you can use + /// WindowState<unit> to just control the Window visibility, + /// and pass fst to . + /// + /// Gets the window state and a sub-model. + /// + /// Converts the models to the model used by the bindings. + /// + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// The function used to get and configure the window. + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + /// + /// Specifies whether the window will be shown modally (using + /// window.ShowDialog, blocking the rest of the app) or non-modally (using + /// window.Show). + /// + static member subModelWin + ( + getState: 'model -> WindowState<'subModel>, + toBindingModel: 'model * 'subModel -> 'bindingModel, + toMsg: 'bindingMsg -> 'msg, + bindings: unit -> Binding<'bindingModel, 'bindingMsg> list, + getWindow: unit -> #Window, + ?onCloseRequested: 'msg, + ?isModal: bool + ) : string -> Binding<'model, 'msg> = + Binding.subModelWin ( + getState, + toBindingModel, + toMsg, + bindings, + (fun _ _ -> getWindow ()), + ?onCloseRequested = onCloseRequested, + ?isModal = isModal + ) + + + /// + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (neither in code + /// nor XAML). + /// + /// The window can only be closed/hidden by changing the return value of + /// , and can not be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it, + /// or displaying relevant feedback to the user.) + /// + /// Gets the window state and a sub-model. + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// The function used to get and configure the window. + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + /// + /// Specifies whether the window will be shown modally (using + /// window.ShowDialog, blocking the rest of the app) or non-modally (using + /// window.Show). + /// + static member subModelWin + ( + getState: 'model -> WindowState<'subModel>, + toMsg: 'subMsg -> 'msg, + bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, + getWindow: 'model -> Dispatch<'msg> -> #Window, + ?onCloseRequested: 'msg, + ?isModal: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModelWin.create + (fun m -> + getState m + |> WindowState.map (fun sub -> (m, sub))) + (fun args -> DynamicViewModel<'model * 'subModel, 'subMsg>(args, bindings ())) + IViewModel.updateModel + (fun _ -> toMsg) + (fun m d -> upcast getWindow m d) + (defaultArg isModal false) + (fun _ -> defaultArg (onCloseRequested |> Option.map ValueSome) ValueNone) + + + /// + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (neither in code + /// nor XAML). + /// + /// The window can only be closed/hidden by changing the return value of + /// , and can not be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it, + /// or displaying relevant feedback to the user.) + /// + /// Gets the window state and a sub-model. + /// + /// Converts the messages used in the bindings to parent model messages + /// (e.g. a parent message union case that wraps the child message type). + /// + /// Returns the bindings for the sub-model. + /// + /// The function used to get and configure the window. + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + /// + /// Specifies whether the window will be shown modally (using + /// window.ShowDialog, blocking the rest of the app) or non-modally (using + /// window.Show). + /// + static member subModelWin + ( + getState: 'model -> WindowState<'subModel>, + toMsg: 'subMsg -> 'msg, + bindings: unit -> Binding<'model * 'subModel, 'subMsg> list, + getWindow: unit -> #Window, + ?onCloseRequested: 'msg, + ?isModal: bool + ) : string -> Binding<'model, 'msg> = + Binding.subModelWin ( + getState, + toMsg, + bindings, + (fun _ _ -> getWindow ()), + ?onCloseRequested = onCloseRequested, + ?isModal = isModal + ) + + + /// + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (neither in code + /// nor XAML). + /// + /// The window can only be closed/hidden by changing the return value of + /// , and can not be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it, + /// or displaying relevant feedback to the user.) + /// + /// Gets the window state and a sub-model. + /// Returns the bindings for the sub-model. + /// + /// The function used to get and configure the window. + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + /// + /// Specifies whether the window will be shown modally (using + /// window.ShowDialog, blocking the rest of the app) or non-modally (using + /// window.Show). + /// + static member subModelWin + ( + getState: 'model -> WindowState<'subModel>, + bindings: unit -> Binding<'model * 'subModel, 'msg> list, + getWindow: 'model -> Dispatch<'msg> -> #Window, + ?onCloseRequested: 'msg, + ?isModal: bool + ) : string -> Binding<'model, 'msg> = + Binding.SubModelWin.create + (fun m -> + getState m + |> WindowState.map (fun sub -> (m, sub))) + (fun args -> DynamicViewModel<'model * 'subModel, 'msg>(args, bindings ())) + IViewModel.updateModel + (fun _ -> id) + (fun m d -> upcast getWindow m d) + (defaultArg isModal false) + (fun _ -> defaultArg (onCloseRequested |> Option.map ValueSome) ValueNone) + + + /// + /// Like , but uses the WindowState wrapper + /// to show/hide/close a new window that will have the specified bindings as + /// its DataContext. + /// + /// You do not need to set the DataContext yourself (neither in code + /// nor XAML). + /// + /// The window can only be closed/hidden by changing the return value of + /// , and can not be directly closed by the + /// user. External close attempts (the Close/X button, Alt+F4, or System + /// Menu -> Close) will cause the message specified by + /// to be dispatched. You should supply + /// and react to this in a manner that + /// will not confuse a user trying to close the window (e.g. by closing it, + /// or displaying relevant feedback to the user.) + /// + /// Gets the window state and a sub-model. + /// Returns the bindings for the sub-model. + /// + /// The function used to get and configure the window. + /// + /// + /// The message to be dispatched on external close attempts (the Close/X + /// button, Alt+F4, or System Menu -> Close). + /// + /// + /// Specifies whether the window will be shown modally (using + /// window.ShowDialog, blocking the rest of the app) or non-modally (using + /// window.Show). + /// + static member subModelWin + ( + getState: 'model -> WindowState<'subModel>, + bindings: unit -> Binding<'model * 'subModel, 'msg> list, + getWindow: unit -> #Window, + ?onCloseRequested: 'msg, + ?isModal: bool + ) : string -> Binding<'model, 'msg> = + Binding.subModelWin ( + getState, + bindings, + (fun _ _ -> getWindow ()), + ?onCloseRequested = onCloseRequested, + ?isModal = isModal + ) + + static member subModelSeq + (getBindings: unit -> Binding<'model, 'msg> list) + : string -> Binding<'model seq, int * 'msg> = + Binding.SubModelSeqUnkeyed.create + (fun args -> DynamicViewModel<'model, 'msg>(args, getBindings ())) + IViewModel.updateModel + + static member subModelSeq + ( + getBindings: unit -> Binding<'model, 'msg> list, + getId: 'model -> 'id + ) : string -> Binding<'model seq, 'id * 'msg> = + Binding.SubModelSeqKeyed.create + (fun args -> DynamicViewModel<'model, 'msg>(args, getBindings ())) + IViewModel.updateModel + getId + (IViewModel.currentModel >> getId) + + + /// + /// Creates a binding to a sequence of sub-models, each uniquely identified + /// by the value returned by . The sub-models have + /// their own bindings and message type. You typically bind this to the + /// ItemsSource of an ItemsControl, ListView, + /// TreeView, etc. + /// + /// Gets the sub-models from the model. + /// + /// Converts the models to the model used by the bindings. + /// + /// Gets a unique identifier for a sub-model. + /// + /// Converts the sub-model ID and messages used in the bindings to parent + /// model messages (e.g. a parent message union case that wraps the + /// sub-model ID and message type). + /// + /// Returns the bindings for the sub-model. + static member subModelSeq + ( + getSubModels: 'model -> #seq<'subModel>, + toBindingModel: 'model * 'subModel -> 'bindingModel, + getId: 'bindingModel -> 'id, + toMsg: 'id * 'bindingMsg -> 'msg, + bindings: unit -> Binding<'bindingModel, 'bindingMsg> list + ) : string -> Binding<'model, 'msg> = + Binding.SubModelSeqKeyed.create + (fun args -> DynamicViewModel<'bindingModel, 'bindingMsg>(args, bindings ())) + IViewModel.updateModel + getId + (IViewModel.currentModel >> getId) + >> Binding.mapModel (fun m -> + getSubModels m + |> Seq.map (fun sub -> toBindingModel (m, sub))) + >> Binding.mapMsg toMsg + + + /// + /// Creates a binding to a sequence of sub-models, each uniquely identified + /// by the value returned by . The sub-models have + /// their own bindings and message type. You typically bind this to the + /// ItemsSource of an ItemsControl, ListView, + /// TreeView, etc. + /// + /// Gets the sub-models from the model. + /// Gets a unique identifier for a sub-model. + /// + /// Converts the sub-model ID and messages used in the bindings to parent + /// model messages (e.g. a parent message union case that wraps the + /// sub-model ID and message type). + /// + /// Returns the bindings for the sub-model. + static member subModelSeq + ( + getSubModels: 'model -> #seq<'subModel>, + getId: 'subModel -> 'id, + toMsg: 'id * 'subMsg -> 'msg, + bindings: unit -> Binding<'model * 'subModel, 'subMsg> list + ) : string -> Binding<'model, 'msg> = + Binding.SubModelSeqKeyed.create + (fun args -> DynamicViewModel<'model * 'subModel, 'subMsg>(args, bindings ())) + IViewModel.updateModel + (snd >> getId) + (IViewModel.currentModel >> snd >> getId) + >> Binding.mapModel (fun m -> getSubModels m |> Seq.map (fun sub -> (m, sub))) + >> Binding.mapMsg toMsg + + + /// + /// Creates a binding to a sequence of sub-models, each uniquely identified + /// by the value returned by . The sub-models have + /// their own bindings. You typically bind this to the ItemsSource of + /// an + /// ItemsControl, ListView, TreeView, etc. + /// + /// Gets the sub-models from the model. + /// Gets a unique identifier for a sub-model. + /// Returns the bindings for the sub-model. + static member subModelSeq + ( + getSubModels: 'model -> #seq<'subModel>, + getId: 'subModel -> 'id, + bindings: unit -> Binding<'model * 'subModel, 'msg> list + ) : string -> Binding<'model, 'msg> = + Binding.SubModelSeqKeyed.create + (fun args -> DynamicViewModel<'model * 'subModel, 'msg>(args, bindings ())) + IViewModel.updateModel + (snd >> getId) + (IViewModel.currentModel >> snd >> getId) + >> Binding.mapModel (fun m -> getSubModels m |> Seq.map (fun sub -> (m, sub))) + >> Binding.mapMsg snd /// /// Creates a two-way binding to a SelectedItem-like property where /// the /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF - /// view models to/from their corresponding IDs, so the Elmish user code - /// only has to work with the IDs. + /// binding. Automatically converts the dynamically created Elmish.WPF view + /// models to/from their corresponding IDs, so the Elmish user code only has + /// to work with the IDs. /// - /// Only use this if you are unable to use some kind of - /// SelectedValue or + /// Only use this if you are unable to use some kind of SelectedValue + /// or /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when - /// initializing the bindings if - /// does not correspond to a binding, and it - /// will throw at runtime if the inferred 'id type does not - /// match the actual ID type used in that binding. + /// binding. This binding is less type-safe. It will throw when initializing + /// the bindings if + /// does not correspond to a binding, and it will + /// throw at runtime if the inferred 'id type does not match the + /// actual ID type used in that binding. /// /// /// The name of the binding used as the items @@ -4058,33 +2830,33 @@ module Extensions = /// Returns the message to dispatch on selections/de-selections. /// static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id voption, - set: 'id voption -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.SubModelSelectedItem.vopt subModelSeqBindingName - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addCaching + ( + 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 /// /// Creates a two-way binding to a SelectedItem-like property where /// the /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF - /// view models to/from their corresponding IDs, so the Elmish user code - /// only has to work with the IDs. + /// binding. Automatically converts the dynamically created Elmish.WPF view + /// models to/from their corresponding IDs, so the Elmish user code only has + /// to work with the IDs. /// - /// Only use this if you are unable to use some kind of - /// SelectedValue or + /// Only use this if you are unable to use some kind of SelectedValue + /// or /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when - /// initializing the bindings if - /// does not correspond to a binding, and it - /// will throw at runtime if the inferred 'id type does not - /// match the actual ID type used in that binding. + /// binding. This binding is less type-safe. It will throw when initializing + /// the bindings if + /// does not correspond to a binding, and it will + /// throw at runtime if the inferred 'id type does not match the + /// actual ID type used in that binding. /// /// /// The name of the binding used as the items @@ -4101,32 +2873,32 @@ module Extensions = /// [] static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id voption, - set: 'id voption -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.subModelSelectedItem (subModelSeqBindingName, get, set) - >> Binding.alterMsgStream wrapDispatch + ( + subModelSeqBindingName: string, + get: 'model -> 'id voption, + set: 'id voption -> 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.subModelSelectedItem (subModelSeqBindingName, get, set) + >> Binding.alterMsgStream wrapDispatch /// /// Creates a two-way binding to a SelectedItem-like property where /// the /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF - /// view models to/from their corresponding IDs, so the Elmish user code - /// only has to work with the IDs. + /// binding. Automatically converts the dynamically created Elmish.WPF view + /// models to/from their corresponding IDs, so the Elmish user code only has + /// to work with the IDs. /// - /// Only use this if you are unable to use some kind of - /// SelectedValue or + /// Only use this if you are unable to use some kind of SelectedValue + /// or /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when - /// initializing the bindings if - /// does not correspond to a binding, and it - /// will throw at runtime if the inferred 'id type does not - /// match the actual ID type used in that binding. + /// binding. This binding is less type-safe. It will throw when initializing + /// the bindings if + /// does not correspond to a binding, and it will + /// throw at runtime if the inferred 'id type does not match the + /// actual ID type used in that binding. /// /// /// The name of the binding used as the items @@ -4138,33 +2910,33 @@ module Extensions = /// Returns the message to dispatch on selections/de-selections. /// static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id option, - set: 'id option -> 'msg) - : string -> Binding<'model, 'msg> = - Binding.SubModelSelectedItem.opt subModelSeqBindingName - >> Binding.addLazy (=) - >> Binding.mapModel get - >> Binding.mapMsg set - >> Binding.addCaching + ( + subModelSeqBindingName: string, + get: 'model -> 'id option, + set: 'id option -> 'model -> 'msg + ) : string -> Binding<'model, 'msg> = + Binding.SubModelSelectedItem.opt subModelSeqBindingName + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsgWithModel set + >> Binding.addCaching /// /// Creates a two-way binding to a SelectedItem-like property where /// the /// ItemsSource-like property is a - /// binding. Automatically converts the dynamically created Elmish.WPF - /// view models to/from their corresponding IDs, so the Elmish user code - /// only has to work with the IDs. + /// binding. Automatically converts the dynamically created Elmish.WPF view + /// models to/from their corresponding IDs, so the Elmish user code only has + /// to work with the IDs. /// - /// Only use this if you are unable to use some kind of - /// SelectedValue or + /// Only use this if you are unable to use some kind of SelectedValue + /// or /// SelectedIndex property with a normal - /// binding. This binding is less type-safe. It will throw when - /// initializing the bindings if - /// does not correspond to a binding, and it - /// will throw at runtime if the inferred 'id type does not - /// match the actual ID type used in that binding. + /// binding. This binding is less type-safe. It will throw when initializing + /// the bindings if + /// does not correspond to a binding, and it will + /// throw at runtime if the inferred 'id type does not match the + /// actual ID type used in that binding. /// /// /// The name of the binding used as the items @@ -4181,10 +2953,1281 @@ module Extensions = /// [] static member subModelSelectedItem - (subModelSeqBindingName: string, - get: 'model -> 'id option, - set: 'id option -> 'msg, - wrapDispatch: Dispatch<'msg> -> Dispatch<'msg>) - : string -> Binding<'model, 'msg> = - Binding.subModelSelectedItem (subModelSeqBindingName, get, set) - >> Binding.alterMsgStream wrapDispatch + ( + subModelSeqBindingName: string, + get: 'model -> 'id option, + set: 'id option -> 'model -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.subModelSelectedItem (subModelSeqBindingName, get, set) + >> Binding.alterMsgStream wrapDispatch + + + +// Some members are implemented as extensions to help overload resolution +[] +module Extensions = + + type Binding with + + /// Creates a one-way-to-source binding. + /// Returns the message to dispatch. + static member oneWayToSource(set: 'a -> 'msg) : string -> Binding<'model, 'msg> = + Binding.OneWayToSource.id<'model, 'a> + >> Binding.mapMsg set + + /// + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + /// + /// Returns the message to dispatch. + static member oneWayToSourceOpt(set: 'a option -> 'msg) : string -> Binding<'model, 'msg> = + Binding.OneWayToSource.opt >> Binding.mapMsg set + + /// + /// Creates a one-way-to-source binding to an optional value. The binding + /// automatically converts between a missing value in the model and + /// a null value in the view. + /// + /// Returns the message to dispatch. + static member oneWayToSourceOpt(set: 'a voption -> 'msg) : string -> Binding<'model, 'msg> = + Binding.OneWayToSource.vopt >> Binding.mapMsg set + + + /// Creates a two-way binding. + /// Gets the value from the model. + /// Returns the message to dispatch. + static member twoWay(get: 'model -> 'a, set: 'a -> 'msg) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + + /// Creates a two-way binding. + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWay + ( + get: 'model -> 'a, + set: 'a -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWay (get, set) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between the optional source value and an + /// unwrapped (possibly null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + static member twoWayOpt(get: 'model -> 'a option, set: 'a option -> 'msg) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + + /// + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between the optional source value and an + /// unwrapped (possibly null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOpt + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOpt (get, set) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between the optional source value and an + /// unwrapped (possibly null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + static member twoWayOpt(get: 'model -> 'a voption, set: 'a voption -> 'msg) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + + /// + /// Creates a two-way binding to an optional value. The binding + /// automatically converts between the optional source value and an + /// unwrapped (possibly null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOpt + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOpt (get, set) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation messages from the updated model. + /// + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> string list + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation validate + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation messages from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> string list, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> string voption + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation (validate >> ValueOption.toList) + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> string voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> string option + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation (validate >> Option.toList) + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> string option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> Result<'ignored, string> + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.id<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation ( + validate + >> ValueOption.ofError + >> ValueOption.toList + ) + + /// + /// Creates a two-way binding with validation using + /// INotifyDataErrorInfo. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayValidate + ( + get: 'model -> 'a, + set: 'a -> 'msg, + validate: 'model -> Result<'ignored, string>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation messages from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> string list + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation validate + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation messages from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> string list, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> string voption + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation (validate >> ValueOption.toList) + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> string voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> string option + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation (validate >> Option.toList) + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> string option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> Result<'ignored, string> + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.vopt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation ( + validate + >> ValueOption.ofError + >> ValueOption.toList + ) + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a voption, + set: 'a voption -> 'msg, + validate: 'model -> Result<'ignored, string>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation messages from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> string list + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation validate + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation messages from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> string list, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> string voption + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation (validate >> ValueOption.toList) + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> string voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> string option + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation (validate >> Option.toList) + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> string option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> Result<'ignored, string> + ) : string -> Binding<'model, 'msg> = + Binding.TwoWay.opt<'a> + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addValidation ( + validate + >> ValueOption.ofError + >> ValueOption.toList + ) + + /// + /// Creates a two-way binding to an optional value with validation using + /// INotifyDataErrorInfo. The binding automatically converts + /// between the optional source value and an unwrapped (possibly + /// null) value on the view side. + /// + /// Gets the value from the model. + /// Returns the message to dispatch. + /// + /// Returns the validation message from the updated model. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member twoWayOptValidate + ( + get: 'model -> 'a option, + set: 'a option -> 'msg, + validate: 'model -> Result<'ignored, string>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.twoWayOptValidate (get, set, validate) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a Command binding that dispatches the specified message + /// and can always execute. + /// + /// Returns the message to dispatch. + static member cmd(exec: 'msg) : string -> Binding<'model, 'msg> = + Binding.Cmd.create (fun _ -> exec |> ValueSome) (fun _ -> true) + + /// + /// Creates a Command binding that dispatches the specified message + /// and can always execute. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmd + ( + exec: 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmd exec + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a Command binding that dispatches the specified message + /// and can execute if returns true. + /// + /// Returns the message to dispatch. + /// Indicates whether the command can execute. + static member cmdIf(exec: 'msg, canExec: 'model -> bool) : string -> Binding<'model, 'msg> = + Binding.Cmd.create (fun _ -> exec |> ValueSome) canExec + + /// + /// Creates a Command binding that dispatches the specified message + /// and can execute if returns true. + /// + /// Returns the message to dispatch. + /// Indicates whether the command can execute. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdIf + ( + exec: 'msg, + canExec: 'model -> bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdIf (exec, canExec) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a Command binding that depends on the + /// CommandParameter + /// and can always execute. + /// + /// Returns the message to dispatch. + static member cmdParam(exec: obj -> 'msg) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam (fun p _ -> exec p |> ValueSome) (fun _ _ -> true) false + + /// + /// Creates a Command binding that depends on the + /// CommandParameter + /// and can always execute. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParam + ( + exec: obj -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParam exec + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns ValueSome. + /// + /// Returns the message to dispatch. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + static member cmdParamIf(exec: obj -> 'msg voption, ?uiBoundCmdParam: bool) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam + (fun p _ -> exec p) + (fun p _ -> exec p |> ValueOption.isSome) + (defaultArg uiBoundCmdParam false) + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns ValueSome. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> 'msg voption, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf exec + >> Binding.alterMsgStream wrapDispatch + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns ValueSome. + /// + /// Returns the message to dispatch. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> 'msg voption, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns Some. + /// + /// Returns the message to dispatch. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + static member cmdParamIf(exec: obj -> 'msg option, ?uiBoundCmdParam: bool) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam + (fun p _ -> exec p |> ValueOption.ofOption) + (fun p _ -> exec p |> Option.isSome) + (defaultArg uiBoundCmdParam false) + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns Some. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> 'msg option, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf exec + >> Binding.alterMsgStream wrapDispatch + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns Some. + /// + /// Returns the message to dispatch. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> 'msg option, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns Ok. + /// + /// This overload allows more easily re-using the same validation + /// functions for inputs and commands. + /// + /// Returns the message to dispatch. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + static member cmdParamIf + ( + exec: obj -> Result<'msg, 'ignored>, + ?uiBoundCmdParam: bool + ) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam + (fun p _ -> exec p |> ValueOption.ofOk) + (fun p _ -> exec p |> Result.isOk) + (defaultArg uiBoundCmdParam false) + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns Ok. + /// + /// This overload allows more easily re-using the same validation + /// functions for inputs and commands. + /// + /// Returns the message to dispatch. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> Result<'msg, 'ignored>, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf exec + >> Binding.alterMsgStream wrapDispatch + + /// + /// Creates a conditional Command binding that depends on the + /// CommandParameter + /// and can execute if returns Ok. + /// + /// This overload allows more easily re-using the same validation + /// functions for inputs and commands. + /// + /// Returns the message to dispatch. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> Result<'msg, 'ignored>, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a Command binding that depends on the + /// CommandParameter + /// and can execute if returns true. + /// + /// Returns the message to dispatch. + /// Indicates whether the command can execute. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + static member cmdParamIf + ( + exec: obj -> 'msg, + canExec: obj -> bool, + ?uiBoundCmdParam: bool + ) : string -> Binding<'model, 'msg> = + Binding.Cmd.createWithParam + (fun p _ -> exec p |> ValueSome) + (fun p _ -> canExec p) + (defaultArg uiBoundCmdParam false) + + /// + /// Creates a Command binding that depends on the + /// CommandParameter + /// and can execute if returns true. + /// + /// Returns the message to dispatch. + /// Indicates whether the command can execute. + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> 'msg, + canExec: obj -> bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, canExec) + >> Binding.alterMsgStream wrapDispatch + + /// + /// Creates a Command binding that depends on the + /// CommandParameter + /// and can execute if returns true. + /// + /// Returns the message to dispatch. + /// Indicates whether the command can execute. + /// + /// If true, CanExecuteChanged will trigger every time WPF's + /// CommandManager + /// detects UI changes that could potentially influence the command's + /// ability to execute. This will likely lead to many more triggers than + /// necessary, but is needed if you have bound the CommandParameter + /// to another UI property. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member cmdParamIf + ( + exec: obj -> 'msg, + canExec: obj -> bool, + uiBoundCmdParam: bool, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.cmdParamIf (exec, canExec, uiBoundCmdParam) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to a SelectedItem-like property where + /// the + /// ItemsSource-like property is a + /// binding. Automatically converts the dynamically created Elmish.WPF + /// view models to/from their corresponding IDs, so the Elmish user code + /// only has to work with the IDs. + /// + /// Only use this if you are unable to use some kind of + /// SelectedValue or + /// SelectedIndex property with a normal + /// binding. This binding is less type-safe. It will throw when + /// initializing the bindings if + /// does not correspond to a binding, and it + /// will throw at runtime if the inferred 'id type does not + /// match the actual ID type used in that binding. + /// + /// + /// The name of the binding used as the items + /// source. + /// + /// Gets the selected sub-model/sub-binding ID from the + /// model. + /// + /// Returns the message to dispatch on selections/de-selections. + /// + static member subModelSelectedItem + ( + subModelSeqBindingName: string, + get: 'model -> 'id voption, + set: 'id voption -> 'msg + ) : string -> Binding<'model, 'msg> = + Binding.SubModelSelectedItem.vopt subModelSeqBindingName + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addCaching + + /// + /// Creates a two-way binding to a SelectedItem-like property where + /// the + /// ItemsSource-like property is a + /// binding. Automatically converts the dynamically created Elmish.WPF + /// view models to/from their corresponding IDs, so the Elmish user code + /// only has to work with the IDs. + /// + /// Only use this if you are unable to use some kind of + /// SelectedValue or + /// SelectedIndex property with a normal + /// binding. This binding is less type-safe. It will throw when + /// initializing the bindings if + /// does not correspond to a binding, and it + /// will throw at runtime if the inferred 'id type does not + /// match the actual ID type used in that binding. + /// + /// + /// The name of the binding used as the items + /// source. + /// + /// Gets the selected sub-model/sub-binding ID from the + /// model. + /// + /// Returns the message to dispatch on selections/de-selections. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member subModelSelectedItem + ( + subModelSeqBindingName: string, + get: 'model -> 'id voption, + set: 'id voption -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.subModelSelectedItem (subModelSeqBindingName, get, set) + >> Binding.alterMsgStream wrapDispatch + + + /// + /// Creates a two-way binding to a SelectedItem-like property where + /// the + /// ItemsSource-like property is a + /// binding. Automatically converts the dynamically created Elmish.WPF + /// view models to/from their corresponding IDs, so the Elmish user code + /// only has to work with the IDs. + /// + /// Only use this if you are unable to use some kind of + /// SelectedValue or + /// SelectedIndex property with a normal + /// binding. This binding is less type-safe. It will throw when + /// initializing the bindings if + /// does not correspond to a binding, and it + /// will throw at runtime if the inferred 'id type does not + /// match the actual ID type used in that binding. + /// + /// + /// The name of the binding used as the items + /// source. + /// + /// Gets the selected sub-model/sub-binding ID from the + /// model. + /// + /// Returns the message to dispatch on selections/de-selections. + /// + static member subModelSelectedItem + ( + subModelSeqBindingName: string, + get: 'model -> 'id option, + set: 'id option -> 'msg + ) : string -> Binding<'model, 'msg> = + Binding.SubModelSelectedItem.opt subModelSeqBindingName + >> Binding.addLazy (=) + >> Binding.mapModel get + >> Binding.mapMsg set + >> Binding.addCaching + + /// + /// Creates a two-way binding to a SelectedItem-like property where + /// the + /// ItemsSource-like property is a + /// binding. Automatically converts the dynamically created Elmish.WPF + /// view models to/from their corresponding IDs, so the Elmish user code + /// only has to work with the IDs. + /// + /// Only use this if you are unable to use some kind of + /// SelectedValue or + /// SelectedIndex property with a normal + /// binding. This binding is less type-safe. It will throw when + /// initializing the bindings if + /// does not correspond to a binding, and it + /// will throw at runtime if the inferred 'id type does not + /// match the actual ID type used in that binding. + /// + /// + /// The name of the binding used as the items + /// source. + /// + /// Gets the selected sub-model/sub-binding ID from the + /// model. + /// + /// Returns the message to dispatch on selections/de-selections. + /// + /// + /// Wraps the dispatch function with additional behavior, such as + /// throttling, debouncing, or limiting. + /// + [] + static member subModelSelectedItem + ( + subModelSeqBindingName: string, + get: 'model -> 'id option, + set: 'id option -> 'msg, + wrapDispatch: Dispatch<'msg> -> Dispatch<'msg> + ) : string -> Binding<'model, 'msg> = + Binding.subModelSelectedItem (subModelSeqBindingName, get, set) + >> Binding.alterMsgStream wrapDispatch diff --git a/src/Samples/Samples.generated.sln b/src/Samples/Samples.generated.sln new file mode 100644 index 00000000..a8dded5b --- /dev/null +++ b/src/Samples/Samples.generated.sln @@ -0,0 +1,121 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capabilities", "Capabilities\Capabilities.csproj", "{11D2A55F-9315-4538-B3E4-44868816E81C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBindingsAndBehaviors", "EventBindingsAndBehaviors\EventBindingsAndBehaviors.csproj", "{26B784E2-4A97-49CB-9DD2-AD23F85A999D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileDialogs", "FileDialogs\FileDialogs.csproj", "{49005859-27DB-4A96-B80F-2C15AFF1A828}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileDialogsCmdMsg", "FileDialogsCmdMsg\FileDialogsCmdMsg.csproj", "{1E366BD6-1750-4150-A6AC-2615551E0E51}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Multiselect", "Multiselect\Multiselect.csproj", "{E81053F1-ACE1-4439-BA6A-162E3EA4E407}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NewWindow", "NewWindow\NewWindow.csproj", "{F6734731-8849-4D1E-A1CF-95CF091E3EC3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneWaySeq", "OneWaySeq\OneWaySeq.csproj", "{C2932EB2-16DF-48D8-8044-4A517815AF50}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SingleCounter", "SingleCounter\SingleCounter.csproj", "{96A6B550-E41C-4029-9D24-D1B1AD60954B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sticky", "Sticky\Sticky.csproj", "{0E7F8A17-5F75-434C-B0A7-EC83783E9BB8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SubModel", "SubModel\SubModel.csproj", "{6D0A8947-5A9D-4A50-AC0C-D797EE87640B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SubModelOpt", "SubModelOpt\SubModelOpt.csproj", "{F0069157-09E3-40DD-97D6-B5A3D3C42C8B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SubModelSelectedItem", "SubModelSelectedItem\SubModelSelectedItem.csproj", "{FC4518FB-73DD-480B-B652-61F8CD20255B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SubModelSeq", "SubModelSeq\SubModelSeq.csproj", "{5B197AC6-9D9A-46A9-B3E8-DC33AB855159}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SubModelStatic", "SubModelStatic\SubModelStatic.csproj", "{D345CFDA-A4C8-4FFD-A1BD-97BBB4291189}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Threading", "Threading\Threading.csproj", "{1E9C54A2-B9DD-4F97-85B9-0DF52FD3202A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiBoundCmdParam", "UiBoundCmdParam\UiBoundCmdParam.csproj", "{C75025E1-20AA-4F16-820E-E7B184D7DFBC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Validation", "Validation\Validation.csproj", "{1B62316F-F093-443F-ACF4-68CC21E89E23}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {11D2A55F-9315-4538-B3E4-44868816E81C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11D2A55F-9315-4538-B3E4-44868816E81C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11D2A55F-9315-4538-B3E4-44868816E81C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11D2A55F-9315-4538-B3E4-44868816E81C}.Release|Any CPU.Build.0 = Release|Any CPU + {26B784E2-4A97-49CB-9DD2-AD23F85A999D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26B784E2-4A97-49CB-9DD2-AD23F85A999D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26B784E2-4A97-49CB-9DD2-AD23F85A999D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26B784E2-4A97-49CB-9DD2-AD23F85A999D}.Release|Any CPU.Build.0 = Release|Any CPU + {49005859-27DB-4A96-B80F-2C15AFF1A828}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {49005859-27DB-4A96-B80F-2C15AFF1A828}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49005859-27DB-4A96-B80F-2C15AFF1A828}.Release|Any CPU.ActiveCfg = Release|Any CPU + {49005859-27DB-4A96-B80F-2C15AFF1A828}.Release|Any CPU.Build.0 = Release|Any CPU + {1E366BD6-1750-4150-A6AC-2615551E0E51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E366BD6-1750-4150-A6AC-2615551E0E51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E366BD6-1750-4150-A6AC-2615551E0E51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E366BD6-1750-4150-A6AC-2615551E0E51}.Release|Any CPU.Build.0 = Release|Any CPU + {E81053F1-ACE1-4439-BA6A-162E3EA4E407}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E81053F1-ACE1-4439-BA6A-162E3EA4E407}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E81053F1-ACE1-4439-BA6A-162E3EA4E407}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E81053F1-ACE1-4439-BA6A-162E3EA4E407}.Release|Any CPU.Build.0 = Release|Any CPU + {F6734731-8849-4D1E-A1CF-95CF091E3EC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6734731-8849-4D1E-A1CF-95CF091E3EC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6734731-8849-4D1E-A1CF-95CF091E3EC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6734731-8849-4D1E-A1CF-95CF091E3EC3}.Release|Any CPU.Build.0 = Release|Any CPU + {C2932EB2-16DF-48D8-8044-4A517815AF50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2932EB2-16DF-48D8-8044-4A517815AF50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2932EB2-16DF-48D8-8044-4A517815AF50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2932EB2-16DF-48D8-8044-4A517815AF50}.Release|Any CPU.Build.0 = Release|Any CPU + {96A6B550-E41C-4029-9D24-D1B1AD60954B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96A6B550-E41C-4029-9D24-D1B1AD60954B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96A6B550-E41C-4029-9D24-D1B1AD60954B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96A6B550-E41C-4029-9D24-D1B1AD60954B}.Release|Any CPU.Build.0 = Release|Any CPU + {0E7F8A17-5F75-434C-B0A7-EC83783E9BB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E7F8A17-5F75-434C-B0A7-EC83783E9BB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E7F8A17-5F75-434C-B0A7-EC83783E9BB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E7F8A17-5F75-434C-B0A7-EC83783E9BB8}.Release|Any CPU.Build.0 = Release|Any CPU + {6D0A8947-5A9D-4A50-AC0C-D797EE87640B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D0A8947-5A9D-4A50-AC0C-D797EE87640B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D0A8947-5A9D-4A50-AC0C-D797EE87640B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D0A8947-5A9D-4A50-AC0C-D797EE87640B}.Release|Any CPU.Build.0 = Release|Any CPU + {F0069157-09E3-40DD-97D6-B5A3D3C42C8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0069157-09E3-40DD-97D6-B5A3D3C42C8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0069157-09E3-40DD-97D6-B5A3D3C42C8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0069157-09E3-40DD-97D6-B5A3D3C42C8B}.Release|Any CPU.Build.0 = Release|Any CPU + {FC4518FB-73DD-480B-B652-61F8CD20255B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC4518FB-73DD-480B-B652-61F8CD20255B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC4518FB-73DD-480B-B652-61F8CD20255B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC4518FB-73DD-480B-B652-61F8CD20255B}.Release|Any CPU.Build.0 = Release|Any CPU + {5B197AC6-9D9A-46A9-B3E8-DC33AB855159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B197AC6-9D9A-46A9-B3E8-DC33AB855159}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B197AC6-9D9A-46A9-B3E8-DC33AB855159}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B197AC6-9D9A-46A9-B3E8-DC33AB855159}.Release|Any CPU.Build.0 = Release|Any CPU + {D345CFDA-A4C8-4FFD-A1BD-97BBB4291189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D345CFDA-A4C8-4FFD-A1BD-97BBB4291189}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D345CFDA-A4C8-4FFD-A1BD-97BBB4291189}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D345CFDA-A4C8-4FFD-A1BD-97BBB4291189}.Release|Any CPU.Build.0 = Release|Any CPU + {1E9C54A2-B9DD-4F97-85B9-0DF52FD3202A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E9C54A2-B9DD-4F97-85B9-0DF52FD3202A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E9C54A2-B9DD-4F97-85B9-0DF52FD3202A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E9C54A2-B9DD-4F97-85B9-0DF52FD3202A}.Release|Any CPU.Build.0 = Release|Any CPU + {C75025E1-20AA-4F16-820E-E7B184D7DFBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C75025E1-20AA-4F16-820E-E7B184D7DFBC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C75025E1-20AA-4F16-820E-E7B184D7DFBC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C75025E1-20AA-4F16-820E-E7B184D7DFBC}.Release|Any CPU.Build.0 = Release|Any CPU + {1B62316F-F093-443F-ACF4-68CC21E89E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B62316F-F093-443F-ACF4-68CC21E89E23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B62316F-F093-443F-ACF4-68CC21E89E23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B62316F-F093-443F-ACF4-68CC21E89E23}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EAE8C9E3-06B3-4889-8E00-600FB55BEA5E} + EndGlobalSection +EndGlobal diff --git a/src/Samples/SubModelSelectedItem.Core/Program.fs b/src/Samples/SubModelSelectedItem.Core/Program.fs index c8f970af..bc62051b 100644 --- a/src/Samples/SubModelSelectedItem.Core/Program.fs +++ b/src/Samples/SubModelSelectedItem.Core/Program.fs @@ -1,57 +1,523 @@ -module Elmish.WPF.Samples.SubModelSelectedItem.Program +namespace Program open System +open Elmish +open Elmish.WPF open Serilog open Serilog.Extensions.Logging -open Elmish.WPF +open System.Windows.Media + + +[] +module Helpers = + + //• logging + let createDashedLine () = String.replicate 69 "-" + let logDashedLine = createDashedLine () + + + let generateName (prefix: string) = + let randomNumber () = Random().Next(1000, 10000).ToString() + prefix + randomNumber () + + + +module TextBox = + + type Model = { Id: Guid; Text: string } + + let create () = + { Id = Guid.NewGuid() + Text = generateName "TextBox_" } + + type Msg = | Dummy + + let init () = create () + + let update msg m = + match msg with + | Dummy -> m + + +module CheckBox = + + type Model = { Id: Guid; Label: string } + + let create () = + { Id = Guid.NewGuid() + Label = generateName "CheckBox_" } + + type Msg = | Dummy + + let init () = create () + + let update msg m = + match msg with + | Dummy -> m + + +module ComboBox = + + type Model = + { Id: Guid + Header: string + Items: string list + SelectedItem: string option } + + let create () = + { Id = Guid.NewGuid() + Header = generateName "ComboBox_" + Items = [ "Option1"; "Option2"; "Option3" ] + SelectedItem = None } + + type Msg = SelectItem of string option + + let init () = create () + + let update msg m = + match msg with + | SelectItem item -> { m with SelectedItem = item } + + +//# Form Designer +module App = + + type FormComponent = + | TextBox of TextBox.Model + | CheckBox of CheckBox.Model + | ComboBox of ComboBox.Model + + type Model = + { Components: FormComponent list + PreviousSelectedFormComponent: Guid option + SelectedFormComponent: Guid option + Log: string list } + + module ModelM = + module Components = + let get m = m.Components + + type Msg = + | SelectFormComponent of Guid option + | AddTextBox + | AddCheckBox + | AddComboBox + | RemoveComponent of Guid + | ClearLog + //• SubModels + | TextBox_Msg of Guid * TextBox.Msg + | CheckBox_Msg of Guid * CheckBox.Msg + | ComboBox_Msg of Guid * ComboBox.Msg + + let componentsMock = + [ TextBox(TextBox.create ()) + CheckBox(CheckBox.create ()) + TextBox(TextBox.create ()) + CheckBox(CheckBox.create ()) + ComboBox(ComboBox.create ()) ] + + + let getId (fc: FormComponent) = + match fc with + | TextBox tb -> tb.Id + | CheckBox cb -> cb.Id + | ComboBox cb -> cb.Id + + let init () = + { Components = componentsMock + SelectedFormComponent = Some(getId (List.item 3 componentsMock)) + PreviousSelectedFormComponent = None + Log = [] }, + Cmd.none + + + [] + module private UpdateHelpers = + //🞍 common + let insertAt index item list = + let before, after = List.splitAt index list + before @ [ item ] @ after + + + let getComponentName fc = + match fc with + | TextBox tb -> tb.Text + | CheckBox cb -> cb.Label + | ComboBox cb -> cb.Header + + + let selectFormComponent id m = + let logEntry = + match id with + | Some selectedId -> + match m.Components + |> List.tryFind (fun c -> getId c = selectedId) + with + | Some c -> + let name = getComponentName c + sprintf "Selected: %s" name + | None -> "Selected: Unknown component" + | None -> "Deselected" + + { m with + SelectedFormComponent = id + Log = logEntry :: logDashedLine :: m.Log } + + + //🞍 add/remove + let addTextBox m = + let newTextBox = TextBox.create () + + let updatedTextBox = { newTextBox with Text = "###New### --- " + newTextBox.Text } + + let newComponent = TextBox updatedTextBox + + let components = + match m.SelectedFormComponent with + | Some selectedId -> + match m.Components + |> List.tryFindIndex (fun c -> getId c = selectedId) + with + | Some index -> insertAt (index + 1) newComponent m.Components + | None -> m.Components @ [ newComponent ] + | None -> m.Components @ [ newComponent ] + + let log = + ("Added: " + updatedTextBox.Text) + :: ("Selected: " + updatedTextBox.Text) + :: logDashedLine :: m.Log + + { m with + Components = components + SelectedFormComponent = Some(getId newComponent) + Log = log } + + + let addCheckBox m = + let newCheckBox = CheckBox.create () + + let updatedCheckBox = { newCheckBox with Label = "###New### --- " + newCheckBox.Label } + + let newComponent = CheckBox updatedCheckBox + + let components = + match m.SelectedFormComponent with + | Some selectedId -> + match m.Components + |> List.tryFindIndex (fun c -> getId c = selectedId) + with + | Some index -> insertAt (index + 1) newComponent m.Components + | None -> m.Components @ [ newComponent ] + | None -> m.Components @ [ newComponent ] + + let log = + ("Added: " + updatedCheckBox.Label) + :: ("Selected: " + updatedCheckBox.Label) + :: logDashedLine :: m.Log + + { m with + Components = components + SelectedFormComponent = Some(getId newComponent) + Log = log } + + + let addComboBox m = + let newComboBox = ComboBox.create () + + let updateComboBox = { newComboBox with Header = "###New### --- " + newComboBox.Header } + + let newComponent = ComboBox newComboBox + + let components = + match m.SelectedFormComponent with + | Some selectedId -> + match m.Components + |> List.tryFindIndex (fun c -> getId c = selectedId) + with + | Some index -> insertAt (index + 1) newComponent m.Components + | None -> m.Components @ [ newComponent ] + | None -> m.Components @ [ newComponent ] + + let log = + ("Added: " + updateComboBox.Header) + :: ("Selected: " + updateComboBox.Header) + :: logDashedLine :: m.Log + + { m with + Components = components + SelectedFormComponent = Some(getId newComponent) + Log = log } + + + let removeComponent id m : Model * Guid option * string list = + let componentOpt = + m.Components + |> List.tryFind (fun c -> getId c = id) + + let removedComponentName = + match componentOpt with + | Some c -> getComponentName c + | None -> "Unknown Component" + + let idxOpt = + m.Components + |> List.tryFindIndex (fun c -> getId c = id) + + let components = List.filter (fun c -> getId c <> id) m.Components + + let newSelected = + match idxOpt with + | Some idx when idx > 0 -> Some(getId (List.item (idx - 1) m.Components)) + | Some idx when components.Length > 0 -> Some(getId (List.item 0 components)) + | _ -> None + + let logs = [ "Removed: " + removedComponentName ] + + let m' = { m with Components = components } + + m', newSelected, logs + + + //🞍 SubModels + // maybe refactor later + let textBox_Msg (id, msg) m = + let updateComponent c = + match c with + | TextBox tb when tb.Id = id -> TextBox(TextBox.update msg tb) + | other -> other + + { m with Components = List.map updateComponent m.Components } + + + let checkBox_Msg (id, msg) m = + let updateComponent c = + match c with + | CheckBox cb when cb.Id = id -> CheckBox(CheckBox.update msg cb) + | other -> other + + { m with Components = List.map updateComponent m.Components } + + + let comboBox_Msg (id, msg) m = + let updateComponent c = + match c with + | ComboBox cb when cb.Id = id -> ComboBox(ComboBox.update msg cb) + | other -> other + + { m with Components = List.map updateComponent m.Components } + + + let update msg m : Model * Cmd = + match msg with + | SelectFormComponent id -> + let m' = selectFormComponent id m + m', Cmd.none + | AddTextBox -> + let m' = addTextBox m + m', Cmd.none + | AddCheckBox -> + let m' = addCheckBox m + m', Cmd.none + | AddComboBox -> + let m' = addComboBox m + m', Cmd.none + | RemoveComponent id -> + let m', newSelectedId, logs = removeComponent id m + let cmd = Cmd.ofMsg (SelectFormComponent newSelectedId) + let m'' = { m' with Log = logs @ m'.Log } + m'', cmd + | ClearLog -> { m with Log = [] }, Cmd.none + // SubModels + | TextBox_Msg (id, msg) -> + let m' = textBox_Msg (id, msg) m + m', Cmd.none + | CheckBox_Msg (id, msg) -> + let m' = checkBox_Msg (id, msg) m + m', Cmd.none + | ComboBox_Msg (id, msg) -> + let m' = comboBox_Msg (id, msg) m + m', Cmd.none + + +[] +type TextBox_VM(args) = + inherit ViewModelBase(args) + + //• helpers + + //🅦 TextBox add ctor? TRY MAYBE IT DOEST WORK BECAUSE OF THIS + new() = TextBox_VM(TextBox.init () |> ViewModelArgs.simple) + + //• members + member _.Text = base.Get () (Binding.oneWay ((fun m -> m.Text))) + + +[] +type CheckBox_VM(args) = + inherit ViewModelBase(args) + + //• helpers + new() = CheckBox_VM(CheckBox.init () |> ViewModelArgs.simple) + + //• members + member _.Label = base.Get () (Binding.oneWay ((fun m -> m.Label))) + + +[] +type ComboBox_VM(args) = + inherit ViewModelBase(args) + + new() = ComboBox_VM(ComboBox.init () |> ViewModelArgs.simple) + + member _.Items = base.Get () (Binding.oneWay (fun m -> m.Items)) + member _.Header = base.Get () (Binding.oneWay (fun m -> m.Header)) + + member _.SelectedItem + with get () = + base.Get + () + (Binding.twoWay ((fun (m: ComboBox.Model) -> m.SelectedItem), (fun v _ -> ComboBox.Msg.SelectItem v))) + and set (value) = + base.Set + (value) + (Binding.twoWay ((fun (m: ComboBox.Model) -> m.SelectedItem), (fun v _ -> ComboBox.Msg.SelectItem v))) + + +[] +type FormComponent_VM(args: ViewModelArgs) = + inherit ViewModelBase(args) + + member this.CurrentModel = + (this :> IViewModel) + .CurrentModel + + member this.Model = fst this.CurrentModel + member this.FormComponent = snd this.CurrentModel + + member this.Id = + match this.FormComponent with + | App.FormComponent.TextBox tb -> tb.Id + | App.FormComponent.CheckBox cb -> cb.Id + | App.FormComponent.ComboBox cb -> cb.Id + + member this.ComponentVM: obj = + let id = this.Id + + match this.FormComponent with + | App.FormComponent.TextBox tb -> + upcast TextBox_VM(ViewModelArgs.map (fun _ -> tb) (fun msg -> App.Msg.TextBox_Msg(id, msg)) args) + | App.FormComponent.CheckBox cb -> + upcast CheckBox_VM(ViewModelArgs.map (fun _ -> cb) (fun msg -> App.Msg.CheckBox_Msg(id, msg)) args) + | App.FormComponent.ComboBox cb -> + upcast ComboBox_VM(ViewModelArgs.map (fun _ -> cb) (fun msg -> App.Msg.ComboBox_Msg(id, msg)) args) + + member this.SelectedLabel = + let componentId = this.Id + + base.Get + () + (Binding.oneWay (fun (m, _) -> + if Some componentId = m.SelectedFormComponent then + " • Selected" + else + "")) + + + // can be done in XAML using lots of boilerplate + // I guess that since it's in a ViewModel, there is no "separation of concerns" issues + //# what do you think? + member this.BackgroundColor: Brush = + match this.FormComponent with + | App.FormComponent.TextBox _ -> Brushes.DarkGreen + | App.FormComponent.CheckBox _ -> Brushes.DarkRed + | App.FormComponent.ComboBox _ -> Brushes.DarkOrange + + +// Adjusted App_VM with SelectedComponent having both get and set +[] +type App_VM(args) = + inherit ViewModelBase(args) + + let getId ((_, fc): App.Model * App.FormComponent) = + match fc with + | App.FormComponent.TextBox tb -> tb.Id + | App.FormComponent.CheckBox cb -> cb.Id + | App.FormComponent.ComboBox cb -> cb.Id + + + new() = App_VM((App.init () |> fst) |> ViewModelArgs.simple) + + + member _.Components_VM = + base.Get + () + (Binding.SubModelSeqKeyedT.id (fun args -> FormComponent_VM(args)) getId + >> Binding.mapModel (fun (m: App.Model) -> m.Components |> List.map (fun fc -> (m, fc))) + >> Binding.addLazy (fun m1 m2 -> + m1.SelectedFormComponent = m2.SelectedFormComponent + && m1.Components = m2.Components) + >> Binding.mapMsg (fun (_id, msg) -> msg)) + + + + member _.SelectedComponent + with get () = + base.Get + () + (Binding.subModelSelectedItem ( + "Components_VM", + (fun (m: App.Model) -> m.SelectedFormComponent), + App.Msg.SelectFormComponent + )) + and set value = + base.Set + (value) + (Binding.subModelSelectedItem ( + "Components_VM", + (fun (m: App.Model) -> m.SelectedFormComponent), + App.Msg.SelectFormComponent + )) + -type Entity = - { Id: int - Name: string } -type Model = - { Entities: Entity list - Selected: int option } + member _.AddTextBox = base.Get () (Binding.CmdT.setAlways App.Msg.AddTextBox) + member _.AddCheckBox = base.Get () (Binding.CmdT.setAlways App.Msg.AddCheckBox) + member _.AddComboBox = base.Get () (Binding.CmdT.setAlways App.Msg.AddComboBox) + member _.ClearLog = base.Get () (Binding.CmdT.setAlways App.Msg.ClearLog) -let init () = - { Entities = [0 .. 10] |> List.map (fun i -> { Id = i; Name = sprintf "Entity %i" i}) - Selected = Some 4 } -type Msg = - | Select of int option + member _.RemoveSelectedComponent = + base.Get + () + (Binding.cmdIf (fun (m: App.Model) -> + match m.SelectedFormComponent with + | Some id -> App.Msg.RemoveComponent id |> ValueSome + | None -> ValueNone)) -let update msg m = - match msg with - | Select entityId -> { m with Selected = entityId } -let bindings () : Binding list = [ - "SelectRandom" |> Binding.cmd - (fun m -> m.Entities.Item(Random().Next(m.Entities.Length)).Id |> Some |> Select) - "Deselect" |> Binding.cmd(Select None) + //🅦 review it (put in update?) + member _.Log = + base.Get + () + (Binding.oneWay (fun m -> + let logLength = List.length m.Log + let takeCount = min 40 logLength + String.concat "\n" (List.take takeCount m.Log))) - "Entities" |> Binding.subModelSeq( - (fun m -> m.Entities), - (fun e -> e.Id), - (fun () -> [ - "Name" |> Binding.oneWay (fun (_, e) -> e.Name) - "SelectedLabel" |> Binding.oneWay (fun (m, e) -> if m.Selected = Some e.Id then " - SELECTED" else "") - ])) - "SelectedEntity" |> Binding.subModelSelectedItem("Entities", (fun m -> m.Selected), Select) -] +module Program = -let designVm = ViewModel.designInstance (init ()) (bindings ()) + let main (window) = -let main window = - let logger = - LoggerConfiguration() - .MinimumLevel.Override("Elmish.WPF.Update", Events.LogEventLevel.Verbose) - .MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose) - .MinimumLevel.Override("Elmish.WPF.Performance", Events.LogEventLevel.Verbose) - .WriteTo.Console() - .CreateLogger() + let logger = + LoggerConfiguration() + .MinimumLevel.Override("Elmish.WPF.Update", Events.LogEventLevel.Verbose) + .MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose) + .MinimumLevel.Override("Elmish.WPF.Performance", Events.LogEventLevel.Verbose) + .WriteTo.Console() + .CreateLogger() - WpfProgram.mkSimple init update bindings - |> WpfProgram.withLogger (new SerilogLoggerFactory(logger)) - |> WpfProgram.startElmishLoop window + WpfProgram.mkProgramT App.init App.update App_VM + |> WpfProgram.withLogger (new SerilogLoggerFactory(logger)) + |> WpfProgram.startElmishLoop window diff --git a/src/Samples/SubModelSelectedItem.Core/SubModelSelectedItem.Core.fsproj b/src/Samples/SubModelSelectedItem.Core/SubModelSelectedItem.Core.fsproj index 28983b0f..8c5aa9d0 100644 --- a/src/Samples/SubModelSelectedItem.Core/SubModelSelectedItem.Core.fsproj +++ b/src/Samples/SubModelSelectedItem.Core/SubModelSelectedItem.Core.fsproj @@ -1,25 +1,19 @@ - - + true - net8.0-windows - - - - - + \ No newline at end of file diff --git a/src/Samples/SubModelSelectedItem/App.xaml.cs b/src/Samples/SubModelSelectedItem/App.xaml.cs index 15195c44..b02a9c86 100644 --- a/src/Samples/SubModelSelectedItem/App.xaml.cs +++ b/src/Samples/SubModelSelectedItem/App.xaml.cs @@ -3,18 +3,18 @@ namespace Elmish.WPF.Samples.SubModelSelectedItem { - public partial class App : Application - { - public App() + public partial class App : Application { - this.Activated += StartElmish; - } + public App() + { + this.Activated += StartElmish; + } - private void StartElmish(object sender, EventArgs e) - { - this.Activated -= StartElmish; - Program.main(MainWindow); - } + private void StartElmish(object sender, EventArgs e) + { + this.Activated -= StartElmish; + Program.Program.main(MainWindow); + } - } + } } diff --git a/src/Samples/SubModelSelectedItem/MainWindow.xaml b/src/Samples/SubModelSelectedItem/MainWindow.xaml index a2702e7c..5156d45a 100644 --- a/src/Samples/SubModelSelectedItem/MainWindow.xaml +++ b/src/Samples/SubModelSelectedItem/MainWindow.xaml @@ -1,29 +1,143 @@ - - - - - - - - - - - - - + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + +