views:

492

answers:

5

I'm looking for a good pattern to resolve the following circular reference in a Windows Form application:

  • Assembly 1 contains a Windows Form with an Infragistics menu item ".Show"ing a Form in Assembly 2
  • Assembly 2 contains a Windows Form with an Infragistics menu item ".Show"ing a Form in Assembly 1

The menu has generally the same items on it throughout the application. So both Assembly 1 and Assembly 2 have references to one another to "New up" one anothers' forms and .Show them.

A note about size: My app is an existing app, so the situation is not quite as simple as the above two-assembly situation. But if I can solve the above simply (probably not implementing a , I can apply that to a much larger application (about 20 components, all with several forms that pop each other up across components).

I've thought through a few solutions, but they all seem cumbersome. Is there a simple solution I'm missing?

+3  A: 

You could (in both cases) make the button simply raise an event. The shell exe references both assemblies, and hooks up the even to show the other form.

So the exe knows about both; neither of the forms knows about the other.

For example (same concept):

using System;
using System.Windows.Forms;
class Form1 : Form
{
    public event EventHandler Foo;
    public Form1()
    {
        Button btn = new Button();
        btn.Click += delegate { if(Foo!=null) Foo(this, EventArgs.Empty);};
        Controls.Add(btn);
    }
}
class Form2 : Form
{
    public event EventHandler Bar;
    public Form2()
    {
        Button btn = new Button();
        btn.Click += delegate { if (Bar!= null) Bar(this, EventArgs.Empty); };
        Controls.Add(btn);
    }
}
static class Program
{
    [STAThread]
    static void Main()
    {
        ShowForm1();
        Application.Run();
    }
    static void ShowForm1()
    {
        Form1 f1 = new Form1();
        f1.Foo += delegate { ShowForm2(); };
        f1.Show();
    }
    static void ShowForm2()
    {
        Form2 f2 = new Form2();
        f2.Bar += delegate { ShowForm1(); };
        f2.Show();
    }
}
Marc Gravell
-1, cause the executable must know the connection between those two windows - use interfaces!
BeowulfOF
@BeowulfOF - that is fairly absurd. It isn't reasonable to put an entire IoC/DI framework in for an example like this! And without IoC/DI, the exe must know the concrete types to create them. I'm honestly quite saddened...
Marc Gravell
I thought about using events and even started implementing it in one small case. I may end up using that solution. However, it seems pretty cumbersome, given the number of assemblies and forms that I have. I'm looking for a more low-impact way to implement the solution on the whole app, if possible.
Mark A Johnson
+2  A: 

Have you considered creating a 3rd assembly and moving all the common code into the 3rd assembly?

John Sonmez
I'm not sure I follow your suggestion, John. If I put all the "new...show" calls in the 3rd assembly, each assembly needs to reference it and it references all others, so I'm still circular.
Mark A Johnson
No, all the common code goes in the 3rd. So both of the others depend on the 3rd, and the 3rd depends on nothing.
John Sonmez
+1  A: 

Use a component factory or component composer, like the MEF, to create instances without referencing the component's source assembly.

David Schmitt
A: 

What about using Interfaces? You could build a third library containing interfaces, and every window implements one interface from itself, and references the interface of the other window.

BeowulfOF
I think interfaces will be involved. However, I still need to create an instance, so my code is something like:IMyClass x = new MyClass();So will will still need a reference to the assembly that houses MyClass.I'm trying to do something with reflection right now, to eliminate the assembly ref.
Mark A Johnson
If you need to, IMyClass = new MyClass, then you definetively need to overthink your model. Should be IMyClass = ObjectFromBaseClass.GetMyClassInstance.
BeowulfOF
A: 

I've decided, at the moment, to use reflection to pop up the windows that need popping up. I remove the need to refer to them directly, and I'll actually be able to add in components more easily, without creating all the cross-referenced assemblies.

I looked at MEF but, unfortunately, I'm using VS2003, rather than VS2008. That suggestion started me down the path of simple reflection.

Thanks.

Mark A Johnson