ãã·ã¢èªã®èšäºã§ã¯ã F#
ãšWPF
䜵çšãããšãããããã¯ã«å°ã泚æãæãããŠããŸãã
仿¥ã¯ã F#
ã©ã€ãã©ãªã®1ã€ã玹ä»ããŸããããã«ããããã®ãããªéçºã倧å¹
ã«ç°¡çŽ åãããŸãã
ãã¢ãšããŠãç¥èããã¹ããããžã¥ãã¢éçºè
ã®ããžã·ã§ã³ãç³è«è
ã«äžããWPF
ãã¹ãã®å²ãåœãŠã®1ã€ãèŠãŠã¿ãŸãããã
ã¿ã¹ã¯èªäœã¯ãã®ããã«èãããŸã
Students.xmlãã¡ã€ã«ã§æäŸãããããŒã¿ã䜿çšããŠã¢ããªã±ãŒã·ã§ã³ãéçºããå¿
èŠããããŸãã
æå®ããããã¡ã€ã«ã«ã¯ãåŠçã«é¢ããæ¬¡ã®æ
å ±ãå«ãŸããŠããŸãïŒå§ãåãå¹Žéœ¢ãæ§å¥ã
ãã¡ããã远å ã®æšå¥šäºé
ãšå®è£
å¶éããããŸãããããããå®å
šã«ã³ããŒããããšã¯ããŸããã å¿
èŠã«å¿ããŠæ¬æã«æ¬æãèšèŒãããŸããå®å
šçã¯ãã¡ãããå
¥æã§ããŸã
æåã«ãVisual StudioïŒãŸãã¯ãã®ä»ã®åªå
IDEïŒã§.NET Frameworkã®ç©ºã®ã³ã³ãœãŒã«ãããžã§ã¯ããäœæããŸãã ãããã°ã³ã³ãœãŒã«ã衚瀺ããããªãå Žåã¯ããããžã§ã¯ãèšå®ã§åºåã®ã¿ã€ãã倿Žããå¿
èŠããããŸãã
ã¡ã€ã³ã¹ãããïŒã¡ã€ã³ããŒã¿åïŒãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã«äŸåããªãããŒã¿åïŒã®æ±ºå®ïŒã䜿çšããŠãåçŽãªã¢ããªã±ãŒã·ã§ã³ã®äœæ¥ãéå§ããŸãã
FïŒ-ïŒãããŸã§ïŒCïŒã«é¡çžäœãæããªãã¿ã€ãã䜿çšããŸã-ã¬ã³ãŒãïŒ Record
ïŒããã³ããŒã¯ããããŠããªã³ïŒ Discriminated Union
ïŒã
type Gender = |Male |Female type Student = {FirstName : string; LastName : string; Age : int; Gender : Gender}
ããããããã«æ»åšãã䟡å€ããããŸãã å²ãåœãŠã匷調ããªãã£ããã1ã€ã®ãã€ã³ãããããŸã-èšé²ã®äžææ§ã§ãã çè«çã«ã¯ããªã¹ããããŠãããã¹ãŠã®ãã£ãŒã«ãã«äžèŽããåŠçãååšããå ŽåããããŸãã
ãããããµã³ãã«ã®xmlãã¡ã€ã«ãèŠããš
<?xml version="1.0" encoding="utf-8"?> <Students> <Student Id="0"> <FirstName>Robert</FirstName> <Last>Jarman</Last> <Age>21</Age> <Gender>0</Gender> </Student> ... </Students>
次ã«ãIDã屿§ãšããŠæå®ãããŠãããããå¥ã®ãã£ãŒã«ãã远å ããã ãã§ãã
type Student = {ID:int; FirstName : string; LastName : string; Age : int; Gender : Gender; }
ãã®ãããªã¢ããŠã³ã¹ã«ã¯1ã€ã®éå€§ãªæ¬ ç¹ããããŸã-IDã®ååšã¯ã¬ã³ãŒãã®äžææ§ãä¿èšŒããŸããã
ã€ãŸããçè«çã«ã¯ãåãèå¥åãæã€ã¬ã³ãŒããããã€ã§ã远å ã§ããŸãã
FïŒã¯ãåã
ã®ãã£ãŒã«ããžã®ã¢ã¯ã»ã¹ä¿®é£Ÿåã®å²ãåœãŠãèš±å¯ããŸããããåã«å¯ŸããŠè¡ãããšãèš±å¯ããŸãã
èªåèªèº«ãä¿è·ãããå Žåã¯ã Student
ã¿ã€ããprivateã«ããããšããæç€ºçãªæç€ºã眮ãããšãã§ããŸãã
type Student = private {ID:int; FirstName : string; LastName : string; Age : int; Gender : Gender; }
ãªããžã§ã¯ããäœæããããã®è£å©é¢æ°ãäœæããŸã
let create firstname lastname age gender = let id = getNextId() { ID = id FirstName = firstname ... }
æå¹ãªãã£ãŒã«ãå€ãå¶éããããã®èŠä»¶ãèæ
®ããŠãã ããã
åãå§ãæ§å¥ã®ãã£ãŒã«ãã¯å¿
é ã§ãã
幎霢ãè² ã«ããããšã¯ã§ãããç¯å²ã¯[16ã100]ã§ãªããã°ãªããŸããã
è«ççãªè³ªåãããã«çºçããŸã-å
¥åããããã©ã¡ãŒã¿ãŒã®æ£ç¢ºæ§ã確èªããå Žæ
Student
ã¿ã€ããä¿è·ãããŠããå Žåã以äžãè¿ãtryCreate
颿°ãäœæã§ããŸãã
None
/ Error<string>
ãŸãã¯Some<Student>
/ Ok<Student>
ãã§ãã¯ã®çµæã«å¿ããŠã
Result
ãåŠçãç»é²ãã詊ã¿ã倱æããããšãç¥ãããã ãã§ãªããåé¡ãçºçããå Žæãå
·äœçã«ç€ºãããã«å¿
èŠãªå Žåã«äœ¿çšããResult
䟿å©ã§ãã
å®è£
ãããããããããããã«ããã®é¢æ°ã®ã³ãŒããèšäºã«è¿œå ããŸããã
äžèšã®ã¢ãããŒããèŠããŠãããŸãããããããŒã¿å¶åŸ¡ã®è²¬ä»»ããã¥ãŒãšã¢ãã«ã®éã®ãªã³ã¯ã«å²ãåœãŠãŸãã
ãã¬ãŒã³ããŒã·ã§ã³ãæ
åœããéšåã«ç§»ãåã«ãã¢ããªã±ãŒã·ã§ã³ã®äž»ãªæ©èœã®ãããã¯ãéããŸã
- æ°ããã¢ã€ãã ãäœæããŠãªã¹ãã«è¿œå ããŸãã
- ãªã¹ãå
ã®ãšã³ããªãç·šéããŸãã
- ãªã¹ããã1ã€ä»¥äžã®ãšã³ããªãåé€ããŸãã
ãã§ã«äœæãããã£ãŠããã®ã§ãããã«ããã€ãã®æ©èœã远å ããŸã
// ; let add xs student = student :: xs // let remove students = List.filter (fun student -> Seq.contains student students |> not) // ; let editFirstName firstname student = { student with FirstName = firstname } let editLastName lastname student = { student with LastName = lastname } let editAge age student = { student with Age = age} let editGender gender student = { student with Gender = gender } let editId student id = {student with ID = id} let edit student = List.map (fun st -> if st.ID = student.ID then student else st)
次ã®ã¹ãããã«é²ã¿ãŸãã
XMLã§ã®èªã¿åããšæžã蟌ã¿
FïŒã§ããŒã¿ãåŠçããã«ã¯ãã¿ã€ããããã€ããŒãšåŒã°ããåªããã¡ã«ããºã ããããŸãïŒããŒã¿ãããã€ããŒïŒforïŒãšãåŒã°ããŸãããå°æ¥ã®æ®åçãé«ããããæåã®ãªãã·ã§ã³ã䜿çšããŸãïŒã
ç¹å®ã®åœ¢åŒã§ã®äŸ¿å©ãªäœæ¥ã®ããã®å€ãã®å®è£
ããããŸãã
ãã®ããŒãã§ã¯ã FSharp.Data
ã®ã¿ãå¿
èŠã§ãïŒ FSharp.Data
ã©ã€ãã©ãªããïŒã
ãã®ããã±ãŒãžããããžã§ã¯ãã«è¿œå ããŸã ã
Install-Package FSharp.Data
XmlProvider
ã¿ã€ãã¯XmlProvider
å
ã§äœ¿çšãããããããŸã ãžã®ãªã³ã¯ãå¿
èŠã§ãã
System.Xml.Linq
open FSharp.Data let [<Literal>] Sample = """ <Students> <Student Id="0"> <FirstName>Robert</FirstName> <Last>Jarman</Last> <Age>21</Age> <Gender>0</Gender> </Student> <Student Id="2"> <FirstName>Leona</FirstName> <Last>Menders</Last> <Age>20</Age> <Gender>1</Gender> </Student> </Students>""" type Students = XmlProvider<Sample>
䜿çšãããŠãããµã³ãã«ã§ã¯ã Id
ã¯ãã¡ã€ã«ã®{0, 1}
ãªã{0, 1}
{0, 2}
ãšããŠç€ºãããŠãããããåã¯bool
ã§ã¯ãªãint
ãšããŠå®çŸ©ãããŠããŸãã
äžè¬ã«ãããŒã¿ãœãŒã¹åœ¢åŒã®åãã¢ããªã±ãŒã·ã§ã³ã§åãå
¥ããããåã«å€æããã«ã¯ãè€éãªããžãã¯ãå¿
èŠã«ãªãå ŽåããããŸãã ãã ãããããã®ããŒã¿æ§é ã¯ã»ãšãã©åãã§ããããã bool
åã®bool
ãšã©ãã«ä»ããŠããªã³ã®å¯Ÿå¿ã確ç«ããããã«è¿œå ãã颿°ã¯1ã€ã ãã§ãã
let fromBool = function | true -> Female | false -> Male
èšé²function | true -> Female | false -> Male
function | true -> Female | false -> Male
function | true -> Female | false -> Male
ã¯æ¬¡ãšãŸã£ããåãæå³
match x with
ããçã圢åŒã®ã¿ã§ãã ãã®åœ¢åŒã¯ããµã³ãã«ãšç°¡åã«æ¯èŒãããšãã«äŸ¿å©ã§ãã
次ã®éšåãåé¡ãåŒãèµ·ãããŸãã-ãã¹ãŠãç°¡åã§æç¢ºã§ãã
let toCoreStudent (student:Students.Student) = student.Gender |> fromBool |> create student.Id student.FirstName student.Last student.Age let readFromFile (path : string) = Students.Load path |> fun x -> x.Students |> Seq.map toCoreStudent
ããããããã ãã§ã¯ãããŸããããŠãŒã¶ãŒããªã¹ãã«ããŒã¿ã远å ã§ããããšãèæ
®ããå¿
èŠããããŸãããããã£ãŠããã¡ã€ã«ããããŒã¿ãæœåºã§ããã ãã§ãªããæžã蟌ã¿ãã§ããå¿
èŠããããŸãã
倿ãç°ãªãæ¹åã«é²ãããšãé€ããŠãã³ãŒãã¯ãŸã£ããåãã§ãã
let toBool = function | Male -> false | Female -> true let fromCoreStudent (student:Student) = Students.Student(student.ID, student.FirstName, student.LastName, student.Age, toBool student.Gender) let toXmlStudents data = data |> Seq.map fromCoreStudent |> Seq.toArray |> Students.Students let writeToFile (path : string) data = let students = data |> toXmlStudents students.XElement.Save path
ãããŸã§æ€èšãããŠãããã¹ãŠãWPFã«äŸåããããã®éšåã«å€æŽïŒããšãã°ãå¥ã®çš®é¡ã®ã€ã³ã¿ãŒãã§ã€ã¹ãžã®ïŒãçããããšã¯ãªãããšã匷調ããŸãã
éåžžã®ç¶æ³ã§ã¯ããã®ãããªã³ãŒããã¯ã©ã¹ã©ã€ãã©ãªã«è»¢éããããšã¯çã«ããªã£ãŠããŸãããç¹å®ã®åœ¢åŒïŒ.xmlïŒã«é¢é£ããªãæ©èœéšåãå°ãããããããå®å
šã«ç¬ç«ããã¢ãžã¥ãŒã«ãäœæããããã«ç¬ç«ãããããžã§ã¯ãã¯äœ¿çšãããŸããã
ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹
ç§ãã¡ã®ç®æšã¯ããããžã§ã¯ããå®å
šã«FïŒã§FsXAML
ã§ãã FsXAML
ãã€ã³ã¿ãŒãã§ã€ã¹ã®åé¡ã«ã€ããŠã¯ã FsXAML
ã®å©ããFsXAML
ãŸãã
CïŒã§ããŒããæžãããšã«ã¯äœã®åé¡ããããŸããããããã»ã©é¢çœããªãããšã«åæããŸãã
FsXAML
ã¯ã FsXAML
ãã¡ã€ã«ã䟿å©ã«äœ¿çšã§ããããã«ããåãããã€ããŒã§ãã NuGetã䜿çšããŠãããžã§ã¯ãã«è¿œå ã§ããŸãã
Install-Package FsXaml.Wpf
XamlReader
ãè¶
ããå©ç¹ã¯ã StackOverFlowã®å¥ã®åçïŒè±èªïŒã«èšèŒãããŠããŸãã
ãã®æ¬ ç¹ã®1ã€ã¯ããã¥ã¡ã³ãããªãããšã§ãããã®ãããã³ã³ããŒã¿ãŒãååšããããšããç¬èªã®ãã®ãäœæããããã®äŸ¿å©ãªã©ãããŒãããããšãããã«ç¥ãããšã¯ã§ããŸããã
ããã§ã¯ãå¹Žéœ¢ãšæ€èšŒãšã©ãŒãæ£ãã衚瀺ããããã®ã³ã³ããŒã¿ãŒãå¿
èŠã§ãã
type AgeToStringConverter() = inherit ConverterBase (fun value _ _ _ -> match value with | :? int -> value |> unbox |> AgeToStringConverter.ageToStr |> box | _ -> null ) static member ageToStr age = ...
ConverterBase
ã¯ã ConverterBase
ãäœæããããã®FsXAML
ã®åºæ¬ã¯ã©ã¹ã§ãã
ã¢ããªã±ãŒã·ã§ã³ã®åºæ¬çãªèŠä»¶ãç¹°ãè¿ããŸãããããä»åºŠã¯å€èгã®èгç¹ããããããèŠãŠã¿ãŸãããã
- æ¢åã®ã¢ã€ãã ã®ãªã¹ãã衚瀺ããŸãã
- æ°ããã¢ã€ãã ãäœæããŠãªã¹ãã«è¿œå ããŸãã
- ãªã¹ãå
ã®ãšã³ããªãç·šéããŸãã
- ãªã¹ããã1ã€ä»¥äžã®ãšã³ããªãåé€ããŸãã
ã¢ã€ãã ã®ãªã¹ãã衚瀺ããã«ã¯ã ListView
ã䜿çšãããšäŸ¿å©ã§ãã
ã¡ã€ã³ãŠã£ã³ããŠã®çåŸã®ããŒãã«ã«å ããŠãã³ã³ãããŒã«ãã¿ã³ããããŸãã
ãã¹ãŠãäžç·ã«ãªã£ãŠãã¢ããªã±ãŒã·ã§ã³ã®ã¡ã€ã³ãããŒãžãã衚ãUserControl
ã圢æããŸãã

ä»ã®ããŒãžã¯äºèŠãããªããããããã²ãŒã·ã§ã³ã®äœ¿çšã¯åé·ãªãœãªã¥ãŒã·ã§ã³ã®ããã«æãããããããŸããã
ããããç°¡åãªäŸã瀺ãããšã¯å®å
šã«é©ããŠããŸãã
åŠçæ
å ±ã®ç·šéãšè¿œå ã¯ããã€ã¢ãã°ããã¯ã¹ã§è¡ãããŸãã
xaml
ãã¡ã€ã«ãäœæãããããããã®ã¿ã€ããäœæããå¿
èŠããããŸã
type App = XAML<"App.xaml"> type MainWin = XAML<"MainWindow.xaml"> type StudentsControl = XAML<"StudentsControl.xaml"> type StudentDialogBase = XAML<"StudentDialog.xaml"> type StudentDialog() = inherit StudentDialogBase() override this.CloseClick (_sender, _e) = this.Close()
3çªç®ã®ããŒãžã§ã³ãããã€ãã³ãåŠçã®åºæ¬çãªãµããŒããFsXAML
远å ããFsXAML
ã äžèšã®äŸã§ã¯ã確èªãã¿ã³ãã¯ãªãã¯ãããšãŠã£ã³ããŠãéããŸãã
ãžã£ã©ã«ããŒã³
ã¢ãã«ããã¥ãŒã«æ¥ç¶ããã«ã¯ãéåžžã«ææãªæ°ããGjallarhorn.Bindableã©ã€ãã©ãªã䜿çšããŸã
Install-Package Gjallarhorn.Bindable.Wpf -Version 1.0.0-beta5
ææ°ã®å©çšå¯èœãªãªãªãŒã¹ ããŸã ããŒã¿çã§ãã
äž»ãªæŠå¿µã¯ã Elm
ã¢ãŒããã¯ãã£ã®äžçš®ã®é
眮ã§ãããã¡ã€ã³ã®Gjallarhornã©ã€ãã©ãªã®äžã«ããwpf
詳现ãèæ
®ããŠwpf
ã wpf
ããŒãžã§ã³ã«å ããŠã XamarinForms
ããã±ãŒãžããããŸã ã
ã¢ããªã±ãŒã·ã§ã³ãäœæããã«ã¯ã Framework
ã¢ãžã¥ãŒã«ã®application
颿°ã䜿çšãããšäŸ¿å©ã§ãã
Framework.application model update appComponent nav
åã
ã®ããŒãïŒã¢ãã«ããããæŽæ°ããããã®æ©èœããã¥ãŒããã³ããã²ãŒã¿ãŒãšéä¿¡ããããã®ã³ã³ããŒãã³ãïŒãæ¥ç¶ããŸã
model
ã¢ããªã±ãŒã·ã§ã³ã¢ãã«ïŒãããã¬ãã«ã¢ãã«ïŒ-ãããªãäœæ¥ãæ®ãã¡ã€ã³ããŒã¿ãupdate:('message -> 'model -> 'model)
åä¿¡ããã¡ãã»ãŒãžïŒ message
ïŒã«å¿ããŠã¢ãã«ïŒ model
ïŒãåŠçããæ°ããå€ãè¿ã颿°ã
ã¿ã¹ã¯ã«åºã¥ããŠãã¢ããªã±ãŒã·ã§ã³ã¯ãªã¹ãããã¢ã€ãã ã远å ãç·šéãåé€ã§ããã¯ãã§ãã
ã¢ã¯ã·ã§ã³ããšã«ãããŒã¯ã¢ããããããŠããªã³ã®ååä»ãããªã¢ã³ãã®åœ¢åŒã§è¡šç€ºãããåå¥ã®ã¡ãã»ãŒãžãéå§ãããšäŸ¿å©ã§ãã
type AppMessages = |Add of Student |Edit of Student |Remove of Student seq |Save
æ¢ã«ãªã¹ããããŠããæ©èœã«ããã¡ã€ã«ãäžæžãããå¥ã®æ©èœã远å ãããŸããã
ãªã¹ãã«æ°ãããšã³ããªã远å ãããšãã¯ãäžæã®èå¥åã®å¢åïŒ ID
ïŒãèæ
®ããå¿
èŠããããŸãã
ãããè¡ãã«ã¯ãè£å©é¢æ°getId
èšè¿°ããŠããªã¹ãå
ã®æå€§æ°ã®æ¬¡ã®ã·ãªã¢ã«çªå·ãè¿ããŸãã
æŽæ°æ©èœã«ã¯ä»ã®èœãšã穎ã¯ãªãã®ã§ãæçµçã«ã¯æ¬¡ã®åœ¢åŒãåããŸã
let update message model = match message with |Add student -> model |> getId |> editId student |> add model |Edit newValue -> model |> edit newValue |Remove students -> model |> remove students |Save -> XmlWorker.writeToFile path model model
ããã²ãŒã·ã§ã³ç¶æ
ãæ±ºå®ããããã«ãã©ãã«ä»ããŠããªã³ã䜿çšããŸã
type CollectionNav = | ViewStudents | AddStudent | EditStudent of Student
ããã§ããã²ãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ã®æºåãæŽããããã²ãŒã·ã§ã³ã¡ãã»ãŒãžãšã¢ããªã±ãŒã·ã§ã³ã®ã¡ãã»ãŒãžã®é¢é£ä»ãã«é²ãããšãã§ããŸãã
ã¢ãã«ã®æŽæ°ãšåæ§ã«ãç¶æ
ã®æŽæ°ãupdate
颿°ã§å®è£
ãããŸã
let updateNavigation (_ : ApplicationCore<Student list,_,_>) request : UIFactory<Student list,_,_> = match request with |ViewStudents -> Navigation.Page.fromComponent StudentsControl id appComponent id |AddStudent -> Navigation.Page.dialog StudentDialog (fun _ -> defaultStudent) studentComponent Add |EditStudent x -> Navigation.Page.dialog StudentDialog (fun _ -> x) studentComponent Edit
ã©ã€ãã©ãªã§æäŸããã2ã€ã®æ©èœãããã§äœ¿çšãããŸãã
Navigation.Page.fromComponent
fromComponent : (makeElement : unit -> 'UIElement) -> (modelMapper : 'Model -> 'Submodel) -> (comp : IComponent<'Submodel, 'Nav, 'Submsg>) -> (msgMapper : 'Submsg -> 'Message) -> UIFactory<_,_,_>
ãããŠ
Navigation.Page.dialog
dialog : (makeElement : unit -> 'Win) -> (modelMapper : 'Model -> 'Submodel) -> (comp : IComponent<'Submodel, 'Nav, 'Submsg>) -> (msgMapper : 'Submsg -> 'Message) = -> UIFactory<_,_,_>
ãããã¯äºãã«éåžžã«é¡äŒŒããŠããããããããã®èª¬æãåå¥ã«ç€ºããŸããã
æåã®åŒæ°ã¯é¢æ°ïŒ makeElement
ïŒã§ããã衚瀺ãããã¢ã€ãã ïŒãŠã£ã³ããŠïŒ Window
ïŒãŸãã¯ã³ã³ãããŒã«ïŒ UIElement
ïŒïŒãèšå®ããŸãã
ãã¶ã€ãã¯æ¬è³ªçã«åãæ©èœã§ãããããã»ãšãã©ã®å Žåãç®çã®åãæž¡ãã ãã§ååã§ãã
2çªç®ã®åŒæ°ïŒ modelMapper
ïŒã¯ãæäžäœã¢ãã«ããäžäœã¢ãã«ãžã®å€æé¢æ°ã§ãã
ç·šéã®å Žåã¯ãèå³ã®ãããªããžã§ã¯ãïŒ Student
ïŒããã©ã¡ãŒã¿ãŒãšããŠååŸãããããåçŽã«æž¡ãããšãã§ããŸãã 远å ããã«ã¯ãããã©ã«ãå€ãæž¡ããŸãã
ViewStudents
ã®åºåºç¶æ
ã®ViewStudents
ã¡ã€ã³ã³ã³ããŒãã³ãã®ã¢ãã«ã¯ã¢ããªã±ãŒã·ã§ã³ã¢ãã«ã«ãªãããã倿Žããå¿
èŠã¯ãªããé©çšã§ããŸãã
æšæºFïŒ id
颿°
次ã«ã³ã³ããŒãã³ãïŒ comp
ïŒãæ¥ãŸããããã«ã¯ãã€ã³ã¿ãŒãã§ãŒã¹ãšå¯Ÿè©±ããããã«å¿
èŠãªãã¹ãŠã®ãã€ã³ãã£ã³ã°ãå«ãŸããŠããŸãã
appComponent
ã³ã³ããŒãã³ãã®ã¿ã€ãã¯IComponent<Student list, CollectionNav, AppMessages>
ã§ã studentComponent
ã¿ã€ãã¯IComponent<Student, CollectionNav, Student>
ã§ãã
æåŸã®åŒæ°ïŒ msgMapper
ïŒã¯ãã¡ãã»ãŒãžã®é倿颿°ã§ãã studentComponent
ã³ã³ããŒãã³ãã¯åŠçãè¿ããããããã§ã¯æ£ããã¡ãã»ãŒãžã®ã¿ãæž¡ãããšãã§ããŸãã
æåŸã®éšåãã€ãŸãã³ã³ããŒãã³ãèªäœã®æ€æ»ã«é²ãããšãã§ããŸãã
Gjallarhorn.Bindable.WPF
ããŒã¿ãã€ã³ãã£ã³ã°ã®å Žåã¯ã Bind
ã¢ãžã¥ãŒã«ã責任ãè² ãããã®ã¢ãžã¥ãŒã«ã¯ããã€ãã®ãµãã¢ãžã¥ãŒã«ã«åå²ãããŸãã
ã¡ã€ã³ïŒã«ãŒãïŒAPIïŒæåã®ããŒãžã§ã³ä»¥éã«è¿œå ãããïŒã¯ããå®å
šã§ããã æã«ã¯æ±ãã«ãããªãã2ã€ç®ã¯æç€ºçã§ã ïŒ Explicit
ã¢ãžã¥ãŒã«ã®æ©èœïŒã
ããã§ã¯ãäž¡æ¹ã®ã¢ãããŒãã瀺ãããã«ã Explicit
䜿çšããŠçåŸæ
å ±ãšã³ã¢ã®Implicit
ãååŸããŸãã
äž¡æ¹ã®ã³ã³ããŒãã³ãã¯äºãã«ç¬ç«ããŠããããšã«æ³šæããŠãã ããã
äž»ãªappComponent
ããå§ããŸãããappComponent
æ°ããAPIã䜿çšããã«ã¯ãèšå®ãããŠãããã¹ãŠã®ããããã£ãšã³ãã³ããå«ãå¿
èŠãããäžéã¿ã€ãã宣èšããå¿
èŠããããŸãã
type AppViewModel = { Students : Student list Add : VmCmd<CollectionNav> Edit : VmCmd<CollectionNav> Remove : VmCmd<AppMessages> RemoveAll : VmCmd<AppMessages> Save : VmCmd<AppMessages> }
ã³ãã³ãã¯ãåã«ã¡ãã»ãŒãžãä¿åããç¹å¥ãªã¿ã€ãã®VmCmd
ã䜿çšããŠæå®ãããŸãã
ããã¯ãããŒã ã®ååãã¯ã©ãŒã¿ïŒåŒçšãšåŒã°ããããšãããïŒã䜿çšããŠååŸããããšããäºå®ã«ã€ãªãããŸãã
ãããã£ãŠã誀åã«ããååã®äžäžèŽã«ãããšã©ãŒã®ãªã¹ã¯ãæžããã®ã«åœ¹ç«ã€ãããžãã¯ã©ã€ã³ããåé¿ããŸãã
ã³ã³ããŒãã³ããèšèšããåã«ã VM
ã¿ã€ãã®ããŒã¹ã€ã³ã¹ã¿ã³ã¹ïŒããã©ã«ãå€ïŒãäœæããå¿
èŠãããVM
let appvd = { Students = [] Edit = Vm.cmd (CollectionNav.EditStudent defaultStudent) Add = Vm.cmd CollectionNav.AddStudent Remove = Vm.cmd (AppMessages.Remove [defaultStudent]) RemoveAll = Vm.cmd (AppMessages.Remove [defaultStudent]) Save = Vm.cmd AppMessages.Save }
ãªã¹ãã空ã®å Žåãæåã«ããã€ãã®ãã¿ã³ã®ããã¯ãèæ
®ããå¿
èŠããããããèŠçŽ ã®ååšã«é¢ããæ
å ±ãå«ã颿°ãå®çŸ©ããŸãã
let hasStudents = List.isEmpty >> not
ïŒååãšããŠã ListView
ãã³ãã¬ãŒãã倿Žããããã«è¡ãããããã«ãããŒã¿ããªã¬ãŒïŒ DataTrigger
ïŒã䜿çšã§ããŸãïŒã
次ã«ã以äžã«ç€ºãããã«ããã¹ãŠã®ãã€ã³ãã£ã³ã°ã®ãªã¹ããComponent.create
颿°ã«æž¡ããŠã³ã³ããŒãã³ããäœæããŸã
let appComponent = let hasStudents = List.isEmpty >> not Component.create<Student list, CollectionNav, AppMessages> [ <@ appvd.Students @> |> Bind.oneWay id <@ appvd.Edit @> |> Bind.cmdParam EditStudent |> Bind.toNav <@ appvd.Add @> |> Bind.cmd |> Bind.toNav <@ appvd.Save @> |> Bind.cmd <@ appvd.Remove @> |> Bind.cmdParamIf hasStudents (Seq.singleton >> Remove) <@ appvd.RemoveAll @> |> Bind.cmdParamIf hasStudents (Seq.cast >> Remove) ]
Bind.oneWay
åæ¹åãã€ã³ãã£ã³ã°ãäœæããããã«èšèšãããŠããŸãã
Bind.cmd
ã Bind.cmdParam
ãããã³Bind.cmdParamIf
ããããã³ãã³ãããã©ã¡ãŒã¿ãŒä»ãã³ãã³ããããã³å®è¡å¯èœæ§ã®è¿œå ãã§ãã¯ä»ãã³ãã³ããäœæããŸãã
ããã€ãã®ç¹ã«æ³šæããŸããã-2ã€ã®å¥åã®ã¡ãã»ãŒãžãéå§ããªãããã«ïŒ1ã€ãŸãã¯è€æ°ã®èŠçŽ ãåé€ããããïŒãéä¿¡ããããªããžã§ã¯ãã¯åäœé·ã®ã·ãŒã±ã³ã¹ã圢æããŸãã
<@ appvd.Remove @> |> Bind.cmdParamIf hasStudents (Seq.singleton >> Remove)
æ®å¿µãªããSelectedItems
ã¯äžè¬åãããã³ã¬ã¯ã·ã§ã³ã§ã¯ãªããããããã§ã¯è¿œå ã®å€æãé©çšããå¿
èŠããããŸã
<@ appvd.RemoveAll @> |> Bind.cmdParamIf hasStudents (Seq.cast >> Remove)
ããã²ãŒã·ã§ã³ã¡ãã»ãŒãžã®éä¿¡ã¯ã Bind.toNav
ã䜿çšããŠè¡ãããŸãã
ããã§ã¯ã代ããã«ãã³ã³ããŒãã³ãããã¯ãªãŒã³ãã®ãŸãŸã«ããå¥ã®ã¢ãããŒãã䜿çšã§ããããšã«æ³šæããŠãã ããïŒããã²ãŒã·ã§ã³ã®å¯äœçšã¯ãããŸããïŒã
ãã®æ¬è³ªã¯ã update
æ©èœã®ãã¹ãŠã®å€æŽã ãã§ãªãã倿ŽèŠæ±èªäœãå®è¡ããããšã§ãã
ç§ãã¡ã®å Žåããããã¯åŠçã«é¢ããæ
å ±ã远å ããã³ç·šéããããã®ãªã¯ãšã¹ãã§ãã
ã€ãŸãã Bind.toNav
åŒã³åºããåé€ããããã³ã³ããŒãã³ãã®Bind.toNav
ãä»ããŠçŽæ¥Bind.toNav
ããå¿
èŠããããŸãïŒæç€ºçãªAPIã䜿çšããå ŽåïŒã
ãã®ã¡ãœãããäŸã§èŠãŠã¿ãŸãããã
å¿
èŠãªèŠæ±ãåæ ããAddRequest
ããã³EditRequest
ãAppMessages
ã¿ã€ãã«è¿œå ããŸãã
type AppMessages = |Add of Student |Edit of Student |Remove of Student seq |Save |AddRequest |EditRequest of Student
次ã«ã次ã®éšåãã³ã³ããŒãã³ãã®è¿œå ãšç·šéãæ
åœããããã«ã AppViewModel
ã®ã¿ã€ããæžãæããŸã
<@ appvd.Edit @> |> Bind.cmdParam EditRequest <@ appvd.Add @> |> Bind.cmd
次ã«ã update
æ©èœã®åã«ããã£ã¹ãããã£ãŒãäœæããŸã
let disp = Dispatcher<CollectionNav>()
ã¡ãã»ãŒãžãåä¿¡ãããšãã«ãªã¯ãšã¹ããéä¿¡ãã颿°ã§äœ¿çšããŸã
|AddRequest -> AddStudent |> disp.Dispatch model |EditRequest st -> EditStudent st |> disp.Dispatch model
ãã£ã¹ãããã£ãŒïŒãã®å Žåãããã²ãŒã·ã§ã³ã®ç®¡çãæ
åœïŒãæ¥ç¶ããã«ã¯ã Framework.withNavigation
颿°ã䜿çšããŸã
let app = Framework.application model update appComponent nav.Navigate |> Framework.withNavigation disp
ã¯ãããã®å Žåãã³ãŒãã¯ããå€ãã®ã¹ããŒã¹ãå æããŸãããã³ã³ããŒãã³ãã¯ãã¯ãªãŒã³ãã§ããããšãããããŸãã
ããã§ã¯ã studentComponent
ã«æž¡ããŸãããããã§ã¯å®å
šã«ã¯æž¡ããŸãããäž»èŠéšåã®ã¿ãæ®ããŸã
type StudentUpdate = |FirstName of string |LastName of string |Age of int |Gender of Gender let studentBind _ source model = let mstudent = model |> Signal.get |> Mutable.create [Female; Male] |> Signal.constant |> Bind.Explicit.oneWay source "Genders" let first = mstudent |> Signal.map (fun student -> student.FirstName) |> Bind.Explicit.twoWayValidated source "FirstName" (Validators.notNullOrWhitespace >> Validators.noSpaces) |> Observable.toMessage FirstName // let upd msg = match msg with | FirstName name -> Mutable.step (editFirstName name) mstudent | LastName name -> Mutable.step (editLastName name) mstudent | Age age -> Mutable.step (editAge age) mstudent | Gender gender -> Mutable.step (editGender gender) mstudent [last; age; gender] |> List.fold Observable.merge first |> Observable.subscribe upd |> source.AddDisposable [ Bind.Explicit.createCommandChecked "SaveCommand" source.Valid source |> Observable.map(fun _ -> mstudent.Value) ] let studentComponent : IComponent<_,CollectionNav,_> = Component.fromExplicit studentBind
ããã§ã¯ãããŒã¿ããªã³ã¯ãããšãã«ã Gjallarhorn
ã©ã€ãã©ãªã®æ©èœã䜿çšããŠæ€èšŒãå®è¡ãããŸãïŒæ€èšŒïŒã
ãã©ã¡ãŒã¿ãŒã®æå¹æ§ã®ç¶æ
ã远跡ããã«ã¯ã source.Valid
ä¿¡å·ãsource.Valid
ãŸãã
Validators
ã¢ãžã¥ãŒã«ã«ã¯ãç°¡åã«çžäºã«çµã¿åãããããšãã§ããããã€ãã®ãã«ããŒé¢æ°ãå«ãŸããŠããŸãã
ããšãã°ãååãã£ãŒã«ãã«ç©ºã®æååã空çœãå«ããªãããã«ããŸãã
ãããè¡ãã«ã¯ãäž¡æ¹ã®æ©èœã«äºææ§ããã
Validators.notNullOrWhitespace >> Validators.noSpaces
æšæºæ©èœã§ã¯äžååãªå Žåã¯ããã€ã§ãç¬èªã®æ©èœãèšè¿°ããŠãã§ãã¯ãã§ãŒã³ã«è¿œå ã§ããŸãã
ãããè¡ãæ¹æ³ãããã³Gjallarhorn
ããŒã¿æ€èšŒã«é¢ãããã®ä»ã®è©³çްã«ã€ããŠã¯ã ããã¥ã¡ã³ããåç
§ããŠãã ããã
Validators.noValidation
颿°ã¯ããã§ãã¯ãäžèŠãªå Žåã«åœ¹ç«ã¡ãŸãã
ãã®çµæãçåŸã远å ããããã®ãã€ã¢ãã°ããã¯ã¹ã¯æ¬¡ã®ããã«ãªããŸãã

泚ç®ã®ã¢ãããŒã
mstudent |> Signal.map (fun student -> student.FirstName) |> Bind.Explicit.twoWayValidated source "FirstName" (Validators.notNullOrWhitespace >> Validators.noSpaces)
ãããã誰ããåé·ãããããã§ãã ãããã解決çããããŸãBind.Explicit.memberToFromView
颿°ã䜿çšããŠãèšé²ãå°ãçãããããšãã§ããŸãã
, :
, . F# ;)
.
F# , ( ). F# Slack ( F# Software Foundation)
Reed Copsey ( F#), API .
, , F# .
ããããïŒ