acadian-ambulance / vinyl-ui Goto Github PK
View Code? Open in Web Editor NEWFramework for F# Desktop Applications
License: MIT License
Framework for F# Desktop Applications
License: MIT License
Currently, VinylUI does not support bindings for non-structural-equatable types. This is not part of its primary design goals, but it should be supported for working with C# types that do not override Equals and may not be open to modification.
Consider a POCO property type on a model:
type MyModel = {
Address: Address // this is a C# class with plain properties and no overload for Equals
}
You can create bindings on Address, but they would only fire if the model property is given a different Address instance and never when the Address is mutated (the Address properties changed). This is because the Address type's Equals uses reference equality, which is not what we want for the purposes of binding.
To take this a step further, consider this scenario that Acadian actually has in our application:
type MyModel = {
Addresses = Address list // list of C# POCOs
}
In this case, Addresses is an F# list which uses structural equality, so if a new list is given with a different set of Address instances, any bindings on this property are fired as expected. However, if the only change is one or more instances inside the list have been mutated, even if they are put into a new F# list instance, the binding is not fired.
For the singular property (first example), you have a few options, none of them particularly nice:
For the collection property, the above workarounds also apply, but there is another arguably simpler solution:
Framework.start
would create a list of the model type hierarchy's mutable properties, where a "mutable property" is a property that:
It would also create a list of "mutable sequence properties", defined as a property that:
IEnumerable<T>
(seq
)T
has at least one mutable property as defined aboveConsider the following Model type hierarchy:
type MyClass() =
member val Id = 0 with get, set
member val Name = "" with get, set
type SubModel = {
Class: MyClass
}
type MyContainerClass() =
member val Class = MyClass() with get, set
type MyModel = {
Name: string
Sub: SubModel
Container: MyContainerClass
Classes: MyClass list
Values: int ResizeArray
}
The mutable property chains would be:
The only mutable sequence property would be MyModel.Classes
. MyModel.Values
would not be included - detecting changes in mutable collections will not be supported due to the complexity.
Note that MyModel.Container.Class
would not be considered a mutable property in this context since its type is a reference type with public setters. The reason for excluding this is that differences in this property should be computed from its properties, not from the object itself.
Map<PropertyChain, (obj * (PropertyInfo * obj) list) list>
).Model.diff
will need to be changed to recurse into properties of types that have mutable properties, but unlike record types, still do the normal comparison and yielding of a change if unequal.Currently, the change detection in Framework.fs first enumerates all values of all properties for both before and after model instances to find all changes. It then iterates over the changes, looking for a matching binding. This is wasteful since not all properties will be bound.
This enhancement would change the algorithm to only look for changes between the models for properties that are actually bound.
Bind.model.toDataSource tries to set selected in SelectionMode.None which causes an exception when setting the data source in the binder.
The binding system currently only supports binding to properties directly on the model type. Support for nested properties would allow binding to properties of properties of the model type, to any depth. For instance:
type Name =
First: string
Middle: string
Last: string
type Model =
Name: Name
// ... in binding function:
Bind.view(<@ view.FirstNameBox.Text @>).toModel(<@ model.Name.First @>)
Off the top of my head, this doesn't seem like it would be too hard. The quotation processing will need to be changed to be recursive, the binding info types will need PropertyInfo list
instead of just PropertyInfo
, and the change detection in Framework will need to follow the properties recursively to get the value for comparison.
Binding radio buttons to a model property would be nice. Currently, the only way to bind radio buttons to discriminated union values for a model property is shown in the ShapeArea app: create events from the buttons' CheckedChanged events, if they are checked:
// Map the CheckedChanged events, when changing to checked, to the corresponding ShapeChanged event
form.RectangleButton.CheckedChanged
|> Observable.filter (fun _ -> form.RectangleButton.Checked)
|> Observable.mapTo (ShapeChanged Rectangle)
form.EllipseButton.CheckedChanged
|> Observable.filter (fun _ -> form.EllipseButton.Checked)
|> Observable.mapTo (ShapeChanged Ellipse)
Then create an event handler that sets the model property to the event argument. This only binds the view to the model. If model-to-view binding is also desired, a model-to-func binding needs to be written to check the appropriate radio button based on the value.
This is awkward and a lot boilerplate to achieve a simple thing conceptually. It would be great if we had a sensible API to achieve this for us. Not sure what it should look like though, since it involves multiple controls and all existing binding API involves only one control.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.