使用 Elmish.wpf/F#,如何在 WPF 中将字符串选项显示为字符串或空值,而不是 "Some(string)"?

With Elmish.wpf/F#, how to display in WPF a string option as the string or null, not "Some(string)"?

我是 F# 的新手。在 WPF 中,我在 Datagrid 中使用 DisplayMemberBinding 作为:

<DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <local:AppointmentListView ItemsSource="{Binding Columns[0].AppointmentKeys}" Height="140" Background="Bisque">
                                    <ListView.View>
                                        <GridView>
                                            <GridViewColumn Header="First"     DisplayMemberBinding="{Binding FirstName}" Width="100"/>
                                            <GridViewColumn Header="Last"      DisplayMemberBinding="{Binding LastName}"  Width="120"/>
                                            <GridViewColumn Header="BirthDate" DisplayMemberBinding="{Binding BirthDate, StringFormat=d}" Width="100"/>
                                        </GridView>
                                    </ListView.View>
                                </local:AppointmentListView>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>

(完整的)后备 F# 模块(在 Elmish.wpf 中)是:

module MyDataGrid.DataGrid

open Elmish
open Elmish.WPF
open System

type Visit = 
    {   ServiceTime: DateTime option
        DoNotSee: Boolean option
        ChartNumber: int option
        LastName: string option
        FirstName: string option
        Mi: string option
        BirthDate: DateTime option
        PostingTime: DateTime option 
        AppointmentTime: DateTime option }

type Cell = 
  {RowNumber: int
   ColumnNumber: int
   AppointmentKeys: Visit list
   ColumnTime: TimeSpan
   AppointmentCount: int
   AppointmentTime: DateTime option  // all lines in the cell have the same appointment time.     
  }

let SetCell (rowNumber: int, columnNumber: int) =
    let AppointmentsPerCell = 4
    {RowNumber = rowNumber
     ColumnNumber = columnNumber
     AppointmentKeys = [for x in 1 .. AppointmentsPerCell -> 
                           {
                             ServiceTime = Some System.DateTime.Now 
                             DoNotSee = Some false 
                             ChartNumber = Some 8812 
                             LastName= Some ("LastName" + string x)
                             FirstName= Some ("FirstName" + string x)
                             Mi = Some "J" 
                             BirthDate = Some(DateTime(2020,09,14))
                             PostingTime = Some DateTime.Now
                             AppointmentTime = Some DateTime.Now
                         }]      
     ColumnTime = System.TimeSpan.FromMinutes(float(columnNumber * 15))
     AppointmentCount = 4
     AppointmentTime = Some(DateTime.Now)
     }

type Row =
  {RowTime: string
   Columns: Cell list}

let SetRow (rowNumber: int, startTime: System.TimeSpan)= 
    let columnCount = 4
    let hr = System.TimeSpan.FromHours(1.0)
    let rowTime = startTime + System.TimeSpan.FromTicks(hr.Ticks * int64(rowNumber))
    { RowTime = rowTime.ToString("h':00'")
      Columns = [for columnNumber in 1 .. columnCount -> SetCell(rowNumber, columnNumber) ]
    }

type Model =
  { AppointmentDate: DateTime
    Rows: Row list
    SelectedRow: Row option}

type Msg =
  | SetAppointmentDate of DateTime
  | SetSelectedRow of Row option

let init =
      let rowCount = 9
      let startTime = TimeSpan.FromHours(float(8))
      { AppointmentDate = DateTime.Now 
        Rows = [for rowNumber in 0 .. rowCount -> SetRow(rowNumber, startTime)]
        SelectedRow = None
      }

let update msg m =
  match msg with
  | SetAppointmentDate d -> {m with AppointmentDate = d}
  | SetSelectedRow r -> {m with SelectedRow = r}

let bindings () : Binding<Model, Msg> list = [
  "SelectedAppointmentDate" |> Binding.twoWay( (fun m -> m.AppointmentDate), SetAppointmentDate)
  "Rows" |> Binding.oneWay( fun m -> m.Rows)
  "SelectedRow" |> Binding.twoWay( (fun m -> m.SelectedRow), SetSelectedRow)
]

let designVm = ViewModel.designInstance init (bindings ())


let main window =
  Program.mkSimpleWpf (fun () -> init) update bindings
  |> Program.withConsoleTrace
  |> Program.runWindowWithConfig
    { ElmConfig.Default with LogConsole = true; Measure = true }
    window

DisplayMememberBindings 将 LastName 显示为“Some(LastName1)”,将 BirthDate 显示为“Some(09/14/2020 00:00:00)”。

如何让 return 的 LastName: string 选项为 null 或字符串的值,以便显示显示“LastName1”而不是“Some(LastName1)”?

出生日期也一样,如何将出生日期显示为“9/14/2020”而不是“Some(09/14/2020 00:00:00)?

TIA

完整源代码位于:Example DataGrid

您的代码只有三个绑定。您应该对每个单独的数据都有一个绑定。具体来说,您应该将 Rows 绑定从 OneWay 绑定更改为 SubModel 绑定。然后对所有其他类型重复此操作。

那么,你具体问的问题是如何显示LastName1而不是Some(LastName1)9/14/2020而不是Some(09/14/2020 00:00:00)。使用以 Opt 结尾的 Binding 方法为这些单独的可选数据片段创建绑定,例如 Binding.oneWayOpt or Binding.twoWayOpt.

对于像我这样的新手,这里是 my 完整的 F# working Elmish 解决方案。WPF/F#:

module MyDataGrid.DataGrid

open Elmish
open Elmish.WPF
open System

module Visit = 
    
    type Model =
       { ServiceTime: DateTime option
         DoNotSee: Boolean option
         ChartNumber: int option
         LastName: string option
         FirstName: string option
         Mi: string option
         BirthDate: DateTime option
         PostingTime: DateTime option 
         AppointmentTime: DateTime option 
         Id: int}

    let SetVisits appointmentsPerCell  = [for x in 1 .. appointmentsPerCell -> 
                                                {
                                                  ServiceTime = Some System.DateTime.Now 
                                                  DoNotSee = Some false 
                                                  ChartNumber = Some 8812 
                                                  LastName= Some ("LastName" + string x)
                                                  FirstName= Some ("FirstName" + string x)
                                                  Mi = Some "J" 
                                                  BirthDate = Some(DateTime(2020,09,14))
                                                  PostingTime = Some DateTime.Now
                                                  AppointmentTime = Some DateTime.Now
                                                  Id = x
                                              }]   
    
    let bindings() = [
        "FirstName" |> Binding.oneWayOpt( fun (_, m) -> m.FirstName)
        "LastName"  |> Binding.oneWayOpt( fun (_, m) -> m.LastName)
        "BirthDate" |> Binding.oneWayOpt( fun (_, m) -> m.BirthDate) 
        "ServiceTime" |> Binding.oneWayOpt( fun (_, m) -> m.ServiceTime)
    ]

module Cell =

    type Model =
        { RowNumber: int
          ColumnNumber: int
          AppointmentKeys: Visit.Model list
          ColumnTime: TimeSpan
          AppointmentCount: int
          AppointmentTime: DateTime option  // all lines in the cell have the same appointment time.  
          Id: int
        }

    let SetCell (rowNumber: int, columnNumber: int) =
        let AppointmentsPerCell = 4
        {RowNumber = rowNumber
         ColumnNumber = columnNumber
         AppointmentKeys =  Visit.SetVisits AppointmentsPerCell  
         ColumnTime = System.TimeSpan.FromMinutes(float(columnNumber * 15))
         AppointmentCount = 4
         AppointmentTime = Some(DateTime.Now)
         Id=rowNumber*10 + columnNumber
         }

    let bindings() =[
        "AppointmentKeys"  |> Binding.subModelSeq(
                                (fun (_, m) -> m.AppointmentKeys),
                                (fun v -> v.Id),
                                 Visit.bindings                            
                              )
    ]

module Row =

    type Model =
      { RowTime: string
        Columns: Cell.Model list 
        Id: int }

    let SetRow (rowNumber: int, startTime: System.TimeSpan)= 
        let columnCount = 4
        let hr = System.TimeSpan.FromHours(1.0)
        let rowTime = startTime + System.TimeSpan.FromTicks(hr.Ticks * int64(rowNumber))
        { RowTime = rowTime.ToString("h':00'")
          Columns = [for columnNumber in 1 .. columnCount -> Cell.SetCell(rowNumber, columnNumber) ]
          Id = rowNumber
        }

    
    let bindings () = [
        "RowTime" |> Binding.oneWay( fun (_,r) -> r.RowTime)
        "Columns" |> Binding.subModelSeq(
                                            (fun (_, m) -> m.Columns),
                                            (fun c -> c.Id),
                                             Cell.bindings                            
                                          )
    
    ] 
    

type Model =
  { AppointmentDate: DateTime
    Rows: Row.Model list
    SelectedRow: Row.Model option}

type Msg =
  | SetAppointmentDate of DateTime
  | SetSelectedRow of Row.Model option

let init () =
    let rowCount = 9
    let startTime = TimeSpan.FromHours(float(8))
    { AppointmentDate = DateTime.Now 
      Rows = [for rowNumber in 0 .. rowCount -> Row.SetRow(rowNumber, startTime)]
      SelectedRow = None
    }

let update msg m =
  match msg with
  | SetAppointmentDate d -> {m with AppointmentDate = d}
  | SetSelectedRow r -> {m with SelectedRow = r}

let bindings () : Binding<Model, Msg> list = [
  "SelectedAppointmentDate" |> Binding.twoWay( (fun m -> m.AppointmentDate), SetAppointmentDate)
  "Rows" |> Binding.subModelSeq(
                                 (fun m -> m.Rows),
                                 (fun r -> r.Id),
                                  Row.bindings                          
                               )
  "SelectedRow" |> Binding.twoWay( (fun m -> m.SelectedRow), SetSelectedRow)
]

let main window =
  Program.mkSimpleWpf init update bindings
  |> Program.withConsoleTrace
  |> Program.runWindowWithConfig
    { ElmConfig.Default with LogConsole = true; Measure = true }
    window
    enter code here