tags:

views:

31

answers:

4

I'm trying to figure out the best way to reference a control on a form from within a module. Unfortunately the form is just an instance, so it's not as easy as calling form.control...

    Dim ChildForm As New frmSearch 
    ' Make it a child of this MDI form before showing it. '
    ChildForm.MdiParent = Me
    ChildForm.Show()

That form has an option for printing, which calls another form where certain options are chosen. The print form in turn calls a function in a module, which tries to reference back to the origional form.

childform as new frmSearch -> frmPrintForm -> sub okToPrint (in module Print)

okToPrint tries to reference a listview on frmSearch, but can't find it.

    For Each itmX In frmSearch.lstResults.Items

So the solutions I can think of off the top of my head are:
1. Somehow divine which form is the caller of frmPrintForm
2. Pass ChildForm to the frmPrintForm as a variable to be passed on to module Print..
3. Use frmSearch directly instead of using an instance of it.

Number 1 would be my preference, as I don't want to have to pass forms around like that.

+1  A: 

Can I recommend option #4: Pass just the items that you would get from lstResults.Items? You are no longer passing forms (which I agree is a bad thing), nor even relying on having been called from a form.

Philip Rieck
Something like `Private iList As New List(Of ListViewItems)`?
AndyD273
More like `iList As New List(Of WhateverTheTypeOfDataIsThatYouAreStoringInYourListViewItem)`.
Heinzi
+1  A: 

Don't pass around forms, pass around data. When the print option is selected, loop through the frmSearch results, put the data into some appropriate data structure (probably some list containing some elements), pass this data to frmPrintForm and, afterwards, to okToPrint.

Yes, this means that more parameters are needed, but it also means that your form frmPrintForm and your sub okToPrint no longer depend on details of frmSearch. This makes it easier to reuse your print functionality and to change stuff in your search form without having to worry about breaking something in a completely unrelated module.

Heinzi
OK, this just got a lot more complicated, and I'm probably going to have to pass the form by reference if I cant just reference the controls on it. frmPrintForm has a lot of options on it, on a lot of different tabs. If they want to use the mailing or shipping address, etc. and the number of tabs shown changes depending on what type of mailing they are doing, so I can't pass them all as parameters. I just wish I could use frmPrintForm.cboAddress.tag or whatever like the VB6 version did.
AndyD273
A: 

call frmPrintForm modally: frmPrintForm.Show(ME). Then you can use frmPrintForm.Parent to obtain a reference to the calling instance of frmSearch

rascalion
+1  A: 

I'm hesitant to suggest this, because this is "asking for downvotes", but I'll mention it anyway for sake of completeness: If you ensure that there is always only one search form on display, you could globally store a reference to the Search form. (Yes, I said "global variable", now go ahead and downvote. :-P)

Public Class frmSearch
    ...

    Private Shared currentSearchForm As frmSearch

    Public Shared ReadOnly Property Current() As frmSearch
        Get
            Return currentSearchForm
        End Get
    End Property

    Public Sub New()
        ''# Do your constructor stuff here
        ...

        currentSearchForm = Me
    End Sub
End Class

This will allow you to access the last opened search form with frmSearch.Current. Note that this solution has all the drawbacks usually associated with global variables, but I guess it most closely resembles what you are used to in VB6.

The code above is to give you the general idea, there is lots of room for improvement (make the constructor private and use a Shared method instead which ensures that no second instance of the form is opened; set currentSearchForm to Nothing when the form is closed, etc.).

Just to mention this once more, passing the relevant data to the print form is a much cleaner solution, but in the end, the decision is yours, and you should know about all available options.

Heinzi
A combination of this and your other suggestion seems to be the answer I'm looking for. I pass the list of items to frmPrintForm from frmSearch, but then use frmPrintForm.Current to get access to all the controls on it that I need. I really thought that it was possible to access forms in .net without using the .current, but whatever, at least this works and I learned something new.
AndyD273
@AndyD273: Actually, now that you mention it, there *is* a way to access "all open forms": http://msdn.microsoft.com/en-us/library/system.windows.forms.application.openforms.aspx. In particular, `Application.OpenForms("frmSearch")` should return the currently open form with the name "frmSearch". I don't know if the `Name` property of a form is automatically set to the class name, so you might need to do `Me.Name = "frmSearch"` in the form's constructor first.
Heinzi
Thanks for the Application.OpenForms tip. I got to use it on another project and it works great for this. I didn't have to name it, just declared `dim frm as frmSearch = Application.OpenForms("frmSearch")` and it just worked for me.
AndyD273