views:

85

answers:

3

I'm making a WPF application that is comprised of Screens (Presenter + View). I want to be able to declare these screens in a config file or SQL database. I have been trying to come up with a good solution I've given up and am asking how some of you design this sort of thing? I've been working at this for over a week and every solution I come up with stinks.

In my WPF application I have a treeview that represents screens. When the user clicks on a node, the screen is loaded. I want to be able to populate the treenodes from a config file or database. The program should not care where these are stored so I can swap out a config store for a database store. If I have the screen info stored I can also use an IOC container to instantiate the screens for me and retrieve them by name. Here is a sample of the config file schema that I have come up with:

<screen name="" title="" presenterType="" viewType=""/>
<screen ...>
    <screen .../>
    <screen .../>
</screen>
<screen .../>

The latest solution I have come up with is to use a ScreenService that asks a ScreenRepository for ScreenInfo objects. Then I will be able to populate the treeview and IOC container with this information.

Does this sound like a good solution? What would you do different? And, how do you design this sort of system in your own programming?

A: 

In general you need to use a Factory Pattern for these types of situations. Your mix of ScreenService, ScreenRepository, and Screeninfo sounds like you nailed it. Here is a basic overview of what a Factory Pattern. You can use the Wikipedia article as a starting point to see if there are any variation or aspects that you missed.

I designed and maintain a CAD/CAM application that has several libraries of precanned parametric shapes where the user can type in a few dimensions and calculate the shape for cutting. Each shape has it's own screen setup. I use a similar pattern to your during the startup of my applications.

I scan the directory of shape library for each assembly, pick out the factory class which has a method that retrieves a list of shapes, load it into a master list. When the user clicks on a toolbar button or picks from the list the software then uses a key to pull the right shape out of the list which exposes a IShapeScreen interface. The form that manages the shapes uses that interface to draw the correct entry screen for that shape.

This method has worked for nearly a decade without any significant problems and just as important hasn't left me with a "Oh I wish I did this when I designed it" feeling. So I think you are on the right track.

Note that you may not need to use a text based config file. Using attributes, some interfaces you define and the .NET reflection API you can just throw DLLs in a directory the software can scan that directory and correctly pull in the desired objects. In your case screen objects. However if you want a human to edit the configuration then a text based file is certainly called for. I am assuming that you are using the .NET API as you tagged with .NET.

RS Conley
A: 

Sorry, I should have mentioned I am using .NET 3.5. I'm so use to posting on the ASP.NET forum that I forgot.

I do like the scanning of assemblies idea, but I would like to have it defined as a hierarchy for populating the treeview. Also, what is the performance penalty for using reflection to scan assemblies compared to a config file or database? Is it a noticable difference or so minor no one will be able to tell?

The application I am creating is to be used internally within our company. It needs to have a hierarchical structure for navigation so our screens can be easy to find. The scanning of an assembly folder would be nice, because we could make a module and through it into that folder and the app would pick it up automatically. This would lead to a problem of representing the screens in a hierarchical way. Also, we would like to implement authorization so the users only see the screens they are allowed to use.

Thanks for the response. I like to see how others do things. It helps me understand a lot of these design concepts since I am just starting out on the path of design patterns (just ordered the PEAA book). Anyone else please share your thoughts. It may also help someone else like me who stumbles upon this question.

Wili
A: 

When you return objects out your factory method you can include a hierarchy as well. For example my shape factories have two methods One returns a list of shapes that added to a master list, Another return Shape Libraries. While User can define and alter the actual libraries I have a default set automatically generated to use for troubleshooting and initial installation. It is hierarchical.

However A ShapeLibrary is comprised of ShapeLibraryItem. A ShapeLibraryItem has a key stored with it so it can pull the shape out of the master program list. So a button or item is clicked, it looks at the ShapeLibrary Item it is associated with. Get the key, uses the key to get the shape program and then uses the UI Interface to draw the screen.

IF your screen has the hierarchy info embedded as one of it's many properties then I recommend that you separate it out into a Hierarchy Item. A HierarchyList then can be created that is comprised of HierarchyLists OR HierarchyItem. I would make a IHierarchyItem interface so that HierarchyLists look like a item.

The main difference is behavior. When you click a HeirarchyList will bring up another list (or expand, etc) a true Item will bring up a screen.

So your assembly will have two class marked with one of two attributes. One will be the ScreenFactory, and the other will be the HierarchyFactory.

Note you don't have to use keys you could directly link a HierarchyItem to the shape. I use GUID keys to avoid coupling every single time. Coupling is not always bad but it isn't always good either. Since GUID are effectively unique it works out the same.

As for performance you will have to hundreds of ASSEMBLIES before you notice it. Remember you don't have to have an assembly for each screen. Just group them logically into a handful of assemblies and you are good to go.

RS Conley