0

I have a MainWindow which opens a modal window (following the NewWindow example in the Elmish.WPF tutorial). My modal window deals almost exclusively with visual elements in xaml and C# code (i.e., handwriting recognition). Aside from creating a separate "submit" button in the xaml, I would like the closing window event to automatically send the accumalated data to the F# supporting code. This is what I've tried, but the closing/closed event is never triggered to send the data. How can this be done?

Thanks for any suggestions.

XAML:

<i:Interaction.Triggers>
        <i:EventTrigger EventName="Closing">
            <i:InvokeCommandAction PassEventArgsToCommand="True" Command="{Binding ClosingCommand}" CommandParameter="{Binding ElementName=ProgressNote, Path=WordDictionary}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

Elmish.Wpf:

 "ClosingCommand" |> Binding.cmdParam paramWordDictionaryMsg

"ProgressNoteWindow"  |> Binding.subModelWin(                          
              (fun m -> m.ProgressNoteWin |> WindowState.ofOption),
                    snd,                                           
                    ProgressNoteWinMsg,                            
                    ProgressNoteWinBindings,                       
                    createProgressNote,                              
                    onCloseRequested = ProgressNoteWinCloseRequested,
                    isModal = true)  


type Msg = | ProgressNoteWinCloseRequested




let update msg m =
| ProgressNoteWinCloseRequested -> 
            match m.ProgressNoteWin with
            | Some { ConfirmState = Some ConfirmStateEnum.CloseRequested } -> { m with ProgressNoteWin = None }, Cmd.none
            | Some progressNoteWin -> { m with ProgressNoteWin = Some { progressNoteWin with ConfirmState = Some ConfirmStateEnum.CloseRequested } }, Cmd.none
            | None -> m, Cmd.none
Alan Wayne
  • 5,122
  • 10
  • 52
  • 95

1 Answers1

2

I really just wanted to post a comment to help you along, but it got far too long. This isn't a quality answer, but so be it. I think it'll solve your problem.

Forget the closing/closed events. It's simpler than that.

It is not clear to me what you want. What do you mean with "Aside from..."? I see two possibilities.

If you want the data to be submitted only when some button is clicked, then you should bind that click event to a message that you handle, and submit the data there, then perhaps you want to close the window which I believe you do by posting ProgressNoteWinCloseRequested. Probably indirectly, by posting a child message which the parent will listen to, before posting ProgressNoteWinCloseRequested to itself.

If instead you mean you don't want such a button, and instead you want to save data no matter which manner you close the window, then your ProgressNoteWinCloseRequested message handler in the parent model can take care of saving the data in the child model, which it has available before you set the state to WindowState.Closed.

Or maybe you can come up with something even more elegant inspired by this.

I'm not sure what the rest of your code might look like, but you'll probably figure out possible problems I can't see.

Also, be aware there's v 3.x and 4.x of Elmish.WPF, and I don't know if the problems I encountered when working with this machinery is still present in the latest 3.x, or have been fixed. Search in the GitHub repo of Elmish.WPF for information. Or easier - just do what I do and stick to the latest 4.x which is a prerelease on NuGet. Yes, it's a prerelease, but still more trustworthy in my opinion.

Bent Tranberg
  • 3,445
  • 26
  • 35
  • Hi! I guess I wasn't very clear. I would like the user to click on the "X" that closes the window and have the modal window "send" the data, by way of a command parameter, back to the supporting F# code. It is not clear to me how to configure the "ProgressNoteWinCloseRequested" message to receive data when the modal window is being closed. Thanks. – Alan Wayne Dec 01 '22 at 18:40
  • 1
    p.s., I'm in Elmish.Wpf, 4.0.0-beta-44 – Alan Wayne Dec 01 '22 at 18:49
  • In my app, outside of the modal window initialization code, the F# support knows nothing about the data in the modal window. Hence, when the modal window is closed, i wish to transfer its data to F#. (i.e., F# does not have the instance of the modal window--only a supporting data structure in the model). Thanks. – Alan Wayne Dec 01 '22 at 19:41
  • Normally you'd bind data to the progressNoteWin model, and read the data from there when ProgressNoteWinCloseRequested is received, before setting m.ProgressNoteWin to None to actually close the modal window. I don't know how to do it in any other way, and I also worry anything else involving XAML or other GUI mechanisms could be messy due to threading issues. – Bent Tranberg Dec 01 '22 at 20:29
  • Ah well, had to try :) Thanks. – Alan Wayne Dec 02 '22 at 00:08
  • 1
    My applications that use Elmish.WPF usually has microservices. These form the business layer of the application. Frequently there will be modal dialogs that only have business interaction with the microservices. If I understand correctly, what you have is so-called code behind in that modal window, and the results are business information. Rather than use the GUI to haphazardly transport your data from the modal dialog to the parent window, you could communicate through a business layer. If you don't have anything suitable, I suggest you look at this gem: https://github.com/Cysharp/MessagePipe – Bent Tranberg Dec 02 '22 at 05:25
  • 1
    You'd subscribe to a subject in the parent window, then publish a message on that subject from the dialog when it closes. (In Elmish.WPF, the onCloseRequested message can be a sub-message from the modal window, which the parent message will then route, so the modal will know when it closes, and can post in MessagePipe.) If I were to use MessagePipe, then I would swap out the MessagePack serializer for FsPickler. I haven't used MessagePipe, but I have used AlterNats which is the same principle but with message servers. There I've used FsPickler rather than MessagePack for the serialization. – Bent Tranberg Dec 02 '22 at 05:38