User avatar
GameDevMadeEasy
Topic Author
Posts: 2
Joined: 06 Jun 2019, 03:33

Using Noesis with F# and WPF

29 Jul 2019, 08:03

To use Noesis with F# and WPF, there are a few setup steps needed. First of which, we need to get a few packages from Nuget.
NugetFiles.png
After the packages have been installed, make sure you have all the appropriate references.
references.png
references.png (8.56 KiB) Viewed 1272 times
Let's define the App.xaml file.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006 ... esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="HelloWorld.xaml">

<Application.Resources>
</Application.Resources>

</Application>
We now need the app.xaml.fs file. We are pretty much following the conventions set forth in c# for this.
open System
open System.Windows
open FsXaml

type App = XAML<"App.xaml">

[<EntryPoint;STAThread>]
let main argv =
App().Run()
This serves as the entry point of the program. Make sure to have the F# version of the using statement, which is the open statement for System.Windows and FsXaml

Let's use the Hello World Xaml file from the Samples. We will have to make some very slight modifications to it for it to work though. We can remove the xclass and the original local schema. We will make a new xmlns:local schema for clr-namespace: being Views and the assembly being the name of the application, in this case, it is NoesisFunctional. Everything else is exactly the same.
<Window xmlns:local="clr-namespace:Views;assembly=NoesisFunctional"
xmlns="http://schemas.microsoft.com/winfx/2006 ... esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/marku ... ility/2006" mc:Ignorable="d"
Background="#FF124C7A"
Title="Hello, World!">

<Window.Resources>
<Storyboard x:Key="Intro">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="Word">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="276.8">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="GUI">
<EasingColorKeyFrame KeyTime="0" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.5" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.8" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:1.2" Value="#FF2AA6E2"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="Logo">
<EasingDoubleKeyFrame KeyTime="0" Value="-4"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="Logo">
<EasingDoubleKeyFrame KeyTime="0" Value="-180"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="Logo">
<EasingDoubleKeyFrame KeyTime="0" Value="0.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Logo">
<EasingDoubleKeyFrame KeyTime="0" Value="0.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="Line1">
<EasingColorKeyFrame KeyTime="0" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.3" Value="#FF2AA6E2"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="Line2">
<EasingColorKeyFrame KeyTime="0" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.1" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.4" Value="#FF2AA6E2"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="Line3">
<EasingColorKeyFrame KeyTime="0" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.2" Value="#002AA6E2"/>
<EasingColorKeyFrame KeyTime="0:0:0.5" Value="#FF2AA6E2"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="GUI">
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1.1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="GUI">
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1.1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Hello">
<EasingColorKeyFrame KeyTime="0" Value="Transparent"/>
<EasingColorKeyFrame KeyTime="0:0:1" Value="Transparent"/>
<EasingColorKeyFrame KeyTime="0:0:1.3" Value="White">
<EasingColorKeyFrame.EasingFunction>
<SineEase EasingMode="EaseInOut"/>
</EasingColorKeyFrame.EasingFunction>
</EasingColorKeyFrame>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="World">
<EasingColorKeyFrame KeyTime="0" Value="Transparent"/>
<EasingColorKeyFrame KeyTime="0:0:1.2" Value="Transparent"/>
<EasingColorKeyFrame KeyTime="0:0:1.5" Value="White">
<EasingColorKeyFrame.EasingFunction>
<SineEase EasingMode="EaseInOut"/>
</EasingColorKeyFrame.EasingFunction>
</EasingColorKeyFrame>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="Hello">
<EasingDoubleKeyFrame KeyTime="0" Value="-40"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-40"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<SineEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="World">
<EasingDoubleKeyFrame KeyTime="0" Value="-40"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-40"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<SineEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleX)" Storyboard.TargetName="Hello">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="20"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<BackEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleX)" Storyboard.TargetName="World">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="20"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<BackEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Intro}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Viewbox>
<Grid Width="325.8" Margin="24">
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid x:Name="Logo" Grid.Column="0" RenderTransformOrigin="0.5,0.5" Width="49">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Path x:Name="Line1" Data="M6.1,16 L13.7,5.7 32,8 35.7,16.7 39.4,11.9 35.5,3 11.2,0 0,15.2 3.8,24.1 9.5,24.8 6.1,16 z" Fill="#FF2AA6E2" VerticalAlignment="Center" Height="24.8" Margin="0,5.5,9.6,16.5"/>
<Path x:Name="Line2" Data="M15.5,6 L20.6,17.8 9.5,32.6 0,31.4 2.4,37 12.1,38.1 26.8,18.5 19.2,1.2 9.7,0 6.2,4.6 15.5,6.1 z" Fill="#FF2AA6E2" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Height="38.1" Margin="22.2,0,0,8.7"/>
<Path x:Name="Line3" Data="M26,26.8 L13.3,25.4 6.1,8.4 6,8.4 11.8,0.8 5.7,0 0,7.8 9.5,30.3 28.4,32.5 34.1,24.8 31.9,19.4 z" Fill="#FF2AA6E2" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Height="32.5" Margin="9.3,14.3,5.6,0"/>
</Grid>
<Grid x:Name="Word" Grid.Column="1" Width="276.8">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Path x:Name="Noesis" Data="M26.0999999999999,16.9L25.8,16.9C25.2,16.9 24.5999999999999,16.6999999999999 24.0999999999999,16.4 23.5999999999999,16.1 23.0999999999999,15.6999999999999 22.6999999999998,15.1999999999999L12.0999999999999,2.99999999999989C11.1999999999998,1.99999999999989 10.1999999999998,1.19999999999993 9.19999999999982,0.799999999999841 8.19999999999982,0.299999999999841 6.99999999999977,0.0999999999997954 5.49999999999977,0.0999999999997954L-2.27373675443232E-13,0.0999999999997954 -2.27373675443232E-13,21.9999999999998 5.19999999999982,21.9999999999998 5.19999999999982,5.19999999999982 5.49999999999977,5.19999999999982C6.09999999999968,5.19999999999982 6.69999999999982,5.39999999999986 7.19999999999982,5.69999999999982 7.79999999999973,5.99999999999977 8.19999999999982,6.39999999999986 8.59999999999991,6.89999999999986L19,18.9999999999999C19.9000000000001,20.0999999999999 20.9000000000001,20.8999999999999 21.9000000000001,21.3999999999999 23,21.8999999999999 24.2,22.0999999999999 25.8000000000002,22.0999999999999L31.3000000000002,22.0999999999999 31.3000000000002,-1.13686837721616E-13 26.1000000000001,-1.13686837721616E-13 26.0999999999999,16.9z M59.3,0L42.3999999999999,0C36.8999999999999,0,34.0999999999999,2.29999999999995,34.0999999999999,7L34.0999999999999,15C34.0999999999999,19.6,36.8999999999999,22,42.3999999999999,22L59.3,22C64.8,22,67.5999999999999,19.7,67.5999999999999,15L67.5999999999999,7C67.5999999999999,2.39999999999998,64.8,0,59.3,0z M62.2,15C62.2,16.2,61.2,16.9,59.3,16.9L42.3999999999999,16.9C40.4999999999998,16.9,39.4999999999998,16.3,39.4999999999998,15L39.4999999999998,7C39.4999999999998,5.70000000000005,40.4999999999998,5.10000000000002,42.3999999999999,5.10000000000002L59.3,5.10000000000002C61.2,5.10000000000002,62.2,5.70000000000005,62.2,7L62.2,15z M75.7,15.7999999999997L75.7,13.5999999999999 100.9,13.5999999999999 100.9,8.49999999999989 75.7,8.49999999999989 75.7,6.29999999999984C75.7,5.5999999999998,76.1000000000001,5.19999999999982,76.9000000000001,5.19999999999982L101,5.19999999999982 101,-2.27373675443232E-13 76.9000000000001,-2.27373675443232E-13C72.5,-2.27373675443232E-13,70.3000000000002,1.79999999999973,70.3000000000002,5.29999999999973L70.3000000000002,16.4999999999998C70.3000000000002,20.0999999999998,72.5000000000002,21.8999999999998,76.9000000000001,21.8999999999998L101.1,21.8999999999998 101.1,16.7999999999997 76.9000000000001,16.7999999999997C76.1000000000001,16.8999999999998,75.7,16.4999999999998,75.7,15.7999999999997z M128.5,8.39999999999998L110.2,8.39999999999998C109.4,8.39999999999998,108.9,8.10000000000002,108.9,7.60000000000002L108.9,5.89999999999998C108.9,5.39999999999998,109.3,5.10000000000002,110.2,5.10000000000002L134.4,5.10000000000002 134.4,0 110.2,0C105.8,0,103.6,1.79999999999995,103.6,5.29999999999995L103.6,8.79999999999995C103.6,11.9,105.8,13.5,110.2,13.5L128.5,13.5C129.3,13.5,129.7,13.8,129.7,14.3L129.7,16.0999999999999C129.7,16.5999999999999,129.3,16.8999999999999,128.5,16.8999999999999L104.3,16.8999999999999 104.3,21.9999999999999 128.5,21.9999999999999C132.9,21.9999999999999,135.1,20.1999999999999,135.1,16.6999999999999L135.1,13.6999999999999C135.1,10.1999999999999,132.9,8.39999999999998,128.5,8.39999999999998z M137.8,0L143.2,0 143.2,21.9 137.8,21.9z M170.8,8.39999999999998L152.5,8.39999999999998C151.7,8.39999999999998,151.2,8.10000000000002,151.2,7.60000000000002L151.2,5.89999999999998C151.2,5.39999999999998,151.6,5.10000000000002,152.5,5.10000000000002L176.7,5.10000000000002 176.7,0 152.5,0C148.1,0,145.9,1.79999999999995,145.9,5.29999999999995L145.9,8.79999999999995C145.9,11.9,148.1,13.5,152.5,13.5L170.8,13.5C171.6,13.5,172,13.8,172,14.3L172,16.0999999999999C172,16.5999999999999,171.6,16.8999999999999,170.8,16.8999999999999L146.6,16.8999999999999 146.6,21.9999999999999 170.8,21.9999999999999C175.2,21.9999999999999,177.4,20.1999999999999,177.4,16.6999999999999L177.4,13.6999999999999C177.3,10.1999999999999,175.1,8.39999999999998,170.8,8.39999999999998z" Fill="White" VerticalAlignment="Center" Margin="12,0,0,0"/>
<Path x:Name="GUI" Data="M61.9000244140625,16.1C61.9000244140625,16.6,61.5000244140624,16.9,60.7000244140625,16.9L41.5000244140624,16.9C40.7000244140625,16.9,40.2000244140625,16.6,40.2000244140625,16.1L40.2000244140625,0.100000000000023 34.8000244140624,0.100000000000023 34.8000244140624,16.7C34.8000244140624,20.3000000000001,37.0000244140624,22.1,41.4000244140623,22.1L60.6000244140623,22.1C65.0000244140624,22.1,67.2000244140622,20.3000000000001,67.2000244140622,16.8000000000001L67.2000244140622,1.13686837721616E-13 61.8000244140621,1.13686837721616E-13 61.8000244140621,16.1000000000001z M70.0000244140624,0L75.4000244140625,0 75.4000244140625,21.9 70.0000244140624,21.9z M20.1000244140623,8.60000000000002L20.1000244140623,14 26.8000244140624,14 26.8000244140624,16.9 6.60002441406232,16.9C5.80002441406236,16.9,5.30002441406236,16.5,5.30002441406236,15.8L5.30002441406236,6.19999999999993C5.30002441406236,5.49999999999989,5.70002441406245,5.09999999999991,6.60002441406232,5.09999999999991L31.6000244140623,5.09999999999991 31.6000244140623,-1.13686837721616E-13 6.60002441406232,-1.13686837721616E-13C2.20002441406223,-1.13686837721616E-13,2.44140624090505E-05,1.79999999999984,2.44140624090505E-05,5.29999999999984L2.44140624090505E-05,16.4999999999999C2.44140624090505E-05,20.0999999999999,2.20002441406245,21.8999999999999,6.60002441406232,21.8999999999999L32.2000244140622,21.8999999999999 32.2000244140622,8.49999999999989 20.1000244140623,8.49999999999989z" Fill="#FF2AA6E2" VerticalAlignment="Center" Margin="12,0,0,0" RenderTransformOrigin="1,0.5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</StackPanel>
</Grid>
<StackPanel x:Name="HelloWorld" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,15,0,0" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock x:Name="Hello" Text="Hello," FontSize="20" Foreground="White" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="World" Text="World!" FontSize="20" Foreground="White" Margin="5,0,0,0" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
</StackPanel>
</Grid>
</Grid>
</Viewbox>
</Grid>
</Window>
We can now make our HelloWorld.xaml.fs file. It pretty much mirrors the C# version only with F# syntax over C#.
namespace FsXamlApp
#if NOESIS
open Noesis
open Noesis.App
#else
open FsXaml
open System.Windows
open Noesis

#endif
type MainWindow = XAML<"HelloWorld.xaml">
#if NOESIS
type MainWindow() as this =
let InitializeComponent = Noesis.GUI.LoadComponent(this, "HelloWorld.xaml");
#endif

And that's it! You can run the application and it will run as intended.

Let's do a quick modification. One where we don't use FSXAML and just use Noesis.
namespace FsXamlApp
open Noesis
open System.Windows

type MainWindow() as this =
let InitializeComponent = Noesis.GUI.LoadComponent(this, "HelloWorld.xaml");
Now you can run the program and see Noesis doing its' thing.

If you would like an explanation of the F# code in depth, let me know. This was a very quick and fun little side project for me to work on but I figured I would share it with you guys so you can see Noesis working with a functional first language running on the .Net Framework.
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: Using Noesis with F# and WPF

01 Aug 2019, 17:02

Thanks a lot for sharing this with the community, it will be very useful for others looking for this.

Who is online

Users browsing this forum: No registered users and 92 guests