I am trying to implement complex Console menu with several multilevel sub menus(path type menu). Maybe someone suggest what design pattern to use in my situation?
Example of top menu
* Main Menu *
1. List Virtual Servers
2. List Image Templates
3. Exit
If for example 1 is selected next sub menu appears
* List Virtual Servers *
1. Virtual server #1
2. Virtual server #2
3. Virtual server #3
4. Return
If for example 2 is selected next sub menu appears
* Command for Virtual server #2 *
1. Delete
2. Return
My current navigation code is below, this is only for the first top menu, not sure how to implement multilevel path type menu with full navigation up and down through menus.
static void Main(string[] args)
{
Console.WriteLine("1. List Virtual Servers" +
Environment.NewLine + "2. List Image Templates" +
Environment.NewLine + "3. Exit");
var input = Console.ReadKey();
var key = input.KeyChar;
int value;
if (int.TryParse(key.ToString(), out value))
{
Console.WriteLine();
RouteChoice(value);
}
else
{
Console.WriteLine("Invalid Entry.");
}
Console.Write("Press any key to exit...");
Console.ReadKey(false);
Console.ReadLine();
}
private static void RouteChoice(int menuChoice)
{
switch (menuChoice)
{
case 1:
GetVirtualServers();
break;
case 2:
GetImageTemplate();
break;
default:
Console.WriteLine("Invalid Entry!");
break;
}
}
My idea is to model a hierarchy of menu items as a tree and to traverse this tree when a user navigates through the menu. From design patterns perspective it would be a mix of Composite and Command + some tree traversing. In order to do so we need:
A base class BaseCommand to model each command in your menu.
A base class Command derived from BaseCommand for menu items that performs some logic - for leafs in the tree.
A base class CompositeCommand derived from BaseCommand for commands with children. This class will have Children property which will store objects of type BaseCommand.
Every command that can perform some logic e.g. Virtual server #1 should be derived from Command.
Every command that has children e.g. List Virtual Servers should be derived from CompositeCommand.
At the beginning of your program you should create a tree of commands. In your case in the root of this tree we will find Main Menu. The Children property of Main Menu will contain references to commands for List Virtual Servers, List Image Templates, Exit and so on.
The last part of this solution is a manager. The manager is a class that has to keep a track where we are in the tree. When the manager receives an input from a user, he can do 3 things: execute the current command if it is a leaf, move to the parent of the current command if a user selects Return, move to a child of the current command if it has one.
I've written a console menu which may be useful as a starting point to you.
CMenu is a lightweight, low-ceremony framework for building console menus in .Net. Instead of manually prompting the user for input and parsing it, you define commands in a short, structured and comprehensive way, and let CMenu handle the rest.
CMenu aims for low overhead - simple stuff should be simple to implement. If you don't use a feature, you don't need to know anything about it.
At the same time, complex scenarios are supported. Large menus can easily be split into several classes. Background self-configuration. You do not have to worry about all the annoying details involved in larger menus, it will just work.
Most importantly, it is very simple and fast to use. Commands can be abbreviated, a smart parser enables even partial matching. A help command is integrated.
It was not written with this numbered style of operation in mind, but it can be emulated and should work perfectly if you name the commands "1. foo", "2. bar" etc.
The inheritance system very simple (just derive from CMenuItem and override Execute), or if you want you can even just use lambdas instead.
var menu = new CMenu ();
menu.Add ("1. foo", s => Console.WriteLine ("Foo!"));
menu.Add ("2. bar", s => Console.WriteLine ("Bar!"));
menu.Run ();
Menu trees are supported very well, see this page for examples. As an example (there are other ways to create hierarchical menus):
var m = new CMenu () {
new CMenuItem ("1") {
new CMenuItem ("1", s => Console.WriteLine ("1-1")),
new CMenuItem ("2", s => Console.WriteLine ("1-2")),
},
new CMenuItem ("2") {
new CMenuItem ("1", s => Console.WriteLine ("2-1")),
new CMenuItem ("2", s => Console.WriteLine ("2-2")),
},
};
Update: Selection via single number key press will be included natively in the next release (0.8).
Related
I have made a simple localization of messages. All messages are stored in the static class Lng
public static partial class Lng
{
public static readonly string AppName = "My application";
public static class Category1
{
public static readonly string ConfirmDelete = "Are you sure want to delete?";
}
}
In code usage is as simple as referencing fields
MessageBox.Show(Lng.Category1.ConfirmDelete, ...
Then there is a manager, which does following:
language selection
load corresponding translation
updating fields via reflection
export currently selected language on application exit for an update (in case if default language is selected - to create first translation for any other language)
It's irrelevant of how language files looks likes, but here is a reflection part
TranslateLng("Lng.", typeof(Lng));
...
private static void TranslateLng(string parent, Type type)
{
foreach (Type nested in type.GetNestedTypes())
{
string child = string.Format("{0}{1}.", parent, nested.Name);
TranslateLng(child, nested);
foreach (var field in nested.GetFields())
{
string key = child + field.Name;
DefaultAdd(key, (string)field.GetValue(null)); // store value in default language dictionary (if not created yet)
field.SetValue(null, GetValue(key)); // get value for currently selected language
}
}
This system has one problem: all messages are defined in one class, which required manual management (deleting and updating messages when updating code which uses them).
And I was thinking to change manager to register strings dynamically and simplify usage to something like
MessageBox.Show(Lng.Text("Are you sure want to delete?"), ...
So that text is defined right where it used, duplicated text can be handled by manager and so on.
There are however 2 problems:
I will need a complete list of all messages at the end of application run to export complete list of messages (for currently selected language). What if some of Lng.Text() are never called at that run? Is there a way to register them as they are used in code (compile time?)? So that all calls will be registered somehow, even if peace of code is never used.
How to generate key. I could use CallerMemberName, but right key are more useful, as they are telling exact purpose. To example, Lng.Configuration.Appearance.CaptionText. I could call Lng.Text(key, message), but then I have to manage keys, ensure in their uniqueness, which doesn't appeals me.
I recently worked on a project with internationaliztion and we used Resources in con junction with the Sisulizer program with great success. Having the resources solves your key problem as you manually enter the key when you extract the resources. You also get great support from Resharper which makes the whole process a breeze.
Sisulizer is then used to extract resources as well as strings hard-coded in our Win Forms and WPF classes. It can export a CSV which you can give your translators and it also supports pseudo translation, which makes testing such apps very easy as well.
Lets say I have a component with a number of smaller components which check prerequisites before the first one will be initialized. They are not dependent on one another so I don't care about order and would like them to run simultaneously. I am using MEF and Caliburn.Micro for presentation.
I thought about this setup:
class Big
{
[ImportMany]
public IEnumerable<IBigPrerequisite> Prerequisites {get; set;}
public void Initialize(){...}
}
and
interface IBigPrerequisite
{
public bool IsBusy {...}
public bool Allow {...}
public void StartChecking();
}
Now what I would like to accomplish with this is that the classes implementing IBigPrerequisite can open up a window (for example "File X was not found - this could lead to errors. Continue?") - this should be possible.
But I would only want one window to be visible at a time. How would I accomplish that besides just going synchronously?
EDIT - since the question seemed too vague
I need these Actions to run specifically before Big will be activated. Let's say we switch up the activation logic to something like this:
Big big; //we got this through Importing somewhere in composition
var allow = true;
var count = 0;
if(!pre.Any()) //no prerequisites, show window immediately
windowManager.ShowWindow(big)
foreach(var pre in big.Prerequisities)
{
pre.PropertyChanged += (s, args) =>
{
if(args.PropertyName == "IsBusy" && !pre.IsBusy) // if a prerequisite finished it's check
{
allow = allow && pre.Allow; //if one prerequisite says nay we could just return, actually...
count++;
if(count == big.Prerequisites.Count() && allow)
windowManager.ShowWindow(big);
}
}
pre.StartChecking();
}
Now, I explicitly want the classes implementing IBigPrerequisite to be able to open a window, but in case all prerequisites are met (no user interaction required) no window should be showing. I do not wish to open up a window for every class here.
I am looking for a way to, say, give the IBigPrerequisite (which should probably be called IPrerequisiteViewModel anyways) a property like bool RequestsWindow {get;} and have the View only created when a) the viewmodel requests it and b) no other prerequisite window is open at the time.
Note: the code here is for illustration only as I am not sure how to implement this behaviour yet. I am not experienced with these frameworks (and concepts) so if this question seems silly please bear with me.
You are mixing concepts here.
Active view management in Caliburn.Micro is handled by the Conductor class. A Conductor-derived ViewModel can display a large number of Screen-derived ViewModels (or other Conductors). Available items are stored in the Items property.
You can find a much better description at "Screens, Conductors and Composition"
MEF has nothing to do with the Conductors and the composition mechanism, although it can be used to pass a list of items to a conductor. You can define an [ImportMany] constructor parameter or public property that receives the Screens to display during initializations and store them in the conductor's Items property.
Using a constructor parameter is more elegant, as you won't have to copy the items from your property's setter to the Items property.
Finally, you shouldn't display messages when creating your views and viewmodels. This is something that should be left for a later step, eg. during the Activate method. The Conductors and MEF get the parts together and build the UI. Executing actions and talking to the user should be done only after the composition step has finished.
I am going to answer this question myself detailing how I ended up solving this.
I made a LoaderViewModel : Conductor<PropertyChangedBase>.Collection.OneActive, IChild<Shell> and gave it a Queue<PropertyChangedBase>.
It has Show/HideWindow methods by traversing the Parent-Properties until it arrives at the Window-Level.
It has Queue and Dequeue methods. Queue is used when PropertyChanged is fired on a RequestsView-Property and calls Dequeue if there's either no ActiveItem or the ActiveItem is not marked as busy. Dequeue will activate a new item if there is one in the queue and then call ShowWindow, if there is no item it will call HideWindow instead.
The initial HideWindow is done in the ViewAttached-Event since if the window is hidden, CM seems to have some strange behaviour. Here, the parallel checking of the prerequisites is started and an event-handler registered similar to the one in the first post.
Sorry for being verbose, but the code has gotten a bit lengthy. If someone wants me to post it up write a comment.
I'm re-writing in C# (with Winforms) an old VB6 app that uses a single context menu with multiple Items that change their Caption, Visible, and Enabled traits based on a monolithic function called "InitControls"
The function is 500 lines long and consists primarily of a switch statement that decides what controls to enable based on the selected item's tag (there's a tree view and list view; it selects the selected item from the active one and gets its tag). It then enables, disables, and modifies the text of the visible items, and clears any useless Separators. The original uses ActiveBar (a custom control) which allows it to change the text in one place and display the item in menus, context menus, and toolbars all at once.
I'm currently just re-implementing the logic line for line in C#, but I hate it because I'm not really fixing anything, just putting the problem into a new language (and possibly screwing it up in the process). I created a class that allowed me to change the text, enabled and visible properties of any "subscribed" Menu Items in one place and even add/remove event handlers for all subscriBed menu items. It works, and even seems apparently correct, but I'm pretty sure there's got to be a better way. My MainForm is ENORMOUS.
What is the standard .NET way of handling complex Context Menu and Toolbar logic?
From what I understand, you basically want to refactor a large switch-case method. Googling for "switch case refactoring" should give you several examples you can check out to find something that suits you best.
Usually, when you are refactoring a switch case, this means that you want to extract logic from each case block into a new class, possibly an implementation of an interface common to all cases. The right implentation of your class will depend on the condition of an individual case statement: this is called a Strategy pattern, because each condition demands a different strategy.
In your case, you need to slightly extend the pattern: you have a number of candidates for the context menu, each of them being able to handle a certain node type. In that case, your right-click handler needs to let them decide if they can provide functionality for a certain node.
[Edit]
To clarify a bit, I will provide a simple example.
I mentioned that individual implementations should be extracted into classes which implement the same interface, which should be responsible for changing menu items' appearance and state, based on the current condition.
interface IMenuStateManager
{
// this method updates state of one or
// more menu elements, according to the
// specified selected node info
void UpdateState(ISelectedNodeInfo info);
}
Our first, basic implementation of the IMenuStateManager interface will do nothing more that simply call other managers' implementations. This is called a Composite object pattern, because it allows us to treat a group of objects as a single object:
// composite class for a list of menu managers
class CompositeMenuStateManager : IMenuStateManager
{
private readonly IMenuStateManager[] _childManagers;
// params keyword will allow as to pass a comma separated list
// of managers, which is neat
public CompositeMenuStateManager(params IMenuStateManager[] managers)
{
_childManagers = managers;
}
// this is where the job gets done, but composite
// class doesn't do much work by itself
public void UpdateState(ISelectedNodeInfo info)
{
// allow each state manager to change its state
foreach (IMenuStateManager mgr in _childManagers)
{
mgr.UpdateState(info);
}
}
}
Now, you still have an enormous list of possible menu candidates, but now their logic is separated into different classes, and then wrapped in a single composite object.
IMenuStateManager _menuManager = new CompositeMenuStateManager
(
// note: each menu "manager" can manage one or more
// items, if you find it useful.
// For example, ClipboardMenuStateManager can be
// a composite manager itself (cut/copy/paste).
new ClipboardMenuStateManager(some params),
new SomeOtherMenuItemManager(various params),
new YetAnotherMenuItemManager(various params),
...
);
I guess that menu states get updated when a node is selected, but this is something you should easily adapt to your app. That particular event handler delegates the whole responsibility to our composite menu manager:
void Node_Selected(sender object, EventArgs args)
{
// find out which node was clicked
Node node = object as Node;
// get the data (model) node for this tree node
INodeData data = node.Tag as INodeData;
// create some info which will be passed to the manager.
// you can pass information that might be useful,
// or just simply pass the node data itself
ISelectedNodeInfo info = new SelectedNodeInfo(data, some other stuff);
// let the manager do the rest of the job
_menuManager.UpdateState(info);
}
Since you will probably have three menu items doing the same job at the same time (main menu, context menu, toolbar), you will probably want to make each IMenuStateManager implementation update all three of them at the same time. The simplest way should be to to pass an array of ToolStripItem objects, which is the base abstract class for several different menu elements:
class PrintMenuManager : IMenuStateManager
{
private readonly ToolStripItem[] _items;
// this constructor can accept several menu elements
public PrintMenuManager(params ToolStripItem[] items)
{
_items = items;
}
public void UpdateState(ISelectedNodeInfo node)
{
foreach (ToolStripItem item in _items)
{
// if node is printable, enable
// all "print" menu items and buttons
item.Enabled = (node.IsPrintable);
}
}
}
When creating the PrintMenuManager instance, you can pass all buttons and menu items which are related:
// (this should be one of the child managers in
// the composite menu manager, but you get it)
IMenuStateManager printMnuManaegr = new PrintMenuManager
(
this.printMenuItem,
this.printContextMenuItem,
this.printToolbarButton,
);
Whew, this turned out to be a lengthy one at the end. :)
Ok, that's about it for a start.
Could you tell me if it is possible to add an element to a Microsoft WinForms control?
For example: Suppose you have an application that has several users, each of which have their own "permissions," which are represented simply by the strings "1," "2," "3," etc. You also have several buttons on your application, which should be enabled/disabled according to the permission level of the current user.
Would it be possible to add a "String" to the "Button" control, which could indicate what permission level this button represents.
The reason this is helpful, is because I could loop through all of my buttons and disable them if the current user's permission level is not high enough.
I hope this makes sense.
Thanks.
There is a Tag property on WinForms controls that you can use to store a reference to related information. It is of type object, so it can store anything. (msdn reference)
myButton.Tag = "1";
If you want to store more than one thing, then create a class for it:
class UserTag
{
public string Permission {get;set;}
public string Name {get;set;}
}
....
myButton.Tag = new UserTag { Permission="1", Name="Alice" };
....
// Use like this: ((UserTag)myButton.Tag).Permission
Maintain and storing logics behind UI is not an appropriate solution, It makes things harder as your projects grows larger, Store your logics in data structures and make UI compatible and suitable by using the datas.
anyway the solution to your problem is both IExtenderProvider said by Hans and Matt's Answer.
----EDIT----
//this is just a simple sample! :D
Dictionary<string, int[]> CtrlType = new Dictionary<string, int[]>();
CtrlType.Add(button1.Name, new int[] { 2, 3 });
//add another controls status or attributes for user customizing
//.
//.
//.
//somewhere in your form UI Customization for users
button1.Enabled = CtrlType[button1.Name].Contains(UserID) ? true : false;
//handle another controls attributes
Is it better to specify all the parameters of a given in one line, or each parameter on a seperate line? i.e. which is better?
seperate And for each parameter
Scenario: some random scenario
Given a menu with a menu width of 19
And quit text of "quit"
And Fruit options of
|Text|
|some text|
When ...
Then ...
or all the paremters for the specific Given on one line
Scenario: Some scenario
Given a menu with quit text of "quit" and menu width of 19 and Fruit options of
|Text|
|Some text|
When ...
Then ...
This appears (and I hope I'm wrong) to have the following implications for how you write your bindings, as well as starts to influence how you write your class, which it shouldnt! i.e. first option (seperate AND for each parameter ) the binding is easier to write if your class has public properties that are set one by one after the object is created...
private Menu _menu;
[Given(#"a menu of fruit options")]
public void GivenAMenuOfFruitOptions(Table table)
{
string[] fruitOptions = table.GetColumn("Fruit");
_menu = new Menu(fruitOptions,null);
}
[Given(#"a menu width of (.*)")]
public void GivenAMenuWidthOf(string width)
{
_menu.Width = int.Parse(width);
}
[Given(#"a Quite text of ""(.*)""")]
public void GivenAMenuWidthOf(string quitText)
{
_menu.QuitText = quitText;
}
whereas option two ( all on one line) it's easier to have an object with a constructor that takes all the parameters as constructor arguments.
private Menu _menu;
[Given(#"a menu with quit text of ""(.*)"" and menu width of (\d+) and Fruit options of ")]
public void GivenAMenuOfFruitOptions(string quitText, int width, Table table)
{
string[] fruitOptions = table.GetColumn("Fruit");
_menu = new Menu(fruitOptions,width, quitText);
}
I feel as if I'm missing something, because the implementation of specflow should not influence the code I write, and I'm worried that #1 above will encourage overly stateful objects. I'm a functional stateless addict.
Any pointers will be most helpful.
txs in advance,
cheers, Alan
I am writing BDD style tests and I am using the first method because...
The setup methods (also for verification) might get reused in related tests.
Any failing tests will highlight the exact method that fails, including setup.
Eliminates duplication for related tests and thus will be easier to maintain.
Not answering the full question, but just this part:
I feel as if I'm missing something,
because the implementation of specflow
should not influence the code I write,
and I'm worried that #1 above will
encourage overly stateful objects. I'm
a functional stateless addict.
I don't think that it is a problem that the formulation of the scenarios influence the binding code. That's why it is a binding (other frameworks call it "glue" that emphasizes this even more). You can have a well designed business or automation logic that you have to drive with the binding code.
Functional/stateless: There is no built-in chaining option for the step bindings (the binding method returns something that the next receives), but you can create a kind of step context class (using context injection: http://github.com/techtalk/SpecFlow/tree/master/Tests/FeatureTests/ContextInjection/) where you can achieve a similar design.