Skip to content
This repository has been archived by the owner on Oct 31, 2021. It is now read-only.

Commit

Permalink
in respond to the issue 16
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry-a-morozov committed Jul 1, 2015
1 parent 9ded63d commit 4188966
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 51 deletions.
9 changes: 9 additions & 0 deletions samples/Calculator/Calculator.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFSharpCoreVersion>4.3.1.0</TargetFSharpCoreVersion>
<Name>Calculator</Name>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand Down Expand Up @@ -85,6 +87,13 @@
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
</ItemGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
Expand Down
49 changes: 24 additions & 25 deletions samples/Calculator/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -138,50 +138,49 @@ type CalculatorView() as this =
@>,
updateSourceTrigger = UpdateSourceTrigger.PropertyChanged)

type CalculatorController(?wolframAlphaService: string -> string -> Async<WolframAlpha.Response>) =
type CalculatorController(?wolframAlphaService: string -> string -> Async<WolframAlpha.Response>) =
inherit Controller<CalculatorEvents, CalculatorModel>()

let wolframAlphaService = defaultArg wolframAlphaService WolframAlpha.instance

interface IController<CalculatorEvents, CalculatorModel> with

member this.InitModel model =
model.WolframalphaResponse <- Empty
let appKey = ConfigurationManager.AppSettings.["WolframalphaAppId"]
if appKey <> null
then model.WolframalphaAppId <- appKey

member this.Dispatcher = function
| Add -> Sync this.Add
| Subtract -> Sync this.Subtract
| Multiply -> Sync this.Multiply
| Divide -> Sync this.Divide
| Clear -> Sync this.Clear
| ArgChanging(text, cancel) -> Sync(this.DiscardInvalidInput text cancel)
| AskWolframalpha -> Async this.AskWolframalpha
| CancelAskWolframalphaRequest -> Sync <| fun _ -> Async.CancelDefaultToken()

member this.Add(model: CalculatorModel) =
override this.InitModel model =
model.WolframalphaResponse <- Empty
let appKey = ConfigurationManager.AppSettings.["WolframalphaAppId"]
if appKey <> null
then model.WolframalphaAppId <- appKey

override this.Dispatcher = function
| Add -> Sync this.Add
| Subtract -> Sync this.Subtract
| Multiply -> Sync this.Multiply
| Divide -> Sync this.Divide
| Clear -> Sync this.Clear
| ArgChanging(text, cancel) -> Sync(this.DiscardInvalidInput text cancel)
| AskWolframalpha -> Async this.AskWolframalpha
| CancelAskWolframalphaRequest -> Sync <| fun _ -> Async.CancelDefaultToken()

member this.Add model =
if model.Y < 0.
then model |> Validation.setError <@ fun m -> m.Y @> "Must be positive number."
else model.Result <- model.X + model.Y

member this.Subtract(model: CalculatorModel) =
member this.Subtract model =
if model.Y < 0.
then model |> Validation.setError <@ fun m -> m.Y @> "Must be positive number."
else model.Result <- model.X - model.Y

member this.Multiply(model: CalculatorModel) =
member this.Multiply model =
model.Result <- model.X * model.Y

member this.Divide(model: CalculatorModel) =
member this.Divide model =
model.Result <- model.X / model.Y

member this.Clear(model: CalculatorModel) =
member this.Clear model =
model.X <- 0.
model.Y <- 0.
model.Result <- 0.

member this.DiscardInvalidInput (newValue: string) cancel (model: CalculatorModel) =
member this.DiscardInvalidInput (newValue: string) cancel model =
let textToCheck = if newValue.EndsWith(".") then newValue + "0" else newValue
match Double.TryParse textToCheck with
| false, _ -> cancel()
Expand Down
21 changes: 0 additions & 21 deletions src/Controller.fs
Original file line number Diff line number Diff line change
@@ -1,23 +1,2 @@
namespace FSharp.Desktop.UI

[<AbstractClass>]
type Controller<'Event, 'Model>() =

interface IController<'Event, 'Model> with
member this.InitModel model = this.InitModel model
member this.Dispatcher = this.Dispatcher

abstract InitModel : 'Model -> unit
abstract Dispatcher : ('Event -> EventHandler<'Model>)

static member Create callback = {
new IController<'Event, 'Model> with
member this.InitModel _ = ()
member this.Dispatcher = callback
}

static member Create callback = {
new IController<'Event, 'Model> with
member this.InitModel _ = ()
member this.Dispatcher = fun event -> Sync(callback event)
}
49 changes: 44 additions & 5 deletions src/Mvc.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@ open System.Reactive
open System.Reactive.Concurrency
open System.Reactive.Linq

open System.Windows

type IDialogService =
abstract MessageBox: text: string * ?caption: string * ?button: MessageBoxButton * ?icon: MessageBoxImage * ?defaultResult: MessageBoxResult * ?options: MessageBoxOptions * ?owner: Window -> MessageBoxResult
//more specialized members can be defined like: Error, Warning, Confrim

type IPartialView<'Event, 'Model> =
abstract Events : IObservable<'Event> with get
abstract SetBindings : 'Model -> unit
abstract Events: IObservable<'Event> with get
abstract SetBindings: 'Model -> unit
abstract DialogService: IDialogService with get

type IView<'Event, 'Model> =
inherit IPartialView<'Event, 'Model>
abstract ShowDialog : unit -> bool
abstract Show : unit -> Async<unit>
abstract ShowDialog: unit -> bool
abstract Show: unit -> Async<unit>

type EventHandler<'Model> =
| Sync of ('Model -> unit)
Expand All @@ -24,6 +31,36 @@ type EventHandler<'Model> =
type IController<'Event, 'Model> =
abstract InitModel : 'Model -> unit
abstract Dispatcher : ('Event -> EventHandler<'Model>)
abstract DialogService: IDialogService with set

[<AbstractClass>]
type Controller<'Event, 'Model>() =

let mutable dialogService = {
new IDialogService with
member __.MessageBox( text, _, _, _, _, _, _) = undefined //or maybe better to use Debug.WriteLine or empty body as deafult
}

interface IController<'Event, 'Model> with
member this.InitModel model = this.InitModel model
member this.Dispatcher = this.Dispatcher
member __.DialogService with set value = dialogService <- value

abstract InitModel : 'Model -> unit
abstract Dispatcher : ('Event -> EventHandler<'Model>)
member __.DialogService = dialogService

static member Create callback = {
new Controller<'Event, 'Model>() with
member this.InitModel _ = ()
member this.Dispatcher = callback
}

static member Create callback = {
new Controller<'Event, 'Model>() with
member this.InitModel _ = ()
member this.Dispatcher = fun event -> Sync(callback event)
}

[<Sealed>]
type Mvc<'Event, 'Model when 'Model :> INotifyPropertyChanged>(model : 'Model, view : IView<'Event, 'Model>, controller : IController<'Event, 'Model>) =
Expand Down Expand Up @@ -72,12 +109,13 @@ type Mvc<'Event, 'Model when 'Model :> INotifyPropertyChanged>(model : 'Model, v
member __.SetBindings model =
view.SetBindings model
model |> childModelSelector |> childView.SetBindings
member __.DialogService = view.DialogService
member __.Show() = view.Show()
member __.ShowDialog() = view.ShowDialog()
}

let compositeController = {
new IController<_, _> with
new Controller<_, _>() with
member __.InitModel model =
controller.InitModel model
model |> childModelSelector |> childController.InitModel
Expand All @@ -99,6 +137,7 @@ type Mvc<'Event, 'Model when 'Model :> INotifyPropertyChanged>(model : 'Model, v
new IPartialView<_, _> with
member __.Events = events
member __.SetBindings _ = ()
member __.DialogService = view.DialogService
}
this.Compose(childController, childView, id)

Expand Down
20 changes: 20 additions & 0 deletions src/View.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@ type PartialView<'Event, 'Model, 'Element when 'Element :> FrameworkElement>(roo
member this.SetBindings model =
root.DataContext <- model
this.SetBindings model
member __.DialogService = {
new IDialogService with
member __.MessageBox( text, caption, button, icon, defaultResult, options, owner) =
match caption, button, icon, defaultResult, options, owner with
| None, None, None, None, None, None -> MessageBox.Show text
| Some caption, None, None, None, None, None -> MessageBox.Show(text, caption)
| Some caption, Some button, None, None, None, None -> MessageBox.Show(text, caption, button)
| Some caption, Some button, Some icon, None, None, None -> MessageBox.Show(text, caption, button, icon)
| Some caption, Some button, Some icon, Some defaultResult, None, None -> MessageBox.Show(text, caption, button, icon, defaultResult)
| Some caption, Some button, Some icon, Some defaultResult, Some options, None -> MessageBox.Show(text, caption, button, icon, defaultResult, options)
//Owner
| None, None, None, None, None, Some owner -> MessageBox.Show(owner, text)
| Some caption, None, None, None, None, Some owner -> MessageBox.Show(owner, text, caption)
| Some caption, Some button, None, None, None, Some owner -> MessageBox.Show(owner, text, caption, button)
| Some caption, Some button, Some icon, None, None, Some owner -> MessageBox.Show(owner, text, caption, button, icon)
| Some caption, Some button, Some icon, Some defaultResult, None, Some owner -> MessageBox.Show(owner, text, caption, button, icon, defaultResult)
| Some caption, Some button, Some icon, Some defaultResult, Some options, Some owner -> MessageBox.Show(owner, text, caption, button, icon, defaultResult, options)

| _ as xs -> invalidOp "Unexpected parameters: %A" xs
}

abstract EventStreams : IObservable<'Event> list
abstract SetBindings : 'Model -> unit
Expand Down

0 comments on commit 4188966

Please sign in to comment.