views:

551

answers:

3

Extended problem

I would like to add a new problem in addition to the original problem specified below. One of the user controls in the application contains a list of objects that I need to access from another user control. How can this be done? (I don't believe the division into controls is very well performed, but I'd rather not change it..)

Should I do it by events as with the original problem, or should I get hold of the parent Form, and use it to find the instance of the control, and expose it as a property?


Original problem

I have two user controls in a form that I want to be able to communicate with each other. Usercontrol A should be able to start an operation on B.

What is the preferred way of solving this? Should the form wait for an Event from A, and then start the operation on B? Any design pattern for this? Or is it an even easier solution?

Thanks in advance! :)

A: 
  1. Expose the data it as a property.
  2. Create a property on the other user control that the parent form will populate with the reference to the control with the data.

Pseudo code:

public UserControlA uca { get; set; }
...

var items = uca.Items;
Adrian Godong
A: 

I would do it like this (i use vb.net)

Class MyUserControlA
'Inherits UserControl '(This line will be in your desinger file)

Delegate Sub SomethingEventHandler (sender as object, e as EventArgs)  '(assumes you are not going to override event args)

Public Event SomethingEvent as SomethingEventHandler

private _someData as String

Public Readonly Property MyDataGrid as DataGridView
    Get
        Return DataGridView1  ' this is in the designer form of the user control
    End Get

Public Property SomeData as string
    Get
        return _someData
    End Get
    Set(value as string)
        _someData as string
    End Set
End Property

Protected Sub OnSomethingEvent()
    RaiseEvent SomethingEvent(Me, EventArgs())
End Sub

'....something happens and you want to raise the event
OnSomethingEvent

End Class

Implement the main form as follows

Class MainForm
Implements Form  'designer file

'....other code
Sub MyUserControlA1_SomethingEvent Handles MyUserControlA1.SomethingEvent
    'instead of calling a property you could override eventArgs and return the control that way.
    MyUserControlB1.OtherDataGridView=MyUserControlA1.MyDataGrid
End Sub

End Class

UserControlB is as follows:

Class UserControlB 
Inherits UserControl ' designer form

'...other code

private _dataGrid as DataGridView=Nothing


    Public Property DataGrid() As DataGridView
        Get
            Return _dataGrid
        End Get
        Set(ByVal value As DataGridView)
            'only set if null
            if _dataGrid is Nothing then _dataGrid = value
        End Set
    End Property



'do stuff with the control...I would always check for null
function DoSomethingWithDataGrid as integer
    if _dataGrid IsNot Nothing then
        return _dataGrid.Items.Count
    End If
End Sub
End Class

THIS CODE IS NOT TESTED.

This is fairly loosely coupled this way. I guess in an ideal world you would wrap what you need in UserControlA DataGrid in methods and properties and consume them that way. But if there is a lot of members you are referecning in the DataGrid then this is certainly easier.

I am not professing that this is a perfect design. I am still learning winforms architecture. What do you experts think?

Seth B Spearman

Seth Spearman
+2  A: 

The two user controls should not have any knowledge of each other. If you want to always deal with them as a pair, consider creating a third user control to house them.

Should the form wait for an Event from A, and then start the operation on B?

Yes, this is the only good way to handle this.

The extended (bonus?) problem is a bit trickier. I would handle this by having the form pass the user control a delegate to a method on the other user control to retrieve the data. The user control can then invoke the delegate method to call the method on the other control without having any knowledge of its implementation.

Jamie Ide
I tried the delegate approach, and it worked fine. (of course you say!) Quite elegant also in contrast to the rest ;)
l3dx