/// <summary> /// Constructor in charge to initialise the menu components, and all its variables required. /// This approach is inspired in a basic implementation of Model-View-Controller framework. /// The view (or user interface) is stored in a separate file with the SAME name, with different extension (.txt) /// The process consists on 4 steps: /// 1. Read the View File: To initialise the interface layout and its attributes /// 2. Load Body attributes: Brigde to connect the interface intormation with object attributes /// 3. Draw the content layout: All the layout is stored in dom variable. /// </summary> public View() { Console.Clear(); // Finding the view layout through relative path. string relativefilePath = string.Format(@"..\..\..\Views\{0}.txt", this.GetType().Name); if (!File.Exists(relativefilePath)) { throw new Exception(string.Format(@"View '{0}' layout not found. ", this.GetType().Name)); } // Reading the view template at once string[] lines = File.ReadAllLines(relativefilePath); // Verifying the content. At least the file must contain 2 rows. // Further validations in process if (lines.Length < 1) { throw new Exception(string.Format(@"View '{0}' layout does not contain the appropiate format. ", this.GetType().Name)); } //-------------------------- // -- Reading the content -- //-------------------------- //---------------------------------------- // -- Row 1: Header, Subheader, and footer //---------------------------------------- string[] titlesArray = lines[0].Split("||"); if (lines.Length < 2) { throw new Exception(string.Format(@"Header, Subheader, and footer are required in '{0}' layout. It does not contain the appropiate format. ", this.GetType().Name)); } // Getting each pair attribure/value. string[] headerArray = titlesArray[0].Split(':'); string[] subheaderArray = titlesArray[1].Split(':'); string[] footerArray = titlesArray[2].Split(':'); // Verifying the dimension of each array string header = headerArray[1]; string subheader = subheaderArray[1]; string footer = footerArray[1]; //---------------------------- // -- Row 2: Body atributes -- //---------------------------- for (int i = 1; i < lines.Length; i++) { // BodyParameter bodyParameter = new BodyParameter(); string[] bodyArray = lines[i].Split("||"); if (bodyArray.Length < 6) { throw new Exception(string.Format(@"ASD ASD ASD are required in '{0}' layout. It does not contain the appropiate format. ", this.GetType().Name)); } string[] paramArray; paramArray = bodyArray[0].Split(':'); bodyParameter.AttributeName = paramArray[1]; paramArray = bodyArray[1].Split(':'); bodyParameter.DataType = paramArray[1]; paramArray = bodyArray[2].Split(':'); bodyParameter.MaxLength = int.Parse(paramArray[1]); paramArray = bodyArray[3].Split(':'); bodyParameter.Nulleable = bool.Parse(paramArray[1]); paramArray = bodyArray[4].Split(':'); bodyParameter.RegexValidation = paramArray[1]; paramArray = bodyArray[5].Split(':'); bodyParameter.Visualisation = paramArray[1]; bodyParameter.Value = string.Empty; bodyParameterList.Add(bodyParameter); // Based on the attribute parameters, the longest value is recorder to facilitate the view drawing. if (lengthLongestAtt < bodyParameter.AttributeName.Length) { lengthLongestAtt = bodyParameter.AttributeName.Length; } if (lengthLongestValue < bodyParameter.MaxLength) { lengthLongestValue = bodyParameter.MaxLength; } } //-------------------------- // -- Drawing the content -- //-------------------------- // Printing the top border Border(BorderType.Top, true); // Printing the header AlignContent(header, AlignmentType.Center, true); // Printing the border between header and subheader (or content when subheader is null) Border(BorderType.Div, true); if (subheader != "") { AlignContent(subheader.Split('#'), AlignmentType.Center, true); } /////////////////////////////// // Printing Margins pre-body // /////////////////////////////// // The Row position is stored to keep a reference in special cases when is required to print information // For Example, an account is founded, the user information is displayed in the body yPosBodyMessage = dom.Count; // Minus 5 because those are the footer's rows. int bodyMargnis = (viewHeight - bodyParameterList.Count - dom.Count - 5) / 2; Border(BorderType.Empty, bodyMargnis, true); // Printing Body foreach (BodyParameter param in bodyParameterList) { // Displaying content aligned to left AlignContent(string.Format("{0}{1}", param.AttributeName, string.Format(":").PadLeft(lengthLongestAtt - param.AttributeName.Length + 1, ' ')) , AlignmentType.Left, true); // As DOM is a copy of the information in console, the position of character ':' is stored // to know exactly where is the x,y location of each attribute. param.X = dom[dom.Count - 1].IndexOf(':') + 2; param.Y = dom.Count - 1; } // Printing Margins post-body Border(BorderType.Empty, bodyMargnis, true); // Printing the border between body and control footer Border(BorderType.Div, true); // Footer // yPosControlMessage = dom.Count; Border(BorderType.Empty, true); Border(BorderType.Empty, true); AlignContent("↑↓: Select Item Enter: Select Esc: Quit/Escape", AlignmentType.Center, true); Border(BorderType.Bottom, true); }
/// <summary> /// CORE METHOD: Method in charge to handle the user inputs. Its purpose is to validate whether /// the user input is a control key such us: Up, Down, enter, Esc or a meaningful character. /// All the interfaces share almost the same approach: A user fills the form. Then, the information is /// validated, and if everything is correct, all the parameters are updated to the object. Otherwise, /// an error message is displayed. /// </summary> /// <returns></returns> protected bool VerifylInputs() { ConsoleKeyInfo usrInput; int currentParameterPosition = 0; // Setting the Console cursor in the first body parameter location. BodyParameter currentParameter = this.bodyParameterList[currentParameterPosition]; Console.SetCursorPosition(currentParameter.X + currentParameter.Value.Length, currentParameter.Y); do { usrInput = Console.ReadKey(true); // Verifying if the user input is an special content or just information if ((int)usrInput.KeyChar < 32) { // SPECIAL CONTROL CHARACTERS // ENTER: All the information must be validated if (usrInput.Key == ConsoleKey.Enter) { // Veryfing if the body parametes could be nullable if (this.VerifyBodyParameters() == true) { return(true); } else { // Returning the cursor to the same position, before the user press enter Console.SetCursorPosition(currentParameter.X + currentParameter.Value.Length, currentParameter.Y); } } else { // UP if (usrInput.Key == ConsoleKey.UpArrow && currentParameterPosition - 1 >= 0) { currentParameterPosition -= 1; currentParameter = this.bodyParameterList[currentParameterPosition]; } // DOWN else if ((usrInput.Key == ConsoleKey.DownArrow || usrInput.Key == ConsoleKey.Tab) && currentParameterPosition + 1 < this.bodyParameterList.Count) { currentParameterPosition += 1; currentParameter = this.bodyParameterList[currentParameterPosition]; } // BACKSPACE else if (usrInput.Key == ConsoleKey.Backspace && currentParameter.Value.Length > 0) { currentParameter.Value = currentParameter.Value.Substring(0, currentParameter.Value.Length - 1); } Console.SetCursorPosition(currentParameter.X, currentParameter.Y); Console.Write(string.Format(" ").PadLeft(viewMargin + viewWidth - currentParameter.X - 1, ' ')); Console.SetCursorPosition(currentParameter.X, currentParameter.Y); if (currentParameter.Visualisation == "Plain") { Console.Write(currentParameter.Value); } else if (currentParameter.Value.Length > 0) { Console.Write(string.Format("*").PadLeft(currentParameter.Value.Length, '*')); } } } // else if (currentParameter.Value.Length < currentParameter.MaxLength) { // SIMPLE CHARACTERS currentParameter.Value += usrInput.KeyChar.ToString(); Console.SetCursorPosition(currentParameter.X, currentParameter.Y); Console.Write(string.Format(" ").PadLeft(viewMargin + viewWidth - currentParameter.X - 1, ' ')); Console.SetCursorPosition(currentParameter.X, currentParameter.Y); if (currentParameter.Visualisation == "Plain") { Console.Write(currentParameter.Value); } else if (currentParameter.Value.Length > 0) { Console.Write(string.Format("*").PadLeft(currentParameter.Value.Length, '*')); } } Console.SetCursorPosition(currentParameter.X, currentParameter.Y); if (currentParameter.Visualisation == "Plain") { Console.Write(currentParameter.Value); } else if (currentParameter.Value.Length > 0) { Console.Write(string.Format("*").PadLeft(currentParameter.Value.Length, '*')); } // Verifying until user press ESC } while (usrInput.Key != ConsoleKey.Escape); return(false); }