F#Elmish.wpf difficulty with pattern matching in bindings(). Pattern match seems to fail? - Stack Overflow

admin2025-04-17  2

In Elmish.wpf / F#, I have the following code:

type Page = 
    | SettingsModel of Settings.Model
    | MainModel of Main.Model

type Model = CurrentPage of Page

type Msg =
    | SettingsMsg of Settings.Msg
    | MainMsg of Main.Msg
    | NavigateToMainModel
    
let mutable currentModel : Model option = None 

let bindings () : Binding<Model, Msg> list =
    match currentModel with
    | Some (CurrentPage (SettingsModel settingsModel)) -> 
        Settings.bindings () 
        |> List.map (Binding.mapMsg SettingsMsg >> Binding.mapModel (function
            | CurrentPage (SettingsModel sm) -> sm 
            | _ -> failwith "Unexpected model in SettingsModel binding"))
    | Some (CurrentPage (MainModel mainModel)) -> 
        Main.bindings () 
        |> List.map (Binding.mapMsg MainMsg >> Binding.mapModel (function
            | CurrentPage (MainModel mm) -> mm 
            | _ -> failwith "Unexpected model in MainModel binding"))
    | None -> failwith "Model not initialized"

The problem is that when currentModel is correctly changed to CurrentPage (MainModel mainModel)), the first pattern still matches on Some(CurrentPage (SettingsModel settingsModel)). Why? How to fix?

Edit#1: As requested, here is more of the code. Essentially, I would like to open a single (preferrably) modal window, "Settings". Upon closing this window, update correctly executes "NavigateToMainModel" which is responsible for placing the second window, "Main", as the Model. (I will need to add code to remove the attached events for loading and closing of the Settings window, but I don't believe that should have any effect on this question).

let subscribeToClosingEvent dispatch = 
        let p = EventPublisher.Instance 
        p.Publish.Add (fun _ -> dispatch NavigateToMainModel)
    
    
    
    let init () : Model * Cmd<Msg> = 
        let settingsModel, settingCmd = Settings.init()   
        let initialModel = CurrentPage (SettingsModel settingsModel)
        currentModel <- Some initialModel
        initialModel, Cmd.batch [
            Cmd.map SettingsMsg settingCmd
            Cmd.ofEffect subscribeToClosingEvent
        ]

    let update msg (CurrentPage page) =
        match page, msg with
        | SettingsModel settingsModel, SettingsMsg settingsMsg ->
            let newSettingsModel, cmd = Settings.update settingsMsg settingsModel
            match settingsMsg with
            | Settings.Success ->
                let mainModel, mainCmd = Main.init()
                let updatedModel = CurrentPage (MainModel mainModel)
                currentModel <- Some updatedModel
                updatedModel, Cmd.batch [ Cmd.map MainMsg mainCmd; 
                                            Cmd.ofEffect (fun dispatch ->
                                                let settingsWindow = Application.Current.MainWindow :?> Settings
                                                settingsWindow.Closing.Add(fun args ->
                                                    args.Cancel <- false
                                                    dispatch NavigateToMainModel
                                                    settingsWindow.Close())
                                            ) ]
            | _ ->
                let updatedModel = CurrentPage (SettingsModel newSettingsModel)
                currentModel <- Some updatedModel
                updatedModel, Cmd.map SettingsMsg cmd 
    
        | MainModel mainModel, MainMsg mainMsg ->
            let newMainModel, cmd = Main.update mainMsg mainModel
            let updatedModel = CurrentPage (MainModel newMainModel)
            currentModel <- Some updatedModel
            updatedModel, Cmd.map MainMsg cmd 
    
        | _, NavigateToMainModel ->
            let mainModel, mainCmd = Main.init()
            let initialModel = CurrentPage (MainModel mainModel)
            currentModel <- Some initialModel
            initialModel, Cmd.map MainMsg mainCmd 
    
        | _ -> CurrentPage page, Cmd.none



module MainModule =

    [<EntryPoint; STAThread>]
    let main argv =

        // Create an instance of the Application class.
        // Note: If the OutputType of this project (e.g., MyApp.Business) is set to Exe, the app will
        // open with a console (black) window. Changing the OutputType to WinExe will avoid the
        // console window and open as a WPF application.
        let app = new Application()
        
        // Create the Settings window
        let closingEventPublisher = CustomEvents.getInstance()
        let settingsWindow = new Settings()
        
        // Set the main window
        app.MainWindow <- settingsWindow

        // Attach event handler for the Loaded event to start the Elmish loop
        settingsWindow.Loaded.Add(fun _ ->
            // Start the Elmish loop after the window is loaded
            WpfProgram.mkProgram AppModule.init AppModule.update AppModule.bindings
            |> WpfProgram.startElmishLoop(settingsWindow)             
        )

        settingsWindow.Closing.Add(fun args ->
            args.Cancel <- true
            closingEventPublisher.Trigger(settingsWindow, EventArgs.Empty)
        )
        
        // Show the window
        settingsWindow.Show()
    
       // settingsWindow.Closing.RemoveHandler(closingHandler)
       // settingsWindow.Close()
        
        // Run the application
        app.Run() |> ignore
        0
转载请注明原文地址:http://anycun.com/QandA/1744848134a88461.html