Releases: fsprojects/Avalonia.FuncUI
1.0.0 RC 1.1.0
What's Changed
- Create a useStateLazy method which takes a callback by @marklam in #277
- Contexts / Environment state by @JaggerJo in #278
- Add a binding for ToggleButton.IsCheckedChangedEvent by @Numpsy in #283
- Update to Avalonia 11.0.0-preview6 by @Numpsy in #282
- Add a DynamicallyAccessedMembers attribute to ViewBuilder.Create by @Numpsy in #288
- data grid bindings by @JaggerJo in #289
- Add theme binding by @melursus23 in #296
- Update README.md by @JaggerJo in #298
- New properties in Avalonia supporting touch scrolling by @marklam in #301
- Remove duplicate Styles.Load extension method in the control catalog by @Numpsy in #291
- Added the DSL to create InlineUIContainers by @Thecentury in #302
- Preview 8 by @JaggerJo in #304
- Drag and Drop functionality by @Numpsy in #295
- Update to Avalonia 11 RC 1 by @Numpsy in #308
- Replace uses of the deprecated IStyleable with StyleKeyOverride by @Numpsy in #310
- Bump version to 1.0.0 rc 1.1.0 by @JaggerJo in #312
New Contributors
- @melursus23 made their first contribution in #296
Full Changelog: 0.6.0-preview8...1.0.0-RC-1.1.0
0.6.0-preview8
What's Changed
- added
StaticComponent
for creating XAML like components with bindings - added
Control.init
to run code once after control instantiation - updated bindings
Full Changelog: 0.6.0-preview7...0.6.0-preview8
0.6.0-preview7
This pre-release contains:
A new overload added to useElmish
hook
initArg
no longer needs to be specified wheninitArg
isunit
.
So this:
let model, dispatch = ctx.useElmish(init, update, ())
Can also be written as this:
let model, dispatch = ctx.useElmish(init, update)
A performance optimization
- See PR #237
0.6.0-preview6
This pre-release version includes:
- Upgraded to Elmish v4
- Completely reworked
useElmish
hook
Upgraded to Elmish v4 (Breaking)
1) Breaking Changes to UI Thread Sync
Program.withSyncDispatch
has been removed in Elmish v4 because the platform specificProgram.runWith___
functions should instead be provided by the library authors.
Additional info
the purpose of the "sync dispatch" is to ensure that UI changes coming from non-UI threads can be properly synchronized via the underlying platform specific dispatcher to avoid race conditions.
Previously, FuncUI automatically configured this within the Program.withHost
function, on behalf of the user, to guard against race conditions that could occur if they called dispatch
from an async
handler.
Avalonia.FuncUI upgrade path
A new Program.runWithAvaloniaSyncDispatch
function has been added that conforms to the new expectation that this should be handled by the library. If you are calling dispatch
from within async
blocks, you will need to use this instead of Program.run
. Otherwise, you will get exceptions, which will force you to use this new function.
Old Elmish v3 Sample with async blocks
Program.mkProgram init update view
|> Program.withHost this
|> Program.run
New Elmish v4 Sample with async blocks
Program.mkProgram init update view
|> Program.withHost this
|> Program.runWithAvaloniaSyncDispatch ()
2) Breaking Changes to Subscriptions
Cmd.ofSub
has been removedProgram.withSubscription
now takes in the state/model, and returns a list of named subscriptions.- Subscription functions must now return
IDisposable
so they can be automatically disposed
The above changes will cause breakage in any FuncUI apps that make use of Program.withSubscription
.
Avalonia.FuncUI upgrade path
Any FuncUI app that was previously using Program.withSubscription
will have to resolve a build error since the function inputs/outputs have changed.
Old Elmish v3 Sample with Multiple Subscriptions
let timer (_state: Clock.State) =
let sub (dispatch: Clock.Msg -> unit) =
let invoke() =
DateTime.Now |> Clock.Msg.Tick |> dispatch
true
DispatcherTimer.Run(Func<bool>(invoke), TimeSpan.FromMilliseconds 1000.0) |> ignore
Cmd.ofSub sub
// Save state when host window is Closed
let onClosedSub (state: Clock.State) =
Cmd.ofSub (fun _ ->
this.Closed.Subscribe(fun e ->
printfn "Saving state: %A" state
)
|> ignore
)
Program.mkSimple (fun () -> Clock.init) Clock.update Clock.view
|> Program.withHost this
|> Program.withSubscription timer
|> Program.withSubscription onClosedSub
|> Program.withConsoleTrace
|> Program.run
New Elmish v4 Sample with Multiple Subscriptions
let subscriptions (_state: Clock.State) : Sub<Clock.Msg> =
let timerSub (dispatch: Clock.Msg -> unit) =
let invoke() =
DateTime.Now |> Clock.Msg.Tick |> dispatch
true
DispatcherTimer.Run(Func<bool>(invoke), TimeSpan.FromMilliseconds 1000.0) // <- IDisposable
let onClosedSub (dispatch: Clock.Msg -> unit) =
this.Closed.Subscribe(fun e -> printfn "The window has been closed.")
// Notes:
// - Each subscription has a unique identifier
// - Subscriptions can be conditionally add/removed from the list based on the passed in model
// - Each subscription returns IDisposable, and is automatically disposed if conditionally removed from the list
[
[ nameof timerSub ], timerSub
[ nameof onClosedSub ], onClosedSub
]
Program.mkSimple Clock.init Clock.update Clock.view
|> Program.withHost this
|> Program.withSubscription subscriptions
|> Program.withConsoleTrace
|> Program.run
Completely reworked useElmish hook (Breaking)
useElmish
now actually uses Elmish 4 under the hood! 🎉
This means that useElmish
can now take advantage of all the great Elmish features like subscriptions and async commands!
It has two main variations of overloads:
- Two that take
init
,update
,initArg
and an optionalmapProgram
(for adding subsriptions or other Elmish extensions) - Two that take
writableModel
,update
and an optionalmapProgram
(for adding subsriptions or other Elmish extensions)
Here is an example from the ChordParserView
sample that uses subscriptions:
let private subscriptions (model: Model) : Sub<Msg> =
let timerSub (dispatch: Msg -> unit) =
let invoke() = dispatch Msg.SetTime; true
DispatcherTimer.Run(invoke, TimeSpan.FromMilliseconds 1000.0)
[
// Dynamically start or stop (Dispose) subscription
if model.Transpose = 0 then
[ nameof timerSub ], timerSub
]
let view () = Component (fun ctx ->
let model, dispatch = ctx.useElmish(init, update, (), Program.withSubscription subscriptions)
//let model, dispatch = ctx.useElmish(init, update, ()) // if no subscriptions are needed
Grid.create [
Thanks to @alfonsogcnunez for paving the way as I relied heavily on his Fable.React.UseElmish implementation!
0.6.0-preview3
This pre-release version includes:
createText
functions in Run, Bold, Italic and Underline elements to easily create text-only inline elements with no other attributes.MaskedTextBox
now correctly accepts its attributes and not onlyTextBox attributes
.
0.6.0-preview2
This pre-release version includes:
- Bindings for
RichTextBlock
and all inline elements. You can take a look at an example using them here. - Support for v11 preview 2 of Avalonia.
0.6.0-preview1
This pre-release version includes:
- Support for v11 preview 1 of Avalonia.
Avalonia.FuncUI v0.5
This release includes a bunch of new stuff:
- New component system inspired by React/Sutil that allows for easier state management via hooks. Take a look at the examples over here: https://github.com/fsprojects/Avalonia.FuncUI/tree/master/src/Examples/Component%20Examples
- The library now uses Avalonia 0.10.12, which includes a lot of new things including Fluent themes.
0.5.0-beta
0.5.0-beta