FolderBrowserDialog not opening in fsharp script - f#

I am having a simple script to select a folder,
the process is not responding on call to ShowDialog(),
below is script file, runtime config file and cli command to run,
I think I’m missing something, or my understanding is wrong,
test.fsx
#I #"C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\6.0.10\ref\net6.0"
#r "System.Windows.Forms"
open System
open System.Windows.Forms
let folderPath = new Label()
let button = new Button(Text = "Select Folder")
let ini_dir = #"C:\Users\hayeskev\source\Workspaces"
let openFolderHandler =
EventHandler(fun _ _ ->
let folderDlg = new FolderBrowserDialog()
folderDlg.InitialDirectory <- ini_dir
folderDlg.ShowNewFolderButton <- true
let dlgResult = folderDlg.ShowDialog()
if dlgResult.Equals(DialogResult.OK) then
folderPath.Text <- folderDlg.SelectedPath
else
folderPath.Text <- "Error")
button.Click.AddHandler(openFolderHandler)
let layout = new FlowLayoutPanel(Dock=DockStyle.Fill)
layout.Controls.Add(button)
layout.Controls.Add(folderPath)
let form = new Form()
form.Controls.Add(layout)
form.ShowDialog()
C:\Program Files\dotnet\sdk\6.0.402\FSharp\fsi.runtimeconfig.json
{
"runtimeOptions": {
"tfm": "net6.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.10"
},
{
"name": "Microsoft.WindowsDesktop.App",
"version": "6.0.10"
}
],
"configProperties": {
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false
}
}
}
running using
dotnet fsi test.fsx
also tried it with sta thread attribute
[<STAThread>]
do
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(false)
use form = new MainGuiForm()
Application.Run(form)

I reproduced this using a regular F# project and got the same behavior. To fix it, I had to call AddHandler on the STA thread. So my working code is:
open System
open System.Windows.Forms
let folderPath = new Label()
let button = new Button(Text = "Select Folder")
let ini_dir = #"C:\Users\hayeskev\source\Workspaces"
let openFolderHandler =
EventHandler(fun _ _ ->
let folderDlg = new FolderBrowserDialog()
folderDlg.InitialDirectory <- ini_dir
folderDlg.ShowNewFolderButton <- true
let dlgResult = folderDlg.ShowDialog()
if dlgResult.Equals(DialogResult.OK) then
folderPath.Text <- folderDlg.SelectedPath
else
folderPath.Text <- "Error")
[<STAThread>]
button.Click.AddHandler(openFolderHandler) // IMPORTANT: Must follow <STAThread>
let layout = new FlowLayoutPanel(Dock=DockStyle.Fill)
layout.Controls.Add(button)
layout.Controls.Add(folderPath)
let form = new Form()
form.Controls.Add(layout)
form.ShowDialog() |> ignore
Result looks like:

Related

XUnit/FsUnit framework throwing "Object reference not set to an instance of an objct"

I have written this simple test case for my code
module CustomerTests
open Xunit
open FsUnit
open MyProject.Customer
open MyProject.Customer.Domain
module ``When upgrading customer`` =
let customerVIP = {Id = 1; IsVip = true; Credit = 0.0M}
let customerSTD = {Id = 2; IsVip = false; Credit = 100.0M}
[<Fact>]
let ``should give VIP customer more credit`` () =
let expected = {customerVIP with Credit = customerVIP.Credit + 100.0M }
let actual = upgradeCustomer customerVIP
actual |> should equal expected
Very surprisingly this code fails with error
[xUnit.net 00:00:00.64] CustomerTests+When upgrading customer.should give VIP cstomer more credit [FAIL]
Failed CustomerTests+When upgrading customer.should give VIP cstomer more credit [3 ms]
Error Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
at CustomerTests.When upgrading customer.should give VIP cstomer more credit() in /Users/user/code/fsharp/CustomerProject/CustomerTests.fs:line 12
But line 12 is just a record being created so its not possible for that line to throw an Object reference not set to an instance of object. This is totally puzzling me.
In the dotnet fsi repl I can execute all my method and there is no object reference problem in my function which are being called from my tests here.
As this SO answer explains, XUnit loads the test in a way that skips initialization of those values. One easy fix is to use a class instead of a module:
type ``When upgrading customer``() =
let customerVIP = {Id = 1; isVip = true; Credit = 0.0M}
let customerSTD = {Id = 2; isVip = false; Credit = 100.0M}
[<Fact>]
let ``should give VIP cstomer more credit`` () =
let expected = {customerVIP with Credit = customerVIP.Credit + 100.0M }
let actual = upgradeCustomer customerVIP
actual |> should equal expected
That way, initialization of those values happens as it should.

How to manipulate my dataset when making an input in flexdashboard?

I dont know how to call my dataset and manipulate it
fileInput(inputId = "file",
label = h4("Input File .csv"), fonte
multiple = F,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")
)
In this area I can generate my table from my upload
rv = reactiveValues(data = NULL)
observe({
req(input$file)
inFile = input$file
data2 = read.csv2(inFile$datapath, stringsAsFactors = FALSE)
save(data2, file = "dataread.RData")
rv$data = data2
})
DT::renderDataTable({
req(rv$data)
rv$data
})
But from here i don't know how to call it and handle it

Fail to parse(?) decimals with FSharpValue.MakeRecord ONLY in iOS device with Region Spanish/Colombia

This bug not happened on Android, IOS emulator, osx, linux. Only on iOS device, when it have a region different to US/English.
I using reflection for decode Json values, and exactly in FSharpValue.MakeRecord the data of decimals get mangled.
Repro steps
Create a Single View iOS app and fill it with:
namespace test
open System
open UIKit
open Foundation
open Microsoft.FSharp.Reflection
type DocumentRow = {
doc_id:int32
doc_kind:string
doc_code:string
customer_code:string
from_code:string option
username:string
createdat:DateTime
updatedat:DateTime
dueat:DateTime option
signature:string option
authorized:string option
delivery_order:int32
price:decimal
cost:decimal
tax_value:decimal
discount_value:decimal
sub_total:decimal
total:decimal
status:string
notes:string option
syncdata:string option
version:int32
}
module JSON =
let fromJSON ty (fields:Reflection.PropertyInfo array) (objs:Map<string, obj>) =
//printfn "%A" objs
let values = fields |> Array.map(fun f ->
let name = f.Name.ToLower()
if objs.ContainsKey(name) then
let value = objs.[name]
value
else
null
)
printfn "%A" values
FSharpValue.MakeRecord(ty, values)
[<Register ("AppDelegate")>]
type AppDelegate () =
inherit UIApplicationDelegate ()
override val Window = null with get, set
override this.FinishedLaunching (app, options) =
let t = typedefof<DocumentRow>
let fields = FSharpType.GetRecordFields t
let data = [
"doc_id", 1|> box
"doc_kind", "O"|> box
"doc_code", "ORD-3-1"|> box
"customer_code", "70084254_32"|> box
"from_code", null
"username", "admin"|> box
"createdat", DateTime.Now |> box
"updatedat", DateTime.Now |> box
"dueat", null
"signature", null
"authorized", null
"delivery_order", 0|> box
"price", 700M|> box
"cost", 0M|> box
"tax_value", 0M|> box
"discount_value", 0M|> box
"sub_total", 3500M|> box
"total", 3500M|> box
"status", "Draft"|> box
"notes", null
"syncdata", null
"version", null
]
let ob = Map.ofList data
let r = JSON.fromJSON t fields ob :?> DocumentRow
printfn "Result = %A" r
true
Run on emulator, it print in the output windows:
{doc_id = 1;
doc_kind = "O";
doc_code = "ORD-3-1";
customer_code = "70084254_32";
from_code = None;
username = "admin";
createdat = 28/02/2019 6:05:13 p. m.;
updatedat = 28/02/2019 6:05:13 p. m.;
dueat = None;
signature = None;
authorized = None;
delivery_order = 0;
price = 700M;
cost = 0M;
tax_value = 0M;
discount_value = 0M;
sub_total = 3500M;
total = 3500M;
status = "Draft";
notes = None;
syncdata = None;
version = 0;}
this is correct.
Run on a iOS device. I have use a iPhone 6 se, but is reproducible in many others.
It print:
{doc_id = 1;
doc_kind = "O";
doc_code = "ORD-3-1";
customer_code = "70084254_32";
from_code = None;
username = "admin";
createdat = 28/02/2019 6:04:12 p. m.;
updatedat = 28/02/2019 6:04:12 p. m.;
dueat = None;
signature = None;
authorized = None;
delivery_order = 0;
price = 12912720851596686131200M;
cost = 0M;
tax_value = 0M;
discount_value = 0M;
sub_total = 64563604257983430656000M;
total = 64564290437145643974656M;
status = "Draft";
notes = None;
syncdata = None;
version = 0;}
See how all the decimal values get mangled.
Related information
iOS 12.1.4
Visual Studio Community 2017 for Mac
Mono 5.16.0.221 (2018-06/b63e5378e38) (64-bit)
P.D: Reported in https://github.com/fsharp/fsharp/issues/893

Are options and WithSize etc in XPlot specific to only certain charts?

I've tried Chart.WithSize and displayZoomButtons = true in the FSLab tutorial, but nothing seems to change the output.
Same thing in other projects using XPlot.GoogleCharts directly.
Am I missing something?
Download Plotly 1.4.2 from nuget and replace the dlls in the FSLab packages directory for XPlotly (see Plotting with Xplotly Q). Then you can use Xplotly's controls to zoom in and out, save the chart, etc. For example:
#load #"..\..\FSLAB\packages\FsLab\FsLab.fsx"
open XPlot.Plotly
open XPlot.Plotly.Graph
open XPlot.Plotly.Html
//open XPlot.GoogleCharts
let layout = Layout(title = "Basic Bar Chart")
["giraffes", 20; "orangutans", 14; "monkeys", 23]
|> Chart.Bar
|> Chart.WithLayout layout
|> Chart.WithHeight 400
|> Chart.WithWidth 700
|> Chart.Show
Very barebones charting solution using Plotly (and it works):
open Newtonsoft.Json
let html = """<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv" style="width: 100%; height: 100%;"></div>
<script>
var data = __DATA__;
var layout = __LAYOUT__;
Plotly.newPlot('myDiv', data, layout);
</script>
</body>"""
let (=>) k v = k, (v:>obj)
let doPlot data layout =
let data = JsonConvert.SerializeObject data
let layout = JsonConvert.SerializeObject layout
let path = Path.GetTempPath() + DateTime.Now.Ticks.ToString() + ".html"
File.WriteAllText(path, html.Replace("__DATA__", data).Replace("__LAYOUT__", layout))
System.Diagnostics.Process.Start(path)
let layout =
[ "title" => "Plot"
"xaxis" => dict [
"title" => "Ticks"
"showgrid" => false
"zeroline" => false
]
"yaxis" => dict [
"title" => "Price"
"showline" => false
]
] |> dict
let data = [
dict [ "x" => [1999; 2000; 2001; 2002]
"y" => [16; 5; 11; 9]
]
]
doPlot data layout

CsvFile.InferColumnTypes not available for FSharp.Data 2.2.3?

The following code works when using F#.Data 2.2.2.
let data = CsvFile.Load(fn)
let dt = data.InferColumnTypes(10000, [|""|], CultureInfo.InvariantCulture, "", false, true)
Now it stop working when using F#.Data 2.2.3. I checked the source file on GitHub https://github.com/fsharp/FSharp.Data/blob/7caa9ed507dc0c69abc39ed438acb5af81080abd/src/Csv/CsvInference.fs and the source file is not changed since Oct 22, 2014. Why it suddenly stops working?
The InferColumnTypes method is an extension method, so you can only call it if you open the module where it is defined. The following works for me with the latest build of F# Data:
open FSharp.Data
open FSharp.Data.Runtime.CsvInference // <- This brings InferColumnTypes into the scope!
let fn = "C:\\some\\file.csv"
let data = CsvFile.Load(fn)
let ci = CultureInfo.InvariantCulture
let dt = data.InferColumnTypes(10000, [|""|], ci, "", false, true)

Resources