@Samuel's suggestion is perfectly adequate when collecting one or two values from the user.
If you're getting many values then the solution in your question is fine as well.
Don't fall prey to premature optimization and over-engineer a decoupled solution. By boundary object I assume you're referring to the datastructure instance referenced by the mainframe and dialog. What's the problem with the dialog and mainframe both referencing this object? What is the benefit of decoupling the boundary/transfer object in this scenario?
The only decoupling payoff I could see here would be decoupling the mainframe from the specific implementation that delivers the data to it. So rather than the mainframe instantiating Dialog and calling Dialog.ShowModal, dependency injection would provide the mainframe with an IDataYouNeedGetter (which would happen to be the same modal dialog) and at the appropriate time the mainframe would do
myGetter.SetTransferObject(dataStructInstance)
myGetter.GoGetTheData()
// do stuff with dataStructInstance now that myGetter set it up.
BUT, there is no reason to add a layer of indirection unless you already know of a specific need for the decoupling.