5
\$\begingroup\$

GetBootstrap-2.0 update from GetBootstrap-1.0.0.2

I just update my console application customizer and add some new features like disable minimize, maximize and close button, new color and simple popup box. Help me review my codes...

Here is my sample preview of GetBootstrap-2.0:

GetBootstrap-2.0

The preview contains Write(), WriteLine(),Popup(), Typewriter effect and colors.

Bootstrap.cs

public partial class Bootstrap
{
        public static void Write(string format, int min = 50, int max = 100, params object[] args)
        {
            format = String.Format(format, args);
            for (int i = 0; i < format.Length; i++)
            {
                Thread.Sleep(TypeWriter.Next(min, max));
                Console.Write(format.Substring(i, 1));
            }
        }

        public static void Write(string format, BootstrapStyle style, BootstrapType type, params object[] args)
        {
            Customize(style, type);
            Console.Write(String.Format(format, args));
            Console.ResetColor();
        }

        public static void Write(string format, int min, int max, BootstrapStyle style, BootstrapType type, params object[] args)
        {
            Customize(style, type);
            Write(format, min, max, args);
            Console.ResetColor();
        }

        #region Method WriteLine...
        public static void WriteLine(string format, int min = 50, int max = 100, params object[] args)
        {
            Write(format, min, max, args);
            Console.WriteLine();
        }

        public static void WriteLine(string format, BootstrapStyle style, BootstrapType type, params object[] args)
        {
            Write(format, style, type, args);
            Console.WriteLine();
        }

        public static void WriteLine(string format, int min, int max, BootstrapStyle style, BootstrapType type, params object[] args)
        {
            Write(format, min, max, style, type, args);
            Console.WriteLine();
        }
        #endregion

        #region Method MessageBox
        public static void Popup(string format, string caption, params object[] args)
        {
            MessageBox.Show(String.Format(format, args), caption);
        }
        #endregion

        #region Method Controller...
        public static void CloseBox(bool enable)
        {
            EnableMenu(GetSystemMenu(GetConsoleWindow(), enable), SC_CLOSE, MF_ENABLED);
        }

        public static void MaximizeBox(bool enable)
        {
            EnableMenu(GetSystemMenu(GetConsoleWindow(), enable), SC_MAXIMIZE, MF_ENABLED);
        }

        public static void MinimizeBox(bool enable)
        {
            EnableMenu(GetSystemMenu(GetConsoleWindow(), enable), SC_MINIMIZE, MF_ENABLED);
        }
        #endregion
    }

I decide to create a new file for my Bootstrap design and make it partial of Bootstrap.cs.

Bootstrap.Designer.cs

partial class Bootstrap
{
        static Random TypeWriter = new Random();

        const int MF_ENABLED = 0x00000000;
        const int SC_CLOSE = 0xF060;
        const int SC_MAXIMIZE = 0xF030;
        const int SC_MINIMIZE = 0xF020;

        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("kernel32.dll", ExactSpelling = true)]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern int EnableMenu(IntPtr hMenu, int nPosition, int wFlags);

        static void Customize(BootstrapStyle style, BootstrapType type)
        {
            switch (type)
            {
                case BootstrapType.Success:
                    Console.ForegroundColor = ConsoleColor.Green;
                    if(style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkGreen;
                    }
                    break;
                case BootstrapType.Info:
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    if(style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkCyan;
                    }
                    break;
                case BootstrapType.Warning:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    if(style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkYellow;
                    }
                    break;
                case BootstrapType.Danger:
                    Console.ForegroundColor = ConsoleColor.Red;
                    if(style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkRed;
                    }
                    break;
                case BootstrapType.Magenta:
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    if(style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkMagenta;
                    }
                    break;
                case BootstrapType.Cobalt:
                    Console.ForegroundColor = ConsoleColor.Blue;
                    if (style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkBlue;
                    }
                    break;
                default:
                    Console.ForegroundColor = ConsoleColor.Gray;
                    if(style == BootstrapStyle.Alert)
                    {
                        Console.BackgroundColor = ConsoleColor.DarkGray;
                    }
                    break;
            }
        }
    }

    #region Enum...
    public enum BootstrapStyle
    {
        Default,
        Alert
    }

    public enum BootstrapType
    {
        Default,
        Success,
        Info,
        Warning,
        Danger,
        Magenta,
        Cobalt
    }
    #endregion

If you want to try it I have a download link below. -"Tutorial Inside"

You can download and edit the project if you want.

Updates:

  • Added New Color
  • Added Simple Popup
  • Added Disable Minimize
  • Added Disable Maximize
  • Added Disable Close Button
  • Download Link
\$\endgroup\$
  • 1
    \$\begingroup\$ I see you ended up using a delegate to clean up that switch. That was a very cool solution. You might want to consider adding your thought process behind that as an answer here. \$\endgroup\$ – RubberDuck Jan 9 '15 at 13:01
1
\$\begingroup\$

A Bit About OOP

There's a really nasty switch statement in your Designer.

        switch (type)
        {
            case BootstrapType.Success:
                Console.ForegroundColor = ConsoleColor.Green;
                if(style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkGreen;
                }
                break;
            case BootstrapType.Info:
                Console.ForegroundColor = ConsoleColor.Cyan;
                if(style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkCyan;
                }
                break;
            case BootstrapType.Warning:
                Console.ForegroundColor = ConsoleColor.Yellow;
                if(style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkYellow;
                }
                break;
            case BootstrapType.Danger:
                Console.ForegroundColor = ConsoleColor.Red;
                if(style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkRed;
                }
                break;
            case BootstrapType.Magenta:
                Console.ForegroundColor = ConsoleColor.Magenta;
                if(style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkMagenta;
                }
                break;
            case BootstrapType.Cobalt:
                Console.ForegroundColor = ConsoleColor.Blue;
                if (style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkBlue;
                }
                break;
            default:
                Console.ForegroundColor = ConsoleColor.Gray;
                if(style == BootstrapStyle.Alert)
                {
                    Console.BackgroundColor = ConsoleColor.DarkGray;
                }
                break;
        }

In order to add any new styles to your code, you potentially have to make changes to three places in your code. Minimally, you have to add it to your enum and your switch. A little OOP can go about making this much easier to deal with. Particularly because these all do a very similar thing. You could extend this indefinitely and easily by inheriting from your Bootstrap class and overriding Customize.

First, you would need to change the signature of Customize in the base class so that we can over ride the method. Second, change it so that only the default case gets executed here.

static virtual void Customize(BootstrapStyle style)
{
    Console.ForegroundColor = ConsoleColor.Gray;
    if (style == Boostrap.Alert)
    {
        ConsoleColor.BackgroundColor = ConsoleColor.DarkGray;
    }
}

Note that I also removed the Type parameter, as we're replacing it with inherited classes.

Now we can go about implementing child classes like so.

public class SuccessBootstrap : Bootstrap
{
    static override void Customize(BootstrapStyle style)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        if (style == Boostrap.Alert)
        {
            ConsoleColor.BackgroundColor = ConsoleColor.DarkGreen;
        }
    }
}

public class InfoBoostrap : Bootstrap
{
    static override void Customize(BootstrapStyle style)
    {
        Console.ForegroundColor = ConsoleColor.Cyan;
        if (style == Boostrap.Alert)
        {
            ConsoleColor.BackgroundColor = ConsoleColor.DarkCyan;
        }
    }
}

And so on. With this method of creating new types of coloring schemes, you don't even have to open up the Bootstrap file. You just create a new child class and over ride Customize.

There is one more refactoring that should probably happen though. The "If style == alert then set background color" logic gets repeated in each and every one of these overrides. It could be simplified by extracting this logic into a protected method of your base class.

protected void SetBackgroundColor(ConsoleColor backgroundColor, BootstrapStyle style)
{
    if(style == BootstrapStyle.Alert)
    {
        Console.BackgroundColor = backgroundColor;
    }
}

Which simplifies your child class implementations down to two dead simple lines of code.

public class SuccessBootstrap : Bootstrap
{
    static override void Customize(BootstrapStyle style)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        base.SetBackgroundColor(ConsoleColor.DarkGreen, style);
    }
}

If you should decide to add a third style, you only need to update the logic in the base class.

\$\endgroup\$
5
\$\begingroup\$

A Bit About Regions

Some people hate them. I'm not one of those people. I think that used correctly, they're a great thing. For example, I think this is a wonderful use of a Region.

    #region Method WriteLine...
    public static void WriteLine(string format, int min = 50, int max = 100, params object[] args)
    {
        Write(format, min, max, args);
        Console.WriteLine();
    }

    public static void WriteLine(string format, BootstrapStyle style, BootstrapType type, params object[] args)
    {
        Write(format, style, type, args);
        Console.WriteLine();
    }

    public static void WriteLine(string format, int min, int max, BootstrapStyle style, BootstrapType type, params object[] args)
    {
        Write(format, min, max, style, type, args);
        Console.WriteLine();
    }
    #endregion

This is beautiful. It makes sense to group all of the different WriteLine overloads together. This is a good use of regions.

Unfortunately, you have some instances where it's not so good.

Here, for example, you've wrapped a single method inside of a region. Why? What does this do for us other than clutter the code?

    #region Method MessageBox
    public static void Popup(string format, string caption, params object[] args)
    {
        MessageBox.Show(String.Format(format, args), caption);
    }
    #endregion

To make it worse, the "comment" in the region doesn't match the method. One says it's a MessageBox while the name of the method is Popup. I understand why. You didn't want to muck around with a namespace conflict, which is okay. Although, I might have just called it ShowMessageBox and been done with it myself. Popup is a noun, but you're taking an action here. I digress however, because there's also this:

    #region Method Controller...
    public static void CloseBox(bool enable)
    {
        EnableMenu(GetSystemMenu(GetConsoleWindow(), enable), SC_CLOSE, MF_ENABLED);
    }

    public static void MaximizeBox(bool enable)
    {
        EnableMenu(GetSystemMenu(GetConsoleWindow(), enable), SC_MAXIMIZE, MF_ENABLED);
    }

    public static void MinimizeBox(bool enable)
    {
        EnableMenu(GetSystemMenu(GetConsoleWindow(), enable), SC_MINIMIZE, MF_ENABLED);
    }
    #endregion

Which in and of itself wouldn't be such a terrible use of regions. These all belong to the same logical group of methods, but now you're not being consistent with how you're using them. Are you using regions to logically group concepts, or overloads?? I suppose this is part of the reason so many people hate them.

All in all though, it's not bad. I've seen much worse and I might even venture to say that you've used them rather well, all in all. Just be careful with it. It's easy to let your regions get away from you. It's easy to just keep shoving things inside of them when you should really be extracting logic and creating new classes. I don't feel that's the case here, but I do feel it's worth mentioning.


P.S. Really cool little project. Thanks for sharing.

\$\endgroup\$
3
\$\begingroup\$

The huge switch block in Customize has a lot of repetition going on. It may be worth extracting a method here:

Console.ForegroundColor = ConsoleColor.Cyan;
if(style == BootstrapStyle.Alert)     
{
    Console.BackgroundColor = 
    ConsoleColor.DarkCyan;
}

There could be a concept of a "style", that contains foreground and background colors for both regular & Alert modes, and then you could replace the whole switch block with a single call - something like this...

_consoleStyles[type](style);
\$\endgroup\$
  • \$\begingroup\$ This is new in to my eyes _consoleStyles[type](style); what kind of method is this? \$\endgroup\$ – Leonel Sarmiento Dec 30 '14 at 3:00
  • \$\begingroup\$ It's just an Action<BootstrapStyle> delegate, in a Dictionary<BootstrapType,Action<BootstrapStyle>> ;) \$\endgroup\$ – Mathieu Guindon Dec 30 '14 at 3:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.