fsprojects-archive / zzarchive-fsharp.desktop.ui Goto Github PK
View Code? Open in Web Editor NEWF# MVC framework for WPF.
Home Page: http://fsprojects.github.io/FSharp.Desktop.UI/
License: Other
F# MVC framework for WPF.
Home Page: http://fsprojects.github.io/FSharp.Desktop.UI/
License: Other
I have started a small application taking the general structure from the Calculator example (which I ported to FsXaml first). However, I am already stuck very early on.
This is the complete F# code:
open System
open System.Windows
open System.Windows.Data
open FSharp.Desktop.UI
type App = FsXaml.XAML<"App.xaml">
type OAuth = FsXaml.XAML<"OAuth.xaml", true>
[<AbstractClass>]
type OAuthModel() =
inherit Model()
abstract Pin : string with get, set
type OAuthEvents =
| SubmitPin
type OAuthView(root : OAuth) as this =
inherit View<OAuthEvents, OAuthModel, Window>(root.Root)
override this.EventStreams =
[
let buttonClicks =
[
root.SubmitPinButton, SubmitPin
]
|> List.map (fun (button, event) -> button.Click |> Observable.mapTo event)
yield! buttonClicks
]
override this.SetBindings model =
let root = OAuth this.Root
Binding.OfExpression
<@
root.PinTextBox.Text <- coerce model.Pin
@>
type OAuthController() =
interface IController<OAuthEvents, OAuthModel> with
member this.InitModel model =
model.Pin <- ""
member this.Dispatcher = function
| SubmitPin -> Sync this.SubmitPin
member this.SubmitPin(model : OAuthModel) =
MessageBox.Show "Da" |> ignore
[<EntryPoint; STAThread>]
let main args =
let model, view, controller = OAuthModel.Create(), OAuthView(OAuth()), OAuthController()
let mvc = Mvc(model, view, controller)
use eventLoop = mvc.Start()
let app = App().Root
app.DispatcherUnhandledException.Add <| fun args ->
if MessageBox.Show(args.Exception.ToString(), "Error! Ignore?", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.Yes) = MessageBoxResult.Yes
then args.Handled <- true
app.Run(window = view.Root)
I am at this time just trying to get anything to work; however, when I run this, a TypeInitializationException
occurs in the Binding.OfExpression
call, telling me that the type initializer for Patterns
has thrown an error, and I don't know what to make of it.
PinTextBox
in OAuth.xaml
is a simple text box, SubmitPin
is a button.
Any ideas what I'm doing wrong?
When using the NuGet package, I get this exception when calling Model.Create()
:
Message: An unhandled exception of type 'System.TypeInitializationException' occurred in Prog.exe
Additional information: The type initializer for 'FSharp.Desktop.UI.Model' threw an exception.
If I upgrade Castle.Core to the latest version, Model.Create()
works. So, it seems that the Castle.Core version referenced in the NuGet package doesn't work with the latest version of .NET or F# runtime.
Even though this is a WPF framework, we're fitting it for WinForms. I know there's a [<DerivedProperty>]
that Binding.OfExpression
uses to do multi-way binding in the case of computed properties. In WinForms the Binding.OfExpression
does not work because, I assume, WinForms is not compatible with the WPF binding framework.
I made a [<DerivedFrom(string array)>]
attribute that lets you mark the direct dependencies of the computed properties on your model and hijacked the body of the Intercept
method on the IIntercepter
on the Model
, so that when a setter is called, I check to see if there are any children pointing to me as a dependency.
I am still working on a couple nice-to-haves like transitive dependency resolution and memoizing reflection results, but it mostly works. Is this something that could be made into a pull request? I know it is a little strange thematically as this is a WPF framework.
I know this is an old library by now, but it still appeared high up on the search results, so here I am.
I'm learning F# (so all of the below may be based on misunderstandings) and I want to use F# for a Xamarin app. Your MVC way of thinking as described in your series seems to have a lot of merit. However, I'm a bit fuzzy on why you have a single event stream per MVC-combo where all the different events are separate cases of a single discriminated union. As far as I can see, this precludes easy Rx manipulation of the different events.
For example, say you have two events for a view: MouseMoved and ButtonClicked. According to your architecture, these would then be two cases of a discriminated union. But if you want to e.g. throttle MouseMoved, or filter it based on coordinates, I can't see an elegant way of doing this. If the two events were instead two different IObservables, this would be trivial.
My two questions:
Do you have any comment on this?
Would you say your MVC solution is still relevant, or are there better ways of solving things nowadays?
@fsgit Looks like I locked out myself from my own repo. :)
Can I get admin access back?
Last commit in 2016. Please, archive the project
This project depends on Rx-Main and the package is now unlisted. Should be changed to System.Reactive.*
Hi,
quick question, how would you handle collections ? Let's say, a list of ToDoItems. I can't find a nice solution.
Thanks !
I read your fsharp-wpf-mvc-series and you actually have got Mvc.Compose methods in this library as well, and all works fine for composition, but what about interoperability?
Maybe I am wrong but in your samples I could not find any example of such interoperability. In C# projects we use Event Aggregators, how could I achieve similar feature in FSharp.Desktop.UI?
Controllers encapsulate operations pipelined by events associated with views. In interoperability among different modules/views basically controllers already implement operations which are required in interoperability operation.
What are your thoughts? Some kind of EventAggregator or similar like in your controller approach some kind of event translator and controller/model selector?
Sorry this is more a question than an issue.
I am trying to use this library for a project where I react also need to react to midi events which are coming from my controller. For this purpose, I have created an agent with MailboxProcessor from which I would like the model to update depending on different messages.
I saw in your wolfram example how to do async calls. My question is where would be the best place to introduce messages coming from the agent? I assume they should come in the controller but not sure how to plug this. Would using the Dispatcher member with an Async event handler which contains a recursive loop waiting on messages be okay?
Thank you.
DataContext should be set before SetBindings otherwise in initial binding there is a lot of errors:
System.Windows.Data Error: 40 : BindingExpression path error: 'ToDate' property not found on 'object' ''MainModelProxy' (HashCode=10737664)'. BindingExpression:Path=ToDate; DataItem='MainModelProxy' (HashCode=10737664); target element is 'DateEdit' (Name='deToDate'); target property is 'EditValue' (type 'Object')
member this.SetBindings model =
root.DataContext <- model
this.SetBindings model
I noticed quite strange behavior for derived properties. In my model I have got:
[<DerivedProperty>]
member this.MarketName
with get() = if this.OpenBetEvent.IsSome then this.Market.MarketInfo.ToString() else "No market selected"
[<DerivedProperty>]
member this.CanCloseMarket
with get() = this.IsAuthorized && this.OpenBetEvent.IsSome
In the first initial data binding for my view CanCloseMarket is evaluated, but not MarketName.
Market is abstract property. When OpenBetEvent changes correct values are set in bind controls on my view, but not on the first initial state.
My workaround is to not use DerivedProperty
for MarketName and to call this.NotifyPropertyChanged "MarketName" whenever OpenBetEvent changes.
In my project I have got quite a lot of such models with this problem. In all such models one of properties is option value, so that could be maybe clue for you to solve this issue. I really do not know because as you can see in CanCloseMarket, the OpenBetEvent is option value and here the DerivedProperty works fine.
No errors or warnings are reported when bindings are set for those properties.
When I run the calculator sample and give the value "-1" to "Y", and then click on the "+" button, the box containing -1 is highlighted with a red border, which makes sense (since we don't allow addition with values of "Y" less than 0).
I don't understand why the "/" button is also highlighted.
When I comment out the "divide.IsEnabled <- model.Y <> 0." binding, the red border does not appear on the "/" button using the above sequence of events.
My guess is that an error in the "Y" box causes some confusion with the divide by zero constraint.
Is there a problem here, or have I missed something?
I'm enjoying the great work being done in F# Deep Dives.
Regards,
g.
I am currently trying to create some projects using your MVC framework and it seems some of the code you are using in fsharp-wpf-mvc-series are now missing or have changed.
What is the current recommended way to use an existing converter (for example a BoolToVisibility converter)? It seems the only correct way (based on my understanding of your code) is to provide a function that acts as converter and not to use a converter class (IValueConverter).
I am also wondering how you would handle displaying a message (for example message box but I assume the behavior would be the same) at the end of an operation? For now, I am passing a method (string -> string -> unit) as an argument of my controller and I call this method when needed. Doing so I am able to keep my unit tests quite simple as I can fake my methods. But I am wondering if the problem should not be inverted, meaning that the XamlView implementation should not subscribe to a result of the controller's method to trigger the message box.
Access to the documentation(http://fsprojects.github.io/FSharp.Desktop.UI/) returns a 404 error.
I'd like to test the GUI I have built by writing scripts that generate the EventStreams that your mvc controllers dispatch on.
If I have a mousewheel event defined as:
w.MouseWheel |> Observable.map (fun args -> if args.Delta > 0 then Next else Previous)
I'd like to be generating the "Next" or "Previous" events in my integration tests rather than using the real MouseWheel (but still exercising the rest of the real GUI).
I haven't a good idea how to plumb that in; I've tried a few things that didn't really work.
Please would you give a few pointers on how to get started?
Thanks,
George.
I think you should consider to add model reset or clear method for abstract properties. In your implementation, abstract properties are held in dictionary:
and internal AbstractProperties() =
let data = Dictionary()
So if model needs to refresh those properties, mainly those which content is set by wpf data binding, those properties remain with old data, if wpf control did not reset them directly.
Of course for most of properties when model context changes,there is possible to set those properties directly by model setter, but really not for all of them in my case.
Some UI libraries use FrameworkContentElement so to bind such UI elements I added TargetContent partial active patterns and extended Expr ToBinding method. Is there a way to make it a more general?
To improve debug-ability/diagnostics
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.