Listening for MessageBox and Dialog results in my application

870 views Asked by At

I have a "ControlMonitor" class which is designed to listen to the events that occur on a form. The way it works is, I pass the form that I want to monitor into an instance of this class, and then the class iterates through all of the form's controls and registers for their "relevant" events. For example, if the control is a TextBox, I register for TextChanged. If the control's a ComboBox, I register for both SelectedIndexChanged and TextChanged, and so on. In this way, the "ControlMonitor" instance is able to report on every significant action the user took in my form, with a minimal amount of intrusiveness to the form code itself.

It works great for reporting on any controls in the form, but I also need to know which common dialogs/message boxes were launched by the form and how the user responded to them. I should mention that the larger objective here is automation: we want to end up with a set of repeatable steps that can be scripted into something that plays back in an automation tool. To that end, it's not enough to know that the user clicked "File/Open"; we also need to know the window title of the OpenFileDialog that was launched, the path that the user selected and the DialogResult. The same goes for MessageBox calls; we need to know the window title and DialogResult.

The common dialogs seem to have minimal support for events (the FolderBrowserDialog apparently doesn't any events at all), and I'm not even sure where to start when it comes to listening for the results of a MessageBox call. Of course, I could write a wrapper class that encapsulates common dialogs and MessageBox calls and passes the results to a "ControlMonitor" instance... but then the rest of the program would have to use this wrapper class all the time, and a primary objective with my "ControlMonitor" class is that you can include it in a project and listen in on one of the forms with minimal intrusion to the original code.

Is there anything I can do within the "ControlMonitor" class? I need DialogResults and window titles for all dialogs/message boxes, and for more complex dialogs like OpenFileDialog I also need to know the path the user selected, etc. The "ControlMonitor" class is a compiled part of the program that it's trying to listen to, so it has direct access to the Form object that is passed into it. I'm so close here; I can monitor 95% of the application because most of it is just controls on a form... I just need a way to monitor the dialogs, too!

2

There are 2 answers

3
Josh Weatherly On

I solved a similar problem by just creating a wrapper function for the MessageBox.Show() calls, then replacing all of the calls in our app to this function.

something akin to:

Public Function My_MessageBox(ByVal pstrMsg As String, _
    Optional ByVal pstrCaption As String = "", _
    Optional ByVal pButtons As Windows.Forms.MessageBoxButtons = MessageBoxButtons.OK, _
    Optional ByVal pIcon As Windows.Forms.MessageBoxIcon = MessageBoxIcon.None, _
    Optional ByVal pDefButton As Windows.Forms.MessageBoxDefaultButton = MessageBoxDefaultButton.Button1) _
    As Windows.Forms.DialogResult

    Dim rval As Windows.Forms.DialogResult

    If glAutomated Then
        ' if automation is running, we don't want to show 
        ' the box to the user, just retrieve the result stored
        rval = AutomateThisMessageBox("MsgBox" & pstrCaption.Replace(" ", ""))
    Else
        rval = MessageBox.Show(pstrMsg, pstrCaption, pButtons, pIcon, pDefButton)

        If glRecording Then 'Only record the result when in "record" mode
            Hooks.RecordMessageBox(pstrCaption.Replace(" ", ""), rval.ToString)
        End If
    End If

    Return rval

End Function

Usage: exactly the same as Messagebox.Show is currently used, just substitute in the new function Name eg:

MessageBox.Show("This is a test", "Test Msg", 
    MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk, 
    MessageBoxDefaultButton.Button1)

becomes

My_MessageBox("This is a test", "Test Msg", 
    MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk, 
    MessageBoxDefaultButton.Button1)

Edit:

Just re-read the end of your question about all the different dialogs. I'm guessing a similar technique could be used in a general sense. Or different wrappers for all the dialogs you need (file open/etc)

0
Can Gencer On

I know that it might require rather big changes your application, however why not go with an event broker design that is loosely coupled instead? It will give you more flexibility on how to deal with the events.

The Composite UI Application Block that Microsoft has released has a sample event broker, but it is also not much effort to write your own. The gist of the idea is that you have a central broker that your controls publish events to. It is then possible for any other class to subscribe to any of these events. This makes the events publishing / subscribing loosely coupled and removes the strong dependencies between different controls.