fabulous-dev / fabulous.avalonia Goto Github PK
View Code? Open in Web Editor NEWDeclarative UIs for Avalonia with F# and MVU, using Fabulous
Home Page: https://docs.fabulous.dev/avalonia
License: Apache License 2.0
Declarative UIs for Avalonia with F# and MVU, using Fabulous
Home Page: https://docs.fabulous.dev/avalonia
License: Apache License 2.0
Context: fabulous-dev/Fabulous#1081 and #243
The Fabulous.Avalonia nuget package (as of 2.0.0-pre10) contains the file Fabulous.Avalonia.targets
which loads the Platform
directory and file project items when the project is loaded. However, it appears these are created before the source files are loaded. So for a new project created from the fabulous-avalonia
template part of the structure is like this:
The ordering of the items is wrong as some of the platform-specific files depend on App.fs
.
In contrast, a project created from the xf-fsharp template in FSharp.Mobile.Templates has the equivalent of the .targets file inlined in the project fiile below the source files so the dependency order is correct.
Also, the samples in this project do something similiar with an Import
of a targets file after the source files. However, I think the approach used by FSharp.Mobile.Templates is preferable as it easier for the user to change.
Hey fabulous, I've tried out the new Notifications API in 2.4.0-pre1 and it seems to work fine for synchronous messages, but when trying to notify from an async process, the Dispatcher throws one of these my way:
System.InvalidOperationException
HResult=0x80131509
Message=Call from invalid thread
Source=Avalonia.Base
StackTrace:
at Avalonia.Threading.Dispatcher.<VerifyAccess>g__ThrowVerifyAccess|16_0() in Avalonia.Threading\Dispatcher.cs:line 182
at Avalonia.AvaloniaObject..ctor() in Avalonia\AvaloniaObject.cs:line 96
at Avalonia.StyledElement..ctor() in Avalonia\StyledElement.cs:line 218
at Avalonia.Visual..ctor()
at Avalonia.Layout.Layoutable..ctor()
at Avalonia.Interactivity.Interactive..ctor()
at Avalonia.Input.InputElement..ctor() in Avalonia.Input\InputElement.cs:line 507
at Avalonia.Controls.Control..ctor()
at Avalonia.Controls.Primitives.TemplatedControl..ctor()
at Avalonia.Controls.ContentControl..ctor()
at Avalonia.Controls.Notifications.NotificationCard..ctor()
at Avalonia.Controls.Notifications.WindowNotificationManager.<Show>d__13.MoveNext()
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
A PR with reproducable examples on the NotificationPage
in the Gallery follows.
It also includes some questions regarding the recent changes towards the concept of CmdMsg
, which I don't understand, seemingly replacing Cmd<'msg>
, which I think I understand by now.
Given that the repo is marked WIP, apologies if you didn't want any bugs reported yet!
Run the gallery sample project using dotnet run --framework net7.0
. If you click any page besides AutoCompleteBox
, and then click AutoCompleteBox
, you hit an ArgumentOutOfRangeException
at Fabulous.Avalonia.Attributes
line 116 (let childNode = node.TreeContext.GetViewNode(box targetColl.[index])
). I printed out the values and found that index
was 0 and targetColl.Count
was also 0. Here's the stack trace:
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
at Avalonia.Collections.AvaloniaList`1.get_Item(Int32 index) in /_/src/Avalonia.Base/Collections/AvaloniaList.cs:line 150
at [email protected](a _arg1, WidgetCollectionItemChanges diffs, IViewNode node) in /Users/nathanglenn/dev/workspaces/dotNET_workspace/Fabulous.Avalonia/src/Fabulous.Avalonia/Attributes.fs:line 118
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at [email protected](a _arg1, WidgetCollectionItemChanges diffs, IViewNode node) in /Users/nathanglenn/dev/workspaces/dotNET_workspace/Fabulous.Avalonia/src/Fabulous.Avalonia/Attributes.fs:line 120
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at [email protected](a _arg1, WidgetCollectionItemChanges diffs, IViewNode node) in /Users/nathanglenn/dev/workspaces/dotNET_workspace/Fabulous.Avalonia/src/Fabulous.Avalonia/Attributes.fs:line 120
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at [email protected](WidgetDiff diff, IViewNode node)
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at [email protected](WidgetDiff diff, IViewNode node)
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at [email protected](a _arg1, WidgetCollectionItemChanges diffs, IViewNode node) in /Users/nathanglenn/dev/workspaces/dotNET_workspace/Fabulous.Avalonia/src/Fabulous.Avalonia/Attributes.fs:line 120
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at [email protected](WidgetDiff diff, IViewNode node)
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at Fabulous.Avalonia.ApplicationUpdaters.mainWindowApplyDiff(WidgetDiff diff, IViewNode node) in /Users/nathanglenn/dev/workspaces/dotNET_workspace/Fabulous.Avalonia/src/Fabulous.Avalonia/Widgets/Application.fs:line 67
at [email protected](WidgetDiff diff, IViewNode node)
at Fabulous.ViewNode.Fabulous.IViewNode.ApplyDiff(WidgetDiff& diff)
at Fabulous.Reconciler.update(FSharpFunc`2 canReuseView, FSharpValueOption`1 prevOpt, Widget next, IViewNode node)
at [email protected](Unit unitVar0)
at [email protected]()
at Avalonia.Threading.JobRunner.Job.Avalonia.Threading.JobRunner.IJob.Run() in /_/src/Avalonia.Base/Threading/JobRunner.cs:line 193
at Avalonia.Threading.JobRunner.RunJobs(Nullable`1 priority) in /_/src/Avalonia.Base/Threading/JobRunner.cs:line 38
at Avalonia.Native.PlatformThreadingInterface.SignaledCallback.Signaled(Int32 priority, Int32 priorityContainsMeaningfulValue) in /_/src/Avalonia.Native/PlatformThreadingInterface.cs:line 39
at Avalonia.Native.Interop.Impl.__MicroComIAvnSignaledCallbackVTable.Signaled(Void* this, Int32 priority, Int32 priorityContainsMeaningfulValue) in /_/src/Avalonia.Native/Interop.Generated.cs:line 4586
--- End of stack trace from previous location ---
at Avalonia.Native.PlatformThreadingInterface.RunLoop(CancellationToken cancellationToken) in /_/src/Avalonia.Native/PlatformThreadingInterface.cs:line 90
at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken) in /_/src/Avalonia.Base/Threading/Dispatcher.cs:line 61
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 120
at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime[T](T builder, String[] args, ShutdownMode shutdownMode) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 209
at Gallery.Desktop.Program.main(String[] argv) in /Users/nathanglenn/dev/workspaces/dotNET_workspace/Fabulous.Avalonia/samples/Gallery/Platform/Desktop/Program.fs:line 20
Hi :)
I remember this project having two different APIs, one inspired by SwiftUI and the classical Elm Architecture.
I assume, you just went with the former, deleted the old repo, and set up a new project?
It seems a bit confusing for somebody, who wants to catch up, as it seems like I can't trust my memory anymore ๐
Pseudocode:
new Avalonia.Window().Show() --> Application.Windows[1]
Application(Window())
Application() {
Window()
Window() --> Fabulous can not add to ReadOnlyList
}
Application() {
// This is the main window
Window(...)
// This is the second window
Window(id = "secondWindow", content = ...)
}
type FabWindow() =
inherit Window()
member this.WindowId
type FabAvaloniaApp() =
inherit Application()
member this.InternalWindows = new List<Window>() <--- this one
override this.MainWindow = this.InternalWindows[0]
member this.OpenWindow(id: string) =
let window = this.InternalWindows |> List.find (fun w -> w.WindowId = id)
window.Show()
Button("Open second window", Clicked)
match msg with
| Clicked -> Application.Current.OpenWindow("secondWindow")
See https://docs.avaloniaui.net/docs/controls/datagrid for more info
In order to track Avalonia support, we need to make sure we have widgets and modifiers for the following controls
When items are added via the constructor (WidgetDataTemplate), it is not quite rendering correctly:
Originally posted by @ConradRoesch in #74 (comment)
Target WebAssembly in the Fabulous SingleProject
https://docs.avaloniaui.net/docs/next/reference/controls/detailed-reference/treeview-1
TreeView(model.Conferences, fun conference ->
TreeNode(TextBlock(conference.Name), conference.Teams, fun team ->
TreeNode(TextBlock(team.Name), team.Rosters, fun roster ->
match roster with
| :? Player as player -> TextBlock(player.Name)
| :? Coach as coach -> TextBlock(coach.Name)
)
)
)
TreeNode -> TreeDataTemplate
Other widget -> DataTemplate
Carousel SelectedChangedIndex and index is not working.
Originally posted by @edgarfgp in #82 (comment)
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.