From 76bc0cbc7ab16e588fb2eb7d4a0a40442805f4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laban?= Date: Sun, 10 Nov 2019 22:45:48 -0500 Subject: [PATCH] wip working --- .../Fabulous.CodeGen/AssemblyReader/Reader.fs | 2 +- .../AssemblyReader/Resolver.fs | 14 +- Fabulous.Uno/samples/CounterApp/CounterApp.fs | 34 +- .../samples/CounterApp/CounterApp.fsproj | 22 +- .../CounterApp/Properties/launchSettings.json | 27 + .../CounterApp/WasmScripts/AppManifest.js | 7 + Fabulous.Uno/samples/CounterApp/main.fs | 8 + Fabulous.Uno/src/Fabulous.Uno.Core/Program.fs | 27 +- .../src/Fabulous.Uno.Core/ViewConverters.fs | 14 +- .../src/Fabulous.Uno.Core/ViewUpdaters.fs | 82 +- .../src/Fabulous.Uno/Fabulous.Uno.fsproj | 5 + Fabulous.Uno/src/Fabulous.Uno/Uno.UI.fs | 755 +++++++++++++++++- Fabulous.Uno/src/Fabulous.Uno/Uno.UI.json | 118 ++- .../Fabulous.Uno.Generator/Reflection.fs | 20 +- .../Fabulous.Uno.Generator/UnoConverters.fs | 3 + Packages.targets | 2 + 16 files changed, 1030 insertions(+), 110 deletions(-) create mode 100644 Fabulous.Uno/samples/CounterApp/Properties/launchSettings.json create mode 100644 Fabulous.Uno/samples/CounterApp/WasmScripts/AppManifest.js create mode 100644 Fabulous.Uno/samples/CounterApp/main.fs diff --git a/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Reader.fs b/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Reader.fs index e070b71..4208ada 100644 --- a/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Reader.fs +++ b/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Reader.fs @@ -21,7 +21,7 @@ module Reader = let eventHandlerType = match edef.EventType with | :? GenericInstanceType as git -> git.FullName |> Text.removeDotNetGenericNotation - | _ -> "System.EventHandler" + | _ -> edef.EventType.FullName { Name = edef.Name EventArgsType = eventArgsType |> Option.map convertTypeName |> Option.defaultValue "unit" diff --git a/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Resolver.fs b/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Resolver.fs index f1d1e95..a67c4f7 100644 --- a/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Resolver.fs +++ b/Fabulous.CodeGen/src/Fabulous.CodeGen/AssemblyReader/Resolver.fs @@ -58,15 +58,27 @@ module Resolver = |> Seq.filter (fun fdef -> fdef.IsStatic && fdef.FieldType.FullName = propertyBaseType && fdef.Name.EndsWith("Property")) |> Seq.filter (fun fdef -> ``type``.Properties |> Seq.exists (fun pdef -> pdef.Name = fdef.Name.Replace("Property", "")) |> not) |> Seq.toArray + + let rec implementsInterface (``type``: TypeDefinition) (interfaceTypeName: string) = + let ifaces = + ``type``.Interfaces.ToArray() + |> Array.filter (fun i -> i.InterfaceType.GetElementType().FullName.Equals(interfaceTypeName)) + + match ifaces with + | [||] -> match ``type``.BaseType with + | null -> false + | _ -> implementsInterface (``type``.BaseType.Resolve()) interfaceTypeName + | _ -> true /// Finds all not settable list properties for a given type let getAllListPropertiesWithNoSetterForType (``type``: TypeDefinition) = + let fullName = ``type``.FullName if not ``type``.HasProperties then [||] else ``type``.Properties |> Seq.filter (fun pdef -> pdef.GetMethod <> null && pdef.GetMethod.IsPublic && pdef.SetMethod = null) - |> Seq.filter (fun pdef -> pdef.PropertyType.GetElementType().FullName = "System.Collections.Generic.IList`1") + |> Seq.filter (fun pdef -> implementsInterface (pdef.PropertyType.Resolve()) "System.Collections.Generic.IList`1") |> Seq.toArray /// Finds all settable properties for a given type diff --git a/Fabulous.Uno/samples/CounterApp/CounterApp.fs b/Fabulous.Uno/samples/CounterApp/CounterApp.fs index 9fd7d33..3930d05 100644 --- a/Fabulous.Uno/samples/CounterApp/CounterApp.fs +++ b/Fabulous.Uno/samples/CounterApp/CounterApp.fs @@ -4,6 +4,8 @@ namespace CounterApp open Fabulous open Fabulous.Uno open System.Diagnostics +open Windows.UI.Xaml +open Windows.UI.Xaml.Controls module App = type Model = @@ -45,38 +47,36 @@ module App = | TimedTick -> if model.TimerOn then { model with Count = model.Count + model.Step }, [ TickTimer ] else model, [] let view (model: Model) dispatch = - View.ContentPage( - content=View.StackLayout(padding = Thickness 30.0, verticalOptions = LayoutOptions.Center, + View.StackPanel(padding = Thickness 30.0, verticalAlignment = VerticalAlignment.Center, children=[ - View.Label(automationId="CountLabel", text=sprintf "%d" model.Count, horizontalOptions=LayoutOptions.Center, width=200.0, horizontalTextAlignment=TextAlignment.Center) - View.Button(automationId="IncrementButton", text="Increment", command= (fun () -> dispatch Increment)) - View.Button(automationId="DecrementButton", text="Decrement", command= (fun () -> dispatch Decrement)) - View.StackLayout(padding = Thickness 20.0, orientation=StackOrientation.Horizontal, horizontalOptions=LayoutOptions.Center, - children = [ View.Label(text="Timer") - View.Switch(automationId="TimerSwitch", isToggled=model.TimerOn, toggled=(fun on -> dispatch (TimerToggled on.Value))) ]) - View.Slider(automationId="StepSlider", minimumMaximum=(0.0, 10.0), value= double model.Step, valueChanged=(fun args -> dispatch (SetStep (int (args.NewValue + 0.5))))) - View.Label(automationId="StepSizeLabel", text=sprintf "Step size: %d" model.Step, horizontalOptions=LayoutOptions.Center) - View.Button(text="Reset", horizontalOptions=LayoutOptions.Center, command=(fun () -> dispatch Reset), commandCanExecute = (model <> initModel () )) - ])) + View.TextBlock(text=sprintf "%d" model.Count, horizontalAlignment=HorizontalAlignment.Center, width=200.0, horizontalTextAlignment=TextAlignment.Center) + View.Button(content="Increment", command= (fun () -> dispatch Increment)) + View.Button(content="Decrement", command= (fun () -> dispatch Decrement)) + View.TextBlock(text=sprintf "Step size: %d" model.Step, horizontalAlignment=HorizontalAlignment.Center) + View.Button(content="Reset", horizontalAlignment=HorizontalAlignment.Center, command=(fun () -> dispatch Reset), commandCanExecute = (model <> initModel () )) + ]) let program = Program.mkProgramWithCmdMsg init update view mapCmdMsgToCmd - - type CounterApp () as app = inherit Application () - let runner = + override u.OnLaunched activatedArgs = + Windows.UI.Xaml.GenericStyles.Initialize() + Windows.ApplicationModel.Resources.ResourceLoader.DefaultLanguage <- "en-US" + Windows.ApplicationModel.Resources.ResourceLoader.AddLookupAssembly(System.Reflection.Assembly.Load("Uno.UI, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null")) + App.program |> Program.withConsoleTrace - |> XamarinFormsProgram.run app + |> UnoProgram.run app + #if DEBUG // Run LiveUpdate using: // - do runner.EnableLiveUpdate () + // do runner.EnableLiveUpdate () #endif diff --git a/Fabulous.Uno/samples/CounterApp/CounterApp.fsproj b/Fabulous.Uno/samples/CounterApp/CounterApp.fsproj index 3770f01..2c9a768 100644 --- a/Fabulous.Uno/samples/CounterApp/CounterApp.fsproj +++ b/Fabulous.Uno/samples/CounterApp/CounterApp.fsproj @@ -1,13 +1,33 @@ - + netstandard2.0 + Exe false + false + + + true + $(DefineConstants);TRACE;DEBUG + portable + true + + + + + + + + + + + + diff --git a/Fabulous.Uno/samples/CounterApp/Properties/launchSettings.json b/Fabulous.Uno/samples/CounterApp/Properties/launchSettings.json new file mode 100644 index 0000000..85bd4a4 --- /dev/null +++ b/Fabulous.Uno/samples/CounterApp/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:60376/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "CounterApp": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:60377/" + } + } +} \ No newline at end of file diff --git a/Fabulous.Uno/samples/CounterApp/WasmScripts/AppManifest.js b/Fabulous.Uno/samples/CounterApp/WasmScripts/AppManifest.js new file mode 100644 index 0000000..53b389e --- /dev/null +++ b/Fabulous.Uno/samples/CounterApp/WasmScripts/AppManifest.js @@ -0,0 +1,7 @@ +var UnoAppManifest = { + + splashScreenImage: "Assets/SplashScreen.scale-200.png", + splashScreenColor: "#00f", + displayName: "App13" + +} diff --git a/Fabulous.Uno/samples/CounterApp/main.fs b/Fabulous.Uno/samples/CounterApp/main.fs new file mode 100644 index 0000000..34a304e --- /dev/null +++ b/Fabulous.Uno/samples/CounterApp/main.fs @@ -0,0 +1,8 @@ +open System +open Windows.UI.Xaml + +[] +let main argv = + + Application.Start(fun _ -> new CounterApp.CounterApp() |> ignore) + 0 \ No newline at end of file diff --git a/Fabulous.Uno/src/Fabulous.Uno.Core/Program.fs b/Fabulous.Uno/src/Fabulous.Uno.Core/Program.fs index 45e1eab..e66d3b9 100644 --- a/Fabulous.Uno/src/Fabulous.Uno.Core/Program.fs +++ b/Fabulous.Uno/src/Fabulous.Uno.Core/Program.fs @@ -5,19 +5,22 @@ namespace Fabulous.Uno open Fabulous open Windows.UI.Xaml open Windows.UI.Core +open Microsoft.Extensions.Logging +open Windows.UI.Xaml.Controls type UnoHost(app: Application) = interface IHost with member __.GetRootView() = match Window.Current.Content with | null -> failwith "No root view" - | rootView -> rootView :> obj + | rootView -> (rootView :?> Frame).Content member __.SetRootView(rootView) = match rootView with - | :? FrameworkElement as element -> Window.Current.Content <- element + | :? FrameworkElement as element -> (Window.Current.Content :?> Frame).Content <- element | _ -> failwithf "Incorrect model type: expected a FrameworkElement but got a %O" (rootView.GetType()) + /// Program module - functions to manipulate program instances [] [] @@ -32,14 +35,34 @@ module UnoProgram = Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, fun () -> fn()) |> ignore () + let configureFilters (factory: ILoggerFactory) = + let settings = new FilterLoggerSettings() + settings.Add("Uno", LogLevel.Warning); + settings.Add("Windows", LogLevel.Warning); + + factory + .WithFilter(settings) + .AddConsole(LogLevel.Debug) + let runWith app arg program = let host = UnoHost(app) + typeof.ToString() |> ignore + + configureFilters Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory |> ignore + + let rootWindow = new Frame() + rootWindow.Background <- SolidColorBrushHelper.Black + + Window.Current.Content <- rootWindow + Window.Current.Activate() + program |> Program.withCanReuseView ViewHelpers.canReuseView |> Program.withSyncDispatch syncDispatch |> Program.withSyncAction syncAction |> Program.runWithFabulous host arg + |> ignore let run app program = runWith app () program \ No newline at end of file diff --git a/Fabulous.Uno/src/Fabulous.Uno.Core/ViewConverters.fs b/Fabulous.Uno/src/Fabulous.Uno.Core/ViewConverters.fs index 19aa7fe..f82d95b 100644 --- a/Fabulous.Uno/src/Fabulous.Uno.Core/ViewConverters.fs +++ b/Fabulous.Uno/src/Fabulous.Uno.Core/ViewConverters.fs @@ -8,6 +8,7 @@ open System.Collections.ObjectModel open Windows.UI.Xaml.Controls open Windows.UI.Xaml.Media open Windows.UI.Xaml +open Windows.UI.Xaml.Controls.Primitives module CollectionHelpers = /// Try and find a specific ListView item @@ -94,7 +95,18 @@ module ViewConverters = ///////////////// /// Event Handlers ///////////////// - + + let makeToggledEventHandler f = + System.EventHandler(fun sender args -> + let toggleSwitch = sender :?> ToggleSwitch + f (toggleSwitch.IsOn) + ) + + let makeValueChangedEventHandler f = + System.EventHandler(fun sender args -> + let rangeBase = sender :?> RangeBase + f (rangeBase.Value) + ) //let makeCurrentPageChanged<'a when 'a :> Xamarin.Forms.Page and 'a : null> f = // System.EventHandler(fun sender _args -> // let control = sender :?> Xamarin.Forms.MultiPage<'a> diff --git a/Fabulous.Uno/src/Fabulous.Uno.Core/ViewUpdaters.fs b/Fabulous.Uno/src/Fabulous.Uno.Core/ViewUpdaters.fs index 9a51fbe..de23685 100644 --- a/Fabulous.Uno/src/Fabulous.Uno.Core/ViewUpdaters.fs +++ b/Fabulous.Uno/src/Fabulous.Uno.Core/ViewUpdaters.fs @@ -338,33 +338,33 @@ module ViewUpdaters = // match prevValueOpt with ValueNone -> () | ValueSome f -> target.SizeAllocated.RemoveHandler(f) // match valueOpt with ValueNone -> () | ValueSome f -> target.SizeAllocated.AddHandler(f) - ///// Converts an F# function to a Xamarin.Forms ICommand - //let makeCommand f = - // let ev = Event<_,_>() - // { new ICommand with - // member __.add_CanExecuteChanged h = ev.Publish.AddHandler h - // member __.remove_CanExecuteChanged h = ev.Publish.RemoveHandler h - // member __.CanExecute _ = true - // member __.Execute _ = f() } + /// Converts an F# function to a Xamarin.Forms ICommand + let makeCommand f = + let ev = Event<_,_>() + { new ICommand with + member __.add_CanExecuteChanged h = ev.Publish.AddHandler h + member __.remove_CanExecuteChanged h = ev.Publish.RemoveHandler h + member __.CanExecute _ = true + member __.Execute _ = f() } - ///// Converts an F# function to a Xamarin.Forms ICommand, with a CanExecute value - //let makeCommandCanExecute f canExecute = - // let ev = Event<_,_>() - // { new ICommand with - // member __.add_CanExecuteChanged h = ev.Publish.AddHandler h - // member __.remove_CanExecuteChanged h = ev.Publish.RemoveHandler h - // member __.CanExecute _ = canExecute - // member __.Execute _ = f() } + /// Converts an F# function to a Xamarin.Forms ICommand, with a CanExecute value + let makeCommandCanExecute f canExecute = + let ev = Event<_,_>() + { new ICommand with + member __.add_CanExecuteChanged h = ev.Publish.AddHandler h + member __.remove_CanExecuteChanged h = ev.Publish.RemoveHandler h + member __.CanExecute _ = canExecute + member __.Execute _ = f() } ///// Update the Command and CanExecute properties of a control, given previous and current values - //let inline updateCommand prevCommandValueOpt commandValueOpt argTransform setter prevCanExecuteValueOpt canExecuteValueOpt target = - // match prevCommandValueOpt, prevCanExecuteValueOpt, commandValueOpt, canExecuteValueOpt with - // | ValueNone, ValueNone, ValueNone, ValueNone -> () - // | ValueSome prevf, ValueNone, ValueSome f, ValueNone when identical prevf f -> () - // | ValueSome prevf, ValueSome prevx, ValueSome f, ValueSome x when identical prevf f && prevx = x -> () - // | _, _, ValueNone, _ -> setter target null - // | _, _, ValueSome f, ValueNone -> setter target (makeCommand (fun () -> f (argTransform target))) - // | _, _, ValueSome f, ValueSome k -> setter target (makeCommandCanExecute (fun () -> f (argTransform target)) k) + let inline updateCommand prevCommandValueOpt commandValueOpt argTransform setter prevCanExecuteValueOpt canExecuteValueOpt target = + match prevCommandValueOpt, prevCanExecuteValueOpt, commandValueOpt, canExecuteValueOpt with + | ValueNone, ValueNone, ValueNone, ValueNone -> () + | ValueSome prevf, ValueNone, ValueSome f, ValueNone when identical prevf f -> () + | ValueSome prevf, ValueSome prevx, ValueSome f, ValueSome x when identical prevf f && prevx = x -> () + | _, _, ValueNone, _ -> setter target null + | _, _, ValueSome f, ValueNone -> setter target (makeCommand (fun () -> f (argTransform target))) + | _, _, ValueSome f, ValueSome k -> setter target (makeCommandCanExecute (fun () -> f (argTransform target)) k) ///// Update the CurrentPage of a control, given previous and current values //let updateMultiPageOfTCurrentPage<'a when 'a :> Xamarin.Forms.Page> prevValueOpt valueOpt (target: Xamarin.Forms.MultiPage<'a>) = @@ -374,24 +374,24 @@ module ViewUpdaters = // | ValueSome _, ValueNone -> target.CurrentPage <- Unchecked.defaultof<'a> // | _, ValueSome curr -> target.CurrentPage <- target.Children.[curr] - ///// Update the Minium and Maximum values of a slider, given previous and current values - //let updateSliderMinimumMaximum prevValueOpt valueOpt (target: obj) = - // let control = target :?> Xamarin.Forms.Slider - // let defaultValue = (0.0, 1.0) - // let updateFunc (_, prevMaximum) (newMinimum, newMaximum) = - // if newMinimum > prevMaximum then - // control.Maximum <- newMaximum - // control.Minimum <- newMinimum - // else - // control.Minimum <- newMinimum - // control.Maximum <- newMaximum + /// Update the Minium and Maximum values of a slider, given previous and current values + let updateRangeBaseMinimumMaximum prevValueOpt valueOpt (target: obj) = + let control = target :?> Slider + let defaultValue = (0.0, 1.0) + let updateFunc (_, prevMaximum) (newMinimum, newMaximum) = + if newMinimum > prevMaximum then + control.Maximum <- newMaximum + control.Minimum <- newMinimum + else + control.Minimum <- newMinimum + control.Maximum <- newMaximum - // match prevValueOpt, valueOpt with - // | ValueNone, ValueNone -> () - // | ValueSome prev, ValueSome curr when prev = curr -> () - // | ValueSome prev, ValueSome curr -> updateFunc prev curr - // | ValueSome prev, ValueNone -> updateFunc prev defaultValue - // | ValueNone, ValueSome curr -> updateFunc defaultValue curr + match prevValueOpt, valueOpt with + | ValueNone, ValueNone -> () + | ValueSome prev, ValueSome curr when prev = curr -> () + | ValueSome prev, ValueSome curr -> updateFunc prev curr + | ValueSome prev, ValueNone -> updateFunc prev defaultValue + | ValueNone, ValueSome curr -> updateFunc defaultValue curr ///// Update the Minimum and Maximum values of a stepper, given previous and current values //let updateStepperMinimumMaximum prevValueOpt valueOpt (target: obj) = diff --git a/Fabulous.Uno/src/Fabulous.Uno/Fabulous.Uno.fsproj b/Fabulous.Uno/src/Fabulous.Uno/Fabulous.Uno.fsproj index 3c69fad..3527865 100644 --- a/Fabulous.Uno/src/Fabulous.Uno/Fabulous.Uno.fsproj +++ b/Fabulous.Uno/src/Fabulous.Uno/Fabulous.Uno.fsproj @@ -11,12 +11,17 @@ + + + + + diff --git a/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.fs b/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.fs index ed5db75..89a4493 100644 --- a/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.fs +++ b/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.fs @@ -1,6 +1,8 @@ // Copyright 2018-2019 Fabulous contributors. See LICENSE.md for license. namespace Fabulous.Uno +open System + #nowarn "59" // cast always holds #nowarn "66" // cast always holds #nowarn "67" // cast always holds @@ -12,9 +14,22 @@ module ViewAttributes = let LoadedEventAttribKey : AttributeKey<_> = AttributeKey<_>("LoadedEvent") let WidthAttribKey : AttributeKey<_> = AttributeKey<_>("Width") let HeightAttribKey : AttributeKey<_> = AttributeKey<_>("Height") + let HorizontalAlignmentAttribKey : AttributeKey<_> = AttributeKey<_>("HorizontalAlignment") + let VerticalAlignmentAttribKey : AttributeKey<_> = AttributeKey<_>("VerticalAlignment") + let ContentAttribKey : AttributeKey<_> = AttributeKey<_>("Content") + let CommandAttribKey : AttributeKey<_> = AttributeKey<_>("Command") + let CommandCanExecuteAttribKey : AttributeKey<_> = AttributeKey<_>("CommandCanExecute") + let ValueChangedAttribKey : AttributeKey<_> = AttributeKey<_>("ValueChanged") + let ValueAttribKey : AttributeKey<_> = AttributeKey<_>("Value") + let MinimumMaximumAttribKey : AttributeKey<_> = AttributeKey<_>("MinimumMaximum") + let ToggledAttribKey : AttributeKey<_> = AttributeKey<_>("Toggled") + let IsOnAttribKey : AttributeKey<_> = AttributeKey<_>("IsOn") + let PaddingAttribKey : AttributeKey<_> = AttributeKey<_>("Padding") + let ChildrenAttribKey : AttributeKey<_> = AttributeKey<_>("Children") let RowSpacingAttribKey : AttributeKey<_> = AttributeKey<_>("RowSpacing") let OrientationAttribKey : AttributeKey<_> = AttributeKey<_>("Orientation") let TextAttribKey : AttributeKey<_> = AttributeKey<_>("Text") + let HorizontalTextAlignmentAttribKey : AttributeKey<_> = AttributeKey<_>("HorizontalTextAlignment") let ForegroundAttribKey : AttributeKey<_> = AttributeKey<_>("Foreground") type ViewBuilders() = @@ -59,16 +74,22 @@ type ViewBuilders() = static member inline BuildFrameworkElement(attribCount: int, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribCount = match width with Some _ -> attribCount + 1 | None -> attribCount let attribCount = match height with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match horizontalAlignment with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match verticalAlignment with Some _ -> attribCount + 1 | None -> attribCount let attribCount = match loadedEvent with Some _ -> attribCount + 1 | None -> attribCount let attribBuilder = ViewBuilders.BuildUIElement(attribCount, ?opacity=opacity) match width with None -> () | Some v -> attribBuilder.Add(ViewAttributes.WidthAttribKey, (v)) match height with None -> () | Some v -> attribBuilder.Add(ViewAttributes.HeightAttribKey, (v)) + match horizontalAlignment with None -> () | Some v -> attribBuilder.Add(ViewAttributes.HorizontalAlignmentAttribKey, (v)) + match verticalAlignment with None -> () | Some v -> attribBuilder.Add(ViewAttributes.VerticalAlignmentAttribKey, (v)) match loadedEvent with None -> () | Some v -> attribBuilder.Add(ViewAttributes.LoadedEventAttribKey, (fun f -> System.EventHandler(fun _sender _args -> f _args))(v)) attribBuilder @@ -80,11 +101,19 @@ type ViewBuilders() = let mutable currWidthOpt = ValueNone let mutable prevHeightOpt = ValueNone let mutable currHeightOpt = ValueNone + let mutable prevHorizontalAlignmentOpt = ValueNone + let mutable currHorizontalAlignmentOpt = ValueNone + let mutable prevVerticalAlignmentOpt = ValueNone + let mutable currVerticalAlignmentOpt = ValueNone for kvp in curr.AttributesKeyed do if kvp.Key = ViewAttributes.WidthAttribKey.KeyValue then currWidthOpt <- ValueSome (kvp.Value :?> float) if kvp.Key = ViewAttributes.HeightAttribKey.KeyValue then currHeightOpt <- ValueSome (kvp.Value :?> float) + if kvp.Key = ViewAttributes.HorizontalAlignmentAttribKey.KeyValue then + currHorizontalAlignmentOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.HorizontalAlignment) + if kvp.Key = ViewAttributes.VerticalAlignmentAttribKey.KeyValue then + currVerticalAlignmentOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.VerticalAlignment) match prevOpt with | ValueNone -> () | ValueSome prev -> @@ -93,6 +122,10 @@ type ViewBuilders() = prevWidthOpt <- ValueSome (kvp.Value :?> float) if kvp.Key = ViewAttributes.HeightAttribKey.KeyValue then prevHeightOpt <- ValueSome (kvp.Value :?> float) + if kvp.Key = ViewAttributes.HorizontalAlignmentAttribKey.KeyValue then + prevHorizontalAlignmentOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.HorizontalAlignment) + if kvp.Key = ViewAttributes.VerticalAlignmentAttribKey.KeyValue then + prevVerticalAlignmentOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.VerticalAlignment) // Update inherited members ViewBuilders.UpdateUIElement (prevOpt, curr, target) // Update properties @@ -106,59 +139,445 @@ type ViewBuilders() = | _, ValueSome currValue -> target.Height <- currValue | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.FrameworkElement.HeightProperty | ValueNone, ValueNone -> () + match prevHorizontalAlignmentOpt, currHorizontalAlignmentOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.HorizontalAlignment <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.FrameworkElement.HorizontalAlignmentProperty + | ValueNone, ValueNone -> () + match prevVerticalAlignmentOpt, currVerticalAlignmentOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.VerticalAlignment <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.FrameworkElement.VerticalAlignmentProperty + | ValueNone, ValueNone -> () static member inline ConstructFrameworkElement(?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribBuilder = ViewBuilders.BuildFrameworkElement(0, ?width=width, ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) ViewElement.Create(ViewBuilders.CreateFrameworkElement, (fun prevOpt curr target -> ViewBuilders.UpdateFrameworkElement(prevOpt, curr, target)), attribBuilder) - /// Builds the attributes for a Panel in the view - static member inline BuildPanel(attribCount: int, - ?width: float, - ?height: float, - ?opacity: float, - ?loadedEvent: obj -> unit) = - let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?opacity=opacity, ?loadedEvent=loadedEvent) + /// Builds the attributes for a ContentControl in the view + static member inline BuildContentControl(attribCount: int, + ?content: obj, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?loadedEvent: obj -> unit) = + + let attribCount = match content with Some _ -> attribCount + 1 | None -> attribCount + + let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, ?opacity=opacity, + ?loadedEvent=loadedEvent) + match content with None -> () | Some v -> attribBuilder.Add(ViewAttributes.ContentAttribKey, (v)) attribBuilder - static member CreatePanel () : Windows.UI.Xaml.Controls.Panel = - new Windows.UI.Xaml.Controls.Panel() + static member CreateContentControl () : Windows.UI.Xaml.Controls.ContentControl = + new Windows.UI.Xaml.Controls.ContentControl() - static member UpdatePanel (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.Panel) = + static member UpdateContentControl (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.ContentControl) = + let mutable prevContentOpt = ValueNone + let mutable currContentOpt = ValueNone + for kvp in curr.AttributesKeyed do + if kvp.Key = ViewAttributes.ContentAttribKey.KeyValue then + currContentOpt <- ValueSome (kvp.Value :?> obj) + match prevOpt with + | ValueNone -> () + | ValueSome prev -> + for kvp in prev.AttributesKeyed do + if kvp.Key = ViewAttributes.ContentAttribKey.KeyValue then + prevContentOpt <- ValueSome (kvp.Value :?> obj) + // Update inherited members ViewBuilders.UpdateFrameworkElement (prevOpt, curr, target) + // Update properties + match prevContentOpt, currContentOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.Content <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.Controls.ContentControl.ContentProperty + | ValueNone, ValueNone -> () - static member inline ConstructPanel(?width: float, - ?height: float, - ?opacity: float, - ?loadedEvent: obj -> unit) = + static member inline ConstructContentControl(?content: obj, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?loadedEvent: obj -> unit) = - let attribBuilder = ViewBuilders.BuildPanel(0, + let attribBuilder = ViewBuilders.BuildContentControl(0, + ?content=content, ?width=width, ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) - ViewElement.Create(ViewBuilders.CreatePanel, (fun prevOpt curr target -> ViewBuilders.UpdatePanel(prevOpt, curr, target)), attribBuilder) + ViewElement.Create(ViewBuilders.CreateContentControl, (fun prevOpt curr target -> ViewBuilders.UpdateContentControl(prevOpt, curr, target)), attribBuilder) + + /// Builds the attributes for a ButtonBase in the view + static member inline BuildButtonBase(attribCount: int, + ?command: unit -> unit, + ?commandCanExecute: bool, + ?content: obj, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?loadedEvent: obj -> unit) = + + let attribCount = match command with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match commandCanExecute with Some _ -> attribCount + 1 | None -> attribCount + + let attribBuilder = ViewBuilders.BuildContentControl(attribCount, ?content=content, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, + ?opacity=opacity, ?loadedEvent=loadedEvent) + match command with None -> () | Some v -> attribBuilder.Add(ViewAttributes.CommandAttribKey, (v)) + match commandCanExecute with None -> () | Some v -> attribBuilder.Add(ViewAttributes.CommandCanExecuteAttribKey, (v)) + attribBuilder + + static member UpdateButtonBase (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.Primitives.ButtonBase) = + let mutable prevCommandOpt = ValueNone + let mutable currCommandOpt = ValueNone + let mutable prevCommandCanExecuteOpt = ValueNone + let mutable currCommandCanExecuteOpt = ValueNone + for kvp in curr.AttributesKeyed do + if kvp.Key = ViewAttributes.CommandAttribKey.KeyValue then + currCommandOpt <- ValueSome (kvp.Value :?> unit -> unit) + if kvp.Key = ViewAttributes.CommandCanExecuteAttribKey.KeyValue then + currCommandCanExecuteOpt <- ValueSome (kvp.Value :?> bool) + match prevOpt with + | ValueNone -> () + | ValueSome prev -> + for kvp in prev.AttributesKeyed do + if kvp.Key = ViewAttributes.CommandAttribKey.KeyValue then + prevCommandOpt <- ValueSome (kvp.Value :?> unit -> unit) + if kvp.Key = ViewAttributes.CommandCanExecuteAttribKey.KeyValue then + prevCommandCanExecuteOpt <- ValueSome (kvp.Value :?> bool) + // Update inherited members + ViewBuilders.UpdateContentControl (prevOpt, curr, target) + // Update properties + (fun _ _ _ -> ()) prevCommandOpt currCommandOpt target + ViewUpdaters.updateCommand prevCommandOpt currCommandOpt (fun _target -> ()) (fun (target: Windows.UI.Xaml.Controls.Primitives.ButtonBase) cmd -> target.Command <- cmd) prevCommandCanExecuteOpt currCommandCanExecuteOpt target + + /// Builds the attributes for a Button in the view + static member inline BuildButton(attribCount: int, + ?command: unit -> unit, + ?commandCanExecute: bool, + ?content: obj, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?loadedEvent: obj -> unit) = + let attribBuilder = ViewBuilders.BuildButtonBase(attribCount, ?command=command, ?commandCanExecute=commandCanExecute, ?content=content, ?width=width, ?height=height, + ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) + attribBuilder + + static member CreateButton () : Windows.UI.Xaml.Controls.Button = + new Windows.UI.Xaml.Controls.Button() + + static member UpdateButton (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.Button) = + ViewBuilders.UpdateButtonBase (prevOpt, curr, target) + + static member inline ConstructButton(?command: unit -> unit, + ?commandCanExecute: bool, + ?content: obj, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?loadedEvent: obj -> unit) = + + let attribBuilder = ViewBuilders.BuildButton(0, + ?command=command, + ?commandCanExecute=commandCanExecute, + ?content=content, + ?width=width, + ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, + ?opacity=opacity, + ?loadedEvent=loadedEvent) + + ViewElement.Create(ViewBuilders.CreateButton, (fun prevOpt curr target -> ViewBuilders.UpdateButton(prevOpt, curr, target)), attribBuilder) + + /// Builds the attributes for a RangeBase in the view + static member inline BuildRangeBase(attribCount: int, + ?value: float, + ?minimumMaximum: double * double, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?valueChanged: double -> unit, + ?loadedEvent: obj -> unit) = + + let attribCount = match value with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match minimumMaximum with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match valueChanged with Some _ -> attribCount + 1 | None -> attribCount + + let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, ?opacity=opacity, + ?loadedEvent=loadedEvent) + match value with None -> () | Some v -> attribBuilder.Add(ViewAttributes.ValueAttribKey, (v)) + match minimumMaximum with None -> () | Some v -> attribBuilder.Add(ViewAttributes.MinimumMaximumAttribKey, (v)) + match valueChanged with None -> () | Some v -> attribBuilder.Add(ViewAttributes.ValueChangedAttribKey, ViewConverters.makeValueChangedEventHandler(v)) + attribBuilder + + static member UpdateRangeBase (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.Primitives.RangeBase) = + let mutable prevValueChangedOpt = ValueNone + let mutable currValueChangedOpt = ValueNone + let mutable prevValueOpt = ValueNone + let mutable currValueOpt = ValueNone + let mutable prevMinimumMaximumOpt = ValueNone + let mutable currMinimumMaximumOpt = ValueNone + for kvp in curr.AttributesKeyed do + if kvp.Key = ViewAttributes.ValueChangedAttribKey.KeyValue then + currValueChangedOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventHandler) + if kvp.Key = ViewAttributes.ValueAttribKey.KeyValue then + currValueOpt <- ValueSome (kvp.Value :?> float) + if kvp.Key = ViewAttributes.MinimumMaximumAttribKey.KeyValue then + currMinimumMaximumOpt <- ValueSome (kvp.Value :?> double * double) + match prevOpt with + | ValueNone -> () + | ValueSome prev -> + for kvp in prev.AttributesKeyed do + if kvp.Key = ViewAttributes.ValueChangedAttribKey.KeyValue then + prevValueChangedOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventHandler) + if kvp.Key = ViewAttributes.ValueAttribKey.KeyValue then + prevValueOpt <- ValueSome (kvp.Value :?> float) + if kvp.Key = ViewAttributes.MinimumMaximumAttribKey.KeyValue then + prevMinimumMaximumOpt <- ValueSome (kvp.Value :?> double * double) + // Unsubscribe previous event handlers + let shouldUpdateValueChanged = not ((identical prevValueChangedOpt currValueChangedOpt) && (identical prevValueOpt currValueOpt)) + if shouldUpdateValueChanged then + match prevValueChangedOpt with + | ValueSome prevValue -> target.ValueChanged.RemoveHandler(prevValue) + | ValueNone -> () + // Update inherited members + ViewBuilders.UpdateFrameworkElement (prevOpt, curr, target) + // Update properties + match prevValueOpt, currValueOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.Value <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.Controls.Primitives.RangeBase.ValueProperty + | ValueNone, ValueNone -> () + ViewUpdaters.updateRangeBaseMinimumMaximum prevMinimumMaximumOpt currMinimumMaximumOpt target + // Subscribe new event handlers + if shouldUpdateValueChanged then + match currValueChangedOpt with + | ValueSome currValue -> target.ValueChanged.AddHandler(currValue) + | ValueNone -> () + + /// Builds the attributes for a Slider in the view + static member inline BuildSlider(attribCount: int, + ?value: float, + ?minimumMaximum: double * double, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?valueChanged: double -> unit, + ?loadedEvent: obj -> unit) = + let attribBuilder = ViewBuilders.BuildRangeBase(attribCount, ?value=value, ?minimumMaximum=minimumMaximum, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?valueChanged=valueChanged, ?loadedEvent=loadedEvent) + attribBuilder + + static member CreateSlider () : Windows.UI.Xaml.Controls.Slider = + new Windows.UI.Xaml.Controls.Slider() + + static member UpdateSlider (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.Slider) = + ViewBuilders.UpdateRangeBase (prevOpt, curr, target) + + static member inline ConstructSlider(?value: float, + ?minimumMaximum: double * double, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?valueChanged: double -> unit, + ?loadedEvent: obj -> unit) = + + let attribBuilder = ViewBuilders.BuildSlider(0, + ?value=value, + ?minimumMaximum=minimumMaximum, + ?width=width, + ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, + ?opacity=opacity, + ?valueChanged=valueChanged, + ?loadedEvent=loadedEvent) + + ViewElement.Create(ViewBuilders.CreateSlider, (fun prevOpt curr target -> ViewBuilders.UpdateSlider(prevOpt, curr, target)), attribBuilder) + + /// Builds the attributes for a ToggleSwitch in the view + static member inline BuildToggleSwitch(attribCount: int, + ?isOn: bool, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?toggled: bool -> unit, + ?loadedEvent: obj -> unit) = + + let attribCount = match isOn with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match toggled with Some _ -> attribCount + 1 | None -> attribCount + + let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, ?opacity=opacity, + ?loadedEvent=loadedEvent) + match isOn with None -> () | Some v -> attribBuilder.Add(ViewAttributes.IsOnAttribKey, (v)) + match toggled with None -> () | Some v -> attribBuilder.Add(ViewAttributes.ToggledAttribKey, ViewConverters.makeToggledEventHandler(v)) + attribBuilder + + static member CreateToggleSwitch () : Windows.UI.Xaml.Controls.ToggleSwitch = + new Windows.UI.Xaml.Controls.ToggleSwitch() + + static member UpdateToggleSwitch (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.ToggleSwitch) = + let mutable prevToggledOpt = ValueNone + let mutable currToggledOpt = ValueNone + let mutable prevIsOnOpt = ValueNone + let mutable currIsOnOpt = ValueNone + for kvp in curr.AttributesKeyed do + if kvp.Key = ViewAttributes.ToggledAttribKey.KeyValue then + currToggledOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.RoutedEventHandler) + if kvp.Key = ViewAttributes.IsOnAttribKey.KeyValue then + currIsOnOpt <- ValueSome (kvp.Value :?> bool) + match prevOpt with + | ValueNone -> () + | ValueSome prev -> + for kvp in prev.AttributesKeyed do + if kvp.Key = ViewAttributes.ToggledAttribKey.KeyValue then + prevToggledOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.RoutedEventHandler) + if kvp.Key = ViewAttributes.IsOnAttribKey.KeyValue then + prevIsOnOpt <- ValueSome (kvp.Value :?> bool) + // Unsubscribe previous event handlers + let shouldUpdateToggled = not ((identical prevToggledOpt currToggledOpt) && (identical prevIsOnOpt currIsOnOpt)) + if shouldUpdateToggled then + match prevToggledOpt with + | ValueSome prevValue -> target.Toggled.RemoveHandler(prevValue) + | ValueNone -> () + // Update inherited members + ViewBuilders.UpdateFrameworkElement (prevOpt, curr, target) + // Update properties + match prevIsOnOpt, currIsOnOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.IsOn <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.Controls.ToggleSwitch.IsOnProperty + | ValueNone, ValueNone -> () + // Subscribe new event handlers + if shouldUpdateToggled then + match currToggledOpt with + | ValueSome currValue -> target.Toggled.AddHandler(currValue) + | ValueNone -> () + + static member inline ConstructToggleSwitch(?isOn: bool, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?toggled: bool -> unit, + ?loadedEvent: obj -> unit) = + + let attribBuilder = ViewBuilders.BuildToggleSwitch(0, + ?isOn=isOn, + ?width=width, + ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, + ?opacity=opacity, + ?toggled=toggled, + ?loadedEvent=loadedEvent) + + ViewElement.Create(ViewBuilders.CreateToggleSwitch, (fun prevOpt curr target -> ViewBuilders.UpdateToggleSwitch(prevOpt, curr, target)), attribBuilder) + + /// Builds the attributes for a Panel in the view + static member inline BuildPanel(attribCount: int, + ?padding: Windows.UI.Xaml.Thickness, + ?children: ViewElement list, + ?width: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?opacity: float, + ?loadedEvent: obj -> unit) = + + let attribCount = match padding with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match children with Some _ -> attribCount + 1 | None -> attribCount + + let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, ?opacity=opacity, + ?loadedEvent=loadedEvent) + match padding with None -> () | Some v -> attribBuilder.Add(ViewAttributes.PaddingAttribKey, (v)) + match children with None -> () | Some v -> attribBuilder.Add(ViewAttributes.ChildrenAttribKey, Array.ofList(v)) + attribBuilder + + static member UpdatePanel (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.Panel) = + let mutable prevPaddingOpt = ValueNone + let mutable currPaddingOpt = ValueNone + let mutable prevChildrenOpt = ValueNone + let mutable currChildrenOpt = ValueNone + for kvp in curr.AttributesKeyed do + if kvp.Key = ViewAttributes.PaddingAttribKey.KeyValue then + currPaddingOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.Thickness) + if kvp.Key = ViewAttributes.ChildrenAttribKey.KeyValue then + currChildrenOpt <- ValueSome (kvp.Value :?> ViewElement array) + match prevOpt with + | ValueNone -> () + | ValueSome prev -> + for kvp in prev.AttributesKeyed do + if kvp.Key = ViewAttributes.PaddingAttribKey.KeyValue then + prevPaddingOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.Thickness) + if kvp.Key = ViewAttributes.ChildrenAttribKey.KeyValue then + prevChildrenOpt <- ValueSome (kvp.Value :?> ViewElement array) + // Update inherited members + ViewBuilders.UpdateFrameworkElement (prevOpt, curr, target) + // Update properties + match prevPaddingOpt, currPaddingOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.Padding <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.Controls.Panel.PaddingProperty + | ValueNone, ValueNone -> () + ViewUpdaters.updateCollectionGeneric prevChildrenOpt currChildrenOpt target.Children + (fun (x:ViewElement) -> x.Create() :?> Windows.UI.Xaml.UIElement) + (fun _ _ _ -> ()) + ViewHelpers.canReuseView + ViewUpdaters.updateChild /// Builds the attributes for a Grid in the view static member inline BuildGrid(attribCount: int, ?rowSpacing: float, + ?padding: Windows.UI.Xaml.Thickness, + ?children: ViewElement list, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribCount = match rowSpacing with Some _ -> attribCount + 1 | None -> attribCount - let attribBuilder = ViewBuilders.BuildPanel(attribCount, ?width=width, ?height=height, ?opacity=opacity, ?loadedEvent=loadedEvent) + let attribBuilder = ViewBuilders.BuildPanel(attribCount, ?padding=padding, ?children=children, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) match rowSpacing with None -> () | Some v -> attribBuilder.Add(ViewAttributes.RowSpacingAttribKey, (v)) attribBuilder @@ -187,15 +606,23 @@ type ViewBuilders() = | ValueNone, ValueNone -> () static member inline ConstructGrid(?rowSpacing: float, + ?padding: Windows.UI.Xaml.Thickness, + ?children: ViewElement list, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribBuilder = ViewBuilders.BuildGrid(0, ?rowSpacing=rowSpacing, + ?padding=padding, + ?children=children, ?width=width, ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) @@ -204,14 +631,19 @@ type ViewBuilders() = /// Builds the attributes for a StackPanel in the view static member inline BuildStackPanel(attribCount: int, ?orientation: Windows.UI.Xaml.Controls.Orientation, + ?padding: Windows.UI.Xaml.Thickness, + ?children: ViewElement list, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribCount = match orientation with Some _ -> attribCount + 1 | None -> attribCount - let attribBuilder = ViewBuilders.BuildPanel(attribCount, ?width=width, ?height=height, ?opacity=opacity, ?loadedEvent=loadedEvent) + let attribBuilder = ViewBuilders.BuildPanel(attribCount, ?padding=padding, ?children=children, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) match orientation with None -> () | Some v -> attribBuilder.Add(ViewAttributes.OrientationAttribKey, (v)) attribBuilder @@ -240,15 +672,23 @@ type ViewBuilders() = | ValueNone, ValueNone -> () static member inline ConstructStackPanel(?orientation: Windows.UI.Xaml.Controls.Orientation, + ?padding: Windows.UI.Xaml.Thickness, + ?children: ViewElement list, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribBuilder = ViewBuilders.BuildStackPanel(0, ?orientation=orientation, + ?padding=padding, + ?children=children, ?width=width, ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) @@ -257,17 +697,23 @@ type ViewBuilders() = /// Builds the attributes for a TextBlock in the view static member inline BuildTextBlock(attribCount: int, ?text: string, + ?horizontalTextAlignment: Windows.UI.Xaml.TextAlignment, ?foreground: Windows.UI.Xaml.Media.Brush, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribCount = match text with Some _ -> attribCount + 1 | None -> attribCount + let attribCount = match horizontalTextAlignment with Some _ -> attribCount + 1 | None -> attribCount let attribCount = match foreground with Some _ -> attribCount + 1 | None -> attribCount - let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?opacity=opacity, ?loadedEvent=loadedEvent) + let attribBuilder = ViewBuilders.BuildFrameworkElement(attribCount, ?width=width, ?height=height, ?horizontalAlignment=horizontalAlignment, ?verticalAlignment=verticalAlignment, ?opacity=opacity, + ?loadedEvent=loadedEvent) match text with None -> () | Some v -> attribBuilder.Add(ViewAttributes.TextAttribKey, (v)) + match horizontalTextAlignment with None -> () | Some v -> attribBuilder.Add(ViewAttributes.HorizontalTextAlignmentAttribKey, (v)) match foreground with None -> () | Some v -> attribBuilder.Add(ViewAttributes.ForegroundAttribKey, (v)) attribBuilder @@ -277,11 +723,15 @@ type ViewBuilders() = static member UpdateTextBlock (prevOpt: ViewElement voption, curr: ViewElement, target: Windows.UI.Xaml.Controls.TextBlock) = let mutable prevTextOpt = ValueNone let mutable currTextOpt = ValueNone + let mutable prevHorizontalTextAlignmentOpt = ValueNone + let mutable currHorizontalTextAlignmentOpt = ValueNone let mutable prevForegroundOpt = ValueNone let mutable currForegroundOpt = ValueNone for kvp in curr.AttributesKeyed do if kvp.Key = ViewAttributes.TextAttribKey.KeyValue then currTextOpt <- ValueSome (kvp.Value :?> string) + if kvp.Key = ViewAttributes.HorizontalTextAlignmentAttribKey.KeyValue then + currHorizontalTextAlignmentOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.TextAlignment) if kvp.Key = ViewAttributes.ForegroundAttribKey.KeyValue then currForegroundOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.Media.Brush) match prevOpt with @@ -290,6 +740,8 @@ type ViewBuilders() = for kvp in prev.AttributesKeyed do if kvp.Key = ViewAttributes.TextAttribKey.KeyValue then prevTextOpt <- ValueSome (kvp.Value :?> string) + if kvp.Key = ViewAttributes.HorizontalTextAlignmentAttribKey.KeyValue then + prevHorizontalTextAlignmentOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.TextAlignment) if kvp.Key = ViewAttributes.ForegroundAttribKey.KeyValue then prevForegroundOpt <- ValueSome (kvp.Value :?> Windows.UI.Xaml.Media.Brush) // Update inherited members @@ -300,6 +752,11 @@ type ViewBuilders() = | _, ValueSome currValue -> target.Text <- currValue | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.Controls.TextBlock.TextProperty | ValueNone, ValueNone -> () + match prevHorizontalTextAlignmentOpt, currHorizontalTextAlignmentOpt with + | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () + | _, ValueSome currValue -> target.HorizontalTextAlignment <- currValue + | ValueSome _, ValueNone -> target.ClearValue Windows.UI.Xaml.Controls.TextBlock.HorizontalTextAlignmentProperty + | ValueNone, ValueNone -> () match prevForegroundOpt, currForegroundOpt with | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> () | _, ValueSome currValue -> target.Foreground <- currValue @@ -307,17 +764,23 @@ type ViewBuilders() = | ValueNone, ValueNone -> () static member inline ConstructTextBlock(?text: string, + ?horizontalTextAlignment: Windows.UI.Xaml.TextAlignment, ?foreground: Windows.UI.Xaml.Media.Brush, ?width: float, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?opacity: float, ?loadedEvent: obj -> unit) = let attribBuilder = ViewBuilders.BuildTextBlock(0, ?text=text, + ?horizontalTextAlignment=horizontalTextAlignment, ?foreground=foreground, ?width=width, ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?verticalAlignment=verticalAlignment, ?opacity=opacity, ?loadedEvent=loadedEvent) @@ -341,13 +804,67 @@ type FrameworkElementViewer(element: ViewElement) = member this.Width = element.GetAttributeKeyed(ViewAttributes.WidthAttribKey) /// Get the value of the Height member member this.Height = element.GetAttributeKeyed(ViewAttributes.HeightAttribKey) + /// Get the value of the HorizontalAlignment member + member this.HorizontalAlignment = element.GetAttributeKeyed(ViewAttributes.HorizontalAlignmentAttribKey) + /// Get the value of the VerticalAlignment member + member this.VerticalAlignment = element.GetAttributeKeyed(ViewAttributes.VerticalAlignmentAttribKey) /// Get the value of the LoadedEvent member member this.LoadedEvent = element.GetAttributeKeyed(ViewAttributes.LoadedEventAttribKey) +/// Viewer that allows to read the properties of a ViewElement representing a ContentControl +type ContentControlViewer(element: ViewElement) = + inherit FrameworkElementViewer(element) + do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.ContentControl' is expected, but '%s' was provided." element.TargetType.FullName + /// Get the value of the Content member + member this.Content = element.GetAttributeKeyed(ViewAttributes.ContentAttribKey) + +/// Viewer that allows to read the properties of a ViewElement representing a ButtonBase +type ButtonBaseViewer(element: ViewElement) = + inherit ContentControlViewer(element) + do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.Primitives.ButtonBase' is expected, but '%s' was provided." element.TargetType.FullName + /// Get the value of the Command member + member this.Command = element.GetAttributeKeyed(ViewAttributes.CommandAttribKey) + /// Get the value of the CommandCanExecute member + member this.CommandCanExecute = element.GetAttributeKeyed(ViewAttributes.CommandCanExecuteAttribKey) + +/// Viewer that allows to read the properties of a ViewElement representing a Button +type ButtonViewer(element: ViewElement) = + inherit ButtonBaseViewer(element) + do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.Button' is expected, but '%s' was provided." element.TargetType.FullName + +/// Viewer that allows to read the properties of a ViewElement representing a RangeBase +type RangeBaseViewer(element: ViewElement) = + inherit FrameworkElementViewer(element) + do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.Primitives.RangeBase' is expected, but '%s' was provided." element.TargetType.FullName + /// Get the value of the Value member + member this.Value = element.GetAttributeKeyed(ViewAttributes.ValueAttribKey) + /// Get the value of the MinimumMaximum member + member this.MinimumMaximum = element.GetAttributeKeyed(ViewAttributes.MinimumMaximumAttribKey) + /// Get the value of the ValueChanged member + member this.ValueChanged = element.GetAttributeKeyed(ViewAttributes.ValueChangedAttribKey) + +/// Viewer that allows to read the properties of a ViewElement representing a Slider +type SliderViewer(element: ViewElement) = + inherit RangeBaseViewer(element) + do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.Slider' is expected, but '%s' was provided." element.TargetType.FullName + +/// Viewer that allows to read the properties of a ViewElement representing a ToggleSwitch +type ToggleSwitchViewer(element: ViewElement) = + inherit FrameworkElementViewer(element) + do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.ToggleSwitch' is expected, but '%s' was provided." element.TargetType.FullName + /// Get the value of the IsOn member + member this.IsOn = element.GetAttributeKeyed(ViewAttributes.IsOnAttribKey) + /// Get the value of the Toggled member + member this.Toggled = element.GetAttributeKeyed(ViewAttributes.ToggledAttribKey) + /// Viewer that allows to read the properties of a ViewElement representing a Panel type PanelViewer(element: ViewElement) = inherit FrameworkElementViewer(element) do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.Panel' is expected, but '%s' was provided." element.TargetType.FullName + /// Get the value of the Padding member + member this.Padding = element.GetAttributeKeyed(ViewAttributes.PaddingAttribKey) + /// Get the value of the Children member + member this.Children = element.GetAttributeKeyed(ViewAttributes.ChildrenAttribKey) /// Viewer that allows to read the properties of a ViewElement representing a Grid type GridViewer(element: ViewElement) = @@ -369,6 +886,8 @@ type TextBlockViewer(element: ViewElement) = do if not ((typeof).IsAssignableFrom(element.TargetType)) then failwithf "A ViewElement assignable to type 'Windows.UI.Xaml.Controls.TextBlock' is expected, but '%s' was provided." element.TargetType.FullName /// Get the value of the Text member member this.Text = element.GetAttributeKeyed(ViewAttributes.TextAttribKey) + /// Get the value of the HorizontalTextAlignment member + member this.HorizontalTextAlignment = element.GetAttributeKeyed(ViewAttributes.HorizontalTextAlignmentAttribKey) /// Get the value of the Foreground member member this.Foreground = element.GetAttributeKeyed(ViewAttributes.ForegroundAttribKey) @@ -376,65 +895,158 @@ type TextBlockViewer(element: ViewElement) = type View private () = /// Describes a FrameworkElement in the view static member inline FrameworkElement(?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, ?loadedEvent: obj -> unit, ?opacity: float, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?width: float) = ViewBuilders.ConstructFrameworkElement(?height=height, + ?horizontalAlignment=horizontalAlignment, ?loadedEvent=loadedEvent, ?opacity=opacity, + ?verticalAlignment=verticalAlignment, ?width=width) - /// Describes a Panel in the view - static member inline Panel(?height: float, - ?loadedEvent: obj -> unit, - ?opacity: float, - ?width: float) = + /// Describes a ContentControl in the view + static member inline ContentControl(?content: obj, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?loadedEvent: obj -> unit, + ?opacity: float, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?width: float) = - ViewBuilders.ConstructPanel(?height=height, + ViewBuilders.ConstructContentControl(?content=content, + ?height=height, + ?horizontalAlignment=horizontalAlignment, ?loadedEvent=loadedEvent, ?opacity=opacity, + ?verticalAlignment=verticalAlignment, + ?width=width) + + /// Describes a Button in the view + static member inline Button(?command: unit -> unit, + ?commandCanExecute: bool, + ?content: obj, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?loadedEvent: obj -> unit, + ?opacity: float, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?width: float) = + + ViewBuilders.ConstructButton(?command=command, + ?commandCanExecute=commandCanExecute, + ?content=content, + ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?loadedEvent=loadedEvent, + ?opacity=opacity, + ?verticalAlignment=verticalAlignment, + ?width=width) + + /// Describes a Slider in the view + static member inline Slider(?value: float, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?loadedEvent: obj -> unit, + ?minimumMaximum: double * double, + ?opacity: float, + ?valueChanged: double -> unit, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?width: float) = + + ViewBuilders.ConstructSlider(?value=value, + ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?loadedEvent=loadedEvent, + ?minimumMaximum=minimumMaximum, + ?opacity=opacity, + ?valueChanged=valueChanged, + ?verticalAlignment=verticalAlignment, + ?width=width) + + /// Describes a ToggleSwitch in the view + static member inline ToggleSwitch(?isOn: bool, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?loadedEvent: obj -> unit, + ?opacity: float, + ?toggled: bool -> unit, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, + ?width: float) = + + ViewBuilders.ConstructToggleSwitch(?isOn=isOn, + ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?loadedEvent=loadedEvent, + ?opacity=opacity, + ?toggled=toggled, + ?verticalAlignment=verticalAlignment, ?width=width) /// Describes a Grid in the view - static member inline Grid(?height: float, + static member inline Grid(?children: ViewElement list, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, ?loadedEvent: obj -> unit, ?opacity: float, + ?padding: Windows.UI.Xaml.Thickness, ?rowSpacing: float, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?width: float) = - ViewBuilders.ConstructGrid(?height=height, + ViewBuilders.ConstructGrid(?children=children, + ?height=height, + ?horizontalAlignment=horizontalAlignment, ?loadedEvent=loadedEvent, ?opacity=opacity, + ?padding=padding, ?rowSpacing=rowSpacing, + ?verticalAlignment=verticalAlignment, ?width=width) /// Describes a StackPanel in the view - static member inline StackPanel(?height: float, + static member inline StackPanel(?children: ViewElement list, + ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, ?loadedEvent: obj -> unit, ?opacity: float, ?orientation: Windows.UI.Xaml.Controls.Orientation, + ?padding: Windows.UI.Xaml.Thickness, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?width: float) = - ViewBuilders.ConstructStackPanel(?height=height, + ViewBuilders.ConstructStackPanel(?children=children, + ?height=height, + ?horizontalAlignment=horizontalAlignment, ?loadedEvent=loadedEvent, ?opacity=opacity, ?orientation=orientation, + ?padding=padding, + ?verticalAlignment=verticalAlignment, ?width=width) /// Describes a TextBlock in the view static member inline TextBlock(?foreground: Windows.UI.Xaml.Media.Brush, ?height: float, + ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?horizontalTextAlignment: Windows.UI.Xaml.TextAlignment, ?loadedEvent: obj -> unit, ?opacity: float, ?text: string, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?width: float) = ViewBuilders.ConstructTextBlock(?foreground=foreground, ?height=height, + ?horizontalAlignment=horizontalAlignment, + ?horizontalTextAlignment=horizontalTextAlignment, ?loadedEvent=loadedEvent, ?opacity=opacity, ?text=text, + ?verticalAlignment=verticalAlignment, ?width=width) @@ -455,6 +1067,42 @@ module ViewElementExtensions = /// Adjusts the Height property in the visual element member x.Height(value: float) = x.WithAttribute(ViewAttributes.HeightAttribKey, (value)) + /// Adjusts the HorizontalAlignment property in the visual element + member x.HorizontalAlignment(value: Windows.UI.Xaml.HorizontalAlignment) = x.WithAttribute(ViewAttributes.HorizontalAlignmentAttribKey, (value)) + + /// Adjusts the VerticalAlignment property in the visual element + member x.VerticalAlignment(value: Windows.UI.Xaml.VerticalAlignment) = x.WithAttribute(ViewAttributes.VerticalAlignmentAttribKey, (value)) + + /// Adjusts the Content property in the visual element + member x.Content(value: obj) = x.WithAttribute(ViewAttributes.ContentAttribKey, (value)) + + /// Adjusts the Command property in the visual element + member x.Command(value: unit -> unit) = x.WithAttribute(ViewAttributes.CommandAttribKey, (value)) + + /// Adjusts the CommandCanExecute property in the visual element + member x.CommandCanExecute(value: bool) = x.WithAttribute(ViewAttributes.CommandCanExecuteAttribKey, (value)) + + /// Adjusts the ValueChanged property in the visual element + member x.ValueChanged(value: double -> unit) = x.WithAttribute(ViewAttributes.ValueChangedAttribKey, ViewConverters.makeValueChangedEventHandler(value)) + + /// Adjusts the Value property in the visual element + member x.Value(value: float) = x.WithAttribute(ViewAttributes.ValueAttribKey, (value)) + + /// Adjusts the MinimumMaximum property in the visual element + member x.MinimumMaximum(value: double * double) = x.WithAttribute(ViewAttributes.MinimumMaximumAttribKey, (value)) + + /// Adjusts the Toggled property in the visual element + member x.Toggled(value: bool -> unit) = x.WithAttribute(ViewAttributes.ToggledAttribKey, ViewConverters.makeToggledEventHandler(value)) + + /// Adjusts the IsOn property in the visual element + member x.IsOn(value: bool) = x.WithAttribute(ViewAttributes.IsOnAttribKey, (value)) + + /// Adjusts the Padding property in the visual element + member x.Padding(value: Windows.UI.Xaml.Thickness) = x.WithAttribute(ViewAttributes.PaddingAttribKey, (value)) + + /// Adjusts the Children property in the visual element + member x.Children(value: ViewElement list) = x.WithAttribute(ViewAttributes.ChildrenAttribKey, Array.ofList(value)) + /// Adjusts the RowSpacing property in the visual element member x.RowSpacing(value: float) = x.WithAttribute(ViewAttributes.RowSpacingAttribKey, (value)) @@ -464,18 +1112,37 @@ module ViewElementExtensions = /// Adjusts the Text property in the visual element member x.Text(value: string) = x.WithAttribute(ViewAttributes.TextAttribKey, (value)) + /// Adjusts the HorizontalTextAlignment property in the visual element + member x.HorizontalTextAlignment(value: Windows.UI.Xaml.TextAlignment) = x.WithAttribute(ViewAttributes.HorizontalTextAlignmentAttribKey, (value)) + /// Adjusts the Foreground property in the visual element member x.Foreground(value: Windows.UI.Xaml.Media.Brush) = x.WithAttribute(ViewAttributes.ForegroundAttribKey, (value)) - member inline x.With(?opacity: float, ?loadedEvent: obj -> unit, ?width: float, ?height: float, ?rowSpacing: float, - ?orientation: Windows.UI.Xaml.Controls.Orientation, ?text: string, ?foreground: Windows.UI.Xaml.Media.Brush) = + member inline x.With(?opacity: float, ?loadedEvent: obj -> unit, ?width: float, ?height: float, ?horizontalAlignment: Windows.UI.Xaml.HorizontalAlignment, + ?verticalAlignment: Windows.UI.Xaml.VerticalAlignment, ?content: obj, ?command: unit -> unit, ?commandCanExecute: bool, ?valueChanged: double -> unit, + ?value: float, ?minimumMaximum: double * double, ?toggled: bool -> unit, ?isOn: bool, ?padding: Windows.UI.Xaml.Thickness, + ?children: ViewElement list, ?rowSpacing: float, ?orientation: Windows.UI.Xaml.Controls.Orientation, ?text: string, ?horizontalTextAlignment: Windows.UI.Xaml.TextAlignment, + ?foreground: Windows.UI.Xaml.Media.Brush) = let x = match opacity with None -> x | Some opt -> x.Opacity(opt) let x = match loadedEvent with None -> x | Some opt -> x.LoadedEvent(opt) let x = match width with None -> x | Some opt -> x.Width(opt) let x = match height with None -> x | Some opt -> x.Height(opt) + let x = match horizontalAlignment with None -> x | Some opt -> x.HorizontalAlignment(opt) + let x = match verticalAlignment with None -> x | Some opt -> x.VerticalAlignment(opt) + let x = match content with None -> x | Some opt -> x.Content(opt) + let x = match command with None -> x | Some opt -> x.Command(opt) + let x = match commandCanExecute with None -> x | Some opt -> x.CommandCanExecute(opt) + let x = match valueChanged with None -> x | Some opt -> x.ValueChanged(opt) + let x = match value with None -> x | Some opt -> x.Value(opt) + let x = match minimumMaximum with None -> x | Some opt -> x.MinimumMaximum(opt) + let x = match toggled with None -> x | Some opt -> x.Toggled(opt) + let x = match isOn with None -> x | Some opt -> x.IsOn(opt) + let x = match padding with None -> x | Some opt -> x.Padding(opt) + let x = match children with None -> x | Some opt -> x.Children(opt) let x = match rowSpacing with None -> x | Some opt -> x.RowSpacing(opt) let x = match orientation with None -> x | Some opt -> x.Orientation(opt) let x = match text with None -> x | Some opt -> x.Text(opt) + let x = match horizontalTextAlignment with None -> x | Some opt -> x.HorizontalTextAlignment(opt) let x = match foreground with None -> x | Some opt -> x.Foreground(opt) x @@ -487,11 +1154,37 @@ module ViewElementExtensions = let width (value: float) (x: ViewElement) = x.Width(value) /// Adjusts the Height property in the visual element let height (value: float) (x: ViewElement) = x.Height(value) + /// Adjusts the HorizontalAlignment property in the visual element + let horizontalAlignment (value: Windows.UI.Xaml.HorizontalAlignment) (x: ViewElement) = x.HorizontalAlignment(value) + /// Adjusts the VerticalAlignment property in the visual element + let verticalAlignment (value: Windows.UI.Xaml.VerticalAlignment) (x: ViewElement) = x.VerticalAlignment(value) + /// Adjusts the Content property in the visual element + let content (value: obj) (x: ViewElement) = x.Content(value) + /// Adjusts the Command property in the visual element + let command (value: unit -> unit) (x: ViewElement) = x.Command(value) + /// Adjusts the CommandCanExecute property in the visual element + let commandCanExecute (value: bool) (x: ViewElement) = x.CommandCanExecute(value) + /// Adjusts the ValueChanged property in the visual element + let valueChanged (value: double -> unit) (x: ViewElement) = x.ValueChanged(value) + /// Adjusts the Value property in the visual element + let value (value: float) (x: ViewElement) = x.Value(value) + /// Adjusts the MinimumMaximum property in the visual element + let minimumMaximum (value: double * double) (x: ViewElement) = x.MinimumMaximum(value) + /// Adjusts the Toggled property in the visual element + let toggled (value: bool -> unit) (x: ViewElement) = x.Toggled(value) + /// Adjusts the IsOn property in the visual element + let isOn (value: bool) (x: ViewElement) = x.IsOn(value) + /// Adjusts the Padding property in the visual element + let padding (value: Windows.UI.Xaml.Thickness) (x: ViewElement) = x.Padding(value) + /// Adjusts the Children property in the visual element + let children (value: ViewElement list) (x: ViewElement) = x.Children(value) /// Adjusts the RowSpacing property in the visual element let rowSpacing (value: float) (x: ViewElement) = x.RowSpacing(value) /// Adjusts the Orientation property in the visual element let orientation (value: Windows.UI.Xaml.Controls.Orientation) (x: ViewElement) = x.Orientation(value) /// Adjusts the Text property in the visual element let text (value: string) (x: ViewElement) = x.Text(value) + /// Adjusts the HorizontalTextAlignment property in the visual element + let horizontalTextAlignment (value: Windows.UI.Xaml.TextAlignment) (x: ViewElement) = x.HorizontalTextAlignment(value) /// Adjusts the Foreground property in the visual element let foreground (value: Windows.UI.Xaml.Media.Brush) (x: ViewElement) = x.Foreground(value) diff --git a/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.json b/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.json index 64483d3..94f7e26 100644 --- a/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.json +++ b/Fabulous.Uno/src/Fabulous.Uno/Uno.UI.json @@ -36,6 +36,12 @@ }, { "source": "Height" + }, + { + "source": "HorizontalAlignment" + }, + { + "source": "VerticalAlignment" } ], "events": [ @@ -49,14 +55,110 @@ ] }, { - "type": "Windows.UI.Xaml.Controls.Panel", + "type": "Windows.UI.Xaml.Controls.ContentControl", + "canBeInstantiated": true, + "properties": [ + { + "source": "Content" + } + ], + "events": [ + ] + }, + { + "type": "Windows.UI.Xaml.Controls.Primitives.ButtonBase", + "canBeInstantiated": false, + "properties": [ + { + "source": "Command" + } + ], + "events": [ + ] + }, + { + "type": "Windows.UI.Xaml.Controls.Button", + "canBeInstantiated": true, + "properties": [ + ], + "events": [ + ] + }, + { + "type": "Windows.UI.Xaml.Controls.Primitives.RangeBase", + "canBeInstantiated": false, + "properties": [ + { + "source": "Value" + }, + { + "source": null, + "name": "MinimumMaximum", + "defaultValue": "(0,100)", + "inputType": "double * double", + "updateCode": "ViewUpdaters.updateRangeBaseMinimumMaximum" + } + ], + "events": [ + { + "source": "ValueChanged", + "inputType": "double -> unit", + "convertInputToModel": "ViewConverters.makeValueChangedEventHandler", + "relatedProperties": [ + "Value" + ] + } + ] + }, + { + "type": "Windows.UI.Xaml.Controls.Slider", "canBeInstantiated": true, "properties": [ ], "events": [ ], "primaryConstructorMembers": [ - "Children" + "Value" + ] + }, + { + "type": "Windows.UI.Xaml.Controls.ToggleSwitch", + "canBeInstantiated": true, + "properties": [ + { + "source": "IsOn" + } + ], + "events": [ + { + "source": "Toggled", + "inputType": "bool -> unit", + "convertInputToModel": "ViewConverters.makeToggledEventHandler", + "relatedProperties": [ + "IsOn" + ] + } + ], + "primaryConstructorMembers": [ + "IsOn" + ] + }, + { + "type": "Windows.UI.Xaml.Controls.Panel", + "canBeInstantiated": false, + "properties": [ + { + "source": "Padding" + }, + { + "source": "Children", + "inputType": "ViewElement list", + "collection": { + "elementType": "Windows.UI.Xaml.UIElement" + } + } + ], + "events": [ ] }, { @@ -68,6 +170,9 @@ } ], "events": [ + ], + "primaryConstructorMembers": [ + "Children" ] }, { @@ -76,8 +181,12 @@ "properties": [ { "source": "Orientation" - } ], + } + ], "events": [ + ], + "primaryConstructorMembers": [ + "Children" ] }, { @@ -87,6 +196,9 @@ { "source": "Text" }, + { + "source": "HorizontalTextAlignment" + }, { "source": "Foreground" } diff --git a/Fabulous.Uno/tools/Fabulous.Uno.Generator/Reflection.fs b/Fabulous.Uno/tools/Fabulous.Uno.Generator/Reflection.fs index 46c9c6d..7529543 100644 --- a/Fabulous.Uno/tools/Fabulous.Uno.Generator/Reflection.fs +++ b/Fabulous.Uno/tools/Fabulous.Uno.Generator/Reflection.fs @@ -28,18 +28,14 @@ module Reflection = match ``type``.ContainsGenericParameters with | true -> return None // Generic types are not supported | false -> - let dependencyPropertyFieldInfo = ``type``.GetField(propertyName + "Property") - let dependencyPropertyInfo = ``type``.GetProperty(propertyName + "Property") - if dependencyPropertyInfo <> null || dependencyPropertyFieldInfo <> null then - let filteredProperties = ``type``.GetProperties() |> Array.filter (fun m -> m.Name.Equals(propertyName)) - return match filteredProperties with - | [|property|] -> Some { - Name = propertyName - Type = property.GetMethod.ReturnType |> toCleanTypeName - DefaultValue = null (*property.GetMetadata(``type``).DefaultValue*) } - | _ -> None - else - return None + let fullName = ``type``.FullName + let filteredProperties = ``type``.GetProperties() |> Array.filter (fun m -> m.Name.Equals(propertyName)) + return match filteredProperties with + | [||] -> None + | _ -> Some { + Name = propertyName + Type = (filteredProperties |> Array.head).GetMethod.ReturnType |> toCleanTypeName + DefaultValue = null (*property.GetMetadata(``type``).DefaultValue*) } } diff --git a/Fabulous.Uno/tools/Fabulous.Uno.Generator/UnoConverters.fs b/Fabulous.Uno/tools/Fabulous.Uno.Generator/UnoConverters.fs index 61d699b..7ebd513 100644 --- a/Fabulous.Uno/tools/Fabulous.Uno.Generator/UnoConverters.fs +++ b/Fabulous.Uno/tools/Fabulous.Uno.Generator/UnoConverters.fs @@ -26,6 +26,9 @@ module UnoConverters = | "System.EventHandler" -> "System.EventHandler" | "System.EventHandler>" -> "System.EventHandler" | "System.Tuple" -> "(string * string)" + + //| "Windows.UI.Xaml.RoutedEventHandler" -> "System.EventHandler" + //| "Windows.Foundation.TypedEventHandler" -> "System.EventHandler" | _ -> Converters.convertTypeName typeName let rec tryGetStringRepresentationOfDefaultValue (defaultValue: obj) : string option = diff --git a/Packages.targets b/Packages.targets index f0e3a34..423a162 100644 --- a/Packages.targets +++ b/Packages.targets @@ -28,6 +28,8 @@ + +