Here is an overview of my application:
It is basically a cook book. The user can create a cookbook and then create recipes within that cookbook. I have a class CookBook and a class Recipe. CookBook keeps track of what recipes are associated with the cook book and Recipe keeps track of the contents of the recipe.
For the UI, i have a treeview where it will display the recipes that are in the CookBook. I have a TabControl that will display the tabs associated with each recipe. The tabs are dynamically created by the user during run time.
When the user clicks on one of the recipes, i want the TabControl to show the tabs related to that specific recipe. When the user clicks on a different recipe i want the tabs for the previous selection to go away and the tabs of the current selection to appear. (side note: I will be saving the contents of the tab and stuff to a file later, for saving purposes)
I want the Recipe class to contain the details about the TabControl (how many tabs there are for the recipe, title of each of the tabs, contents of the tabs). But i do not want Recipe to be responsible for creating the Tabs or TabControl.
My questions is, how do i accomplish the bolded section above? What are people's opinions and experience with this type of problem? What are the best practices for this type of problem?
THANKS!
I hope that the following code gives you an idea
public Form1()
{
InitializeComponent();
Recipe r1 = new Recipe() { Text = "Re1" };
Recipe r2 = new Recipe() { Text = "Re2" };
Recipe r3 = new Recipe() { Text = "Re3" };
listBox1.Items.Add(r1);
listBox1.Items.Add(r2);
listBox1.Items.Add(r3);
tabControl1.TabPages.Add(new AdvancedTabPage() { Recipe = r1,Text=r1.ToString() });
tabControl1.TabPages.Add(new AdvancedTabPage() { Recipe = r2, Text = r2.ToString() });
tabControl1.TabPages.Add(new AdvancedTabPage() { Recipe = r3, Text = r3.ToString() });
listBox1.SelectedIndexChanged += new EventHandler(listBox1_SelectedIndexChanged);
}
void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedItem != null)
foreach (AdvancedTabPage ad in tabControl1.TabPages)
{
if (ad.Recipe == listBox1.SelectedItem)
{
tabControl1.SelectedTab = ad;
break;
}
}
}
public class AdvancedTabPage : System.Windows.Forms.TabPage
{
public Recipe Recipe{get;set;}
}
public class Recipe
{
public string Text = "";
public override string ToString()
{
return Text;
}
}
This is a WinForms app I assume? You've run into the classic UI separation of concerns problem. The way most developers solve this (cleanly) is by implementing something like a document/view model. A loaded term thanks to MFC, but useful nonetheless.
Basically, your Recipe class is the document. The tabs are the view. Create a class that handles the tasks of displaying the Recipe in the tabs (or any other UI container), and use that to handle interaction with the user as well. The View is typically tightly coupled with the 'container' (which in this case would be the form itself), although that can be abstracted as well.
D/V in its most basic form is very similar to the MVC pattern, although you can do away with the controller part if your app is simple enough. Here is some light reading on the subject. Don't worry about the fact that it refers to MFC, the approach is the same regardless. Documentation on MVC might be useful as well, but it tends to focus on web-based apps.
Fun stuff :)
One way that I'd approach this is for each Treeview's item to have a reference to the Recipe class it represents. The Treeview will trigger an selection changed event captured on the form where you can extract the Recipe instance. This will then pass the Recipe instance to the TabControl, which will configure itself based on the Recipe information.
To accomplish this, I'd probably have a custom class derived from Treeview and one from TabControl with methods such as MyTreeview.DisplayCookBook(CookBook book), and MyTabControl.DisplayRecipe(Recipe recipe). This will encapsulate functionality in their respective containers and will communicate with each other via events, avoiding having a form with 1000 lines of code.
Hope that gives you some direction.