Esc input cuts of Writeline - c#

So I tried to code an userinput with ConsoleKeyInfo. Its works. Than I tried to implement an cancellation when Esc is pressed. It works aswell but it cuts off some of my Writeline. When I try the same code with checking for example M it works just fine!
Is someone able to help?
My Code:
class Program
{
static void Main()
{
while (true)
{
string eingabeArtikelnummer, eingabePlatzalter;
Console.Clear();
Console.Write("Ein neuer Artikel wird angelegt:\n\nGeben Sie die Artikelnummer an: ");
eingabePlatzalter = SteuerungUndEingabe();
if (eingabePlatzalter == ConsoleKey.Escape.ToString()) { break; }
else { eingabeArtikelnummer = eingabePlatzalter; }
}
WartenAufUser();
}
static string SteuerungUndEingabe()
{
ConsoleKey input;
string userEingabe = null;
do
{
input = Console.ReadKey().Key;
if (input == ConsoleKey.Escape)
{
userEingabe = input.ToString();
break;
}
userEingabe += input.ToString();
} while (input != ConsoleKey.Enter);
return (userEingabe);
}
static void WartenAufUser()
{
Console.WriteLine("----------------------------------------------------------------------------------------\n\nBeliebige Taste druecken um ins Menue zu gelangen!");
while (Console.ReadKey() == null) { };
}
}
}
This is the output in the Console:
This is how it should be:
Edit:
So I asked my Teacher how to fix this Problem. He had no idea why it occurs but he recommanded me to go around the Problem and change my Writeline to
Console.WriteLine("x\n----------------------------------------------------------------------------------------\n\nBeliebige Taste druecken um ins Menue zu gelangen!");
The "x\n" miraculously avoids the problem :D

Related

How to go back into Console.ReadLine() with return

I'm coding "Higher / Lower".
I commented where is the problem. Please don't spoiler the full solution of that game.
static void Main(string[] args)
{
Console.WriteLine("Higher ! Lower Game");
Console.WriteLine("\nSchwierigkeitsstufen:\nEasy: 1 - 100\nMedium: 100 - 1000\nHard: 1000 - 10000");
Console.WriteLine("\nWähle ein Level!");
string auswahl = Convert.ToString(Console.ReadLine());
Console.WriteLine("\nDu hast " + auswahl + " gewählt\nBist du sicher?\n'Ja' / 'Nein'");
string confirm = Convert.ToString(Console.ReadLine());
/// TEXT
/// PROZESS
if (confirm == "Ja")
{
if (auswahl == "Easy")
{
Console.WriteLine("\nGebe eine Zahl ein!");
int eingabe = Convert.ToInt32(Console.ReadLine());
Random rnd = new Random();
int rmd = rnd.Next(0, 99);
while (eingabe != rmd)
{
int eingabe2 = Convert.ToInt32(Console.ReadLine());
while (eingabe < rmd)
{
Console.WriteLine("Higher");
return; /// Here, it should go back to "eingabe2" to let the user guess again. if im trying: "return eingabe2;" there comes the error "CS0127".
}
while (eingabe > rmd)
{
Console.WriteLine("Lower");
return; /// Here, it should go back to "eingabe2" to let the user guess again. if im trying: "return eingabe2;" there comes the error "CS0127".
}
}
}
}
}
Do you make your code work the first thing is to remove the nested loop (use if instead of while. I may be wrong but you should not need it. Just reassign your value.
Somethings you want to dig:
int.TryParse vs Convert.ToInt32()
while vs do...while
Enum type for you level (Level.Easy, Level.Medium, Level.Hard) and for Ja/Nein (Answer.Yes, Answer.No)
Guard pattern (return early to avoid nesting logic)
Spoilers below:
static void Main(string[] args)
{
Console.WriteLine("Higher ! Lower Game");
Console.WriteLine("\nSchwierigkeitsstufen:\nEasy: 1 - 100\nMedium: 100 - 1000\nHard: 1000 - 10000");
Console.WriteLine("\nWähle ein Level!");
string auswahl = Convert.ToString(Console.ReadLine());
Console.WriteLine("\nDu hast " + auswahl + " gewählt\nBist du sicher?\n'Ja' / 'Nein'");
string confirm = Convert.ToString(Console.ReadLine());
/// TEXT
/// PROZESS
if (confirm == "Ja")
{
if (auswahl == "Easy")
{
Console.WriteLine("\nGebe eine Zahl ein!");
var rnd = new Random();
var rmd = rnd.Next(0, 99);
var eingabe = -1;
while (eingabe != rmd)
{
eingabe = Convert.ToInt32(Console.ReadLine());
if (eingabe < rmd)
{
Console.WriteLine("Higher");
/// Here, it should go back to "eingabe2" to let the user guess again. if im trying: "return eingabe2;" there comes the error "CS0127".
}
if (eingabe > rmd)
{
Console.WriteLine("Lower");
/// Here, it should go back to "eingabe2" to let the user guess again. if im trying: "return eingabe2;" there comes the error "CS0127".
}
}
}
}
}

C# Terminating the program with a key combo without pressing enter while in read

Now here is the situation we are in:
getinput:
//things happen here
string typed = Console.ReadLine();
try
if (typed == "com")
{
//things happen here
}
else if (Console.ReadKey(true).Key == (ConsoleKey.F1) + (ConsoleModifiers.Alt))
{
System.Environment.Exit(0);
}
//other else if's happen here
else
{
Console.WriteLine("\n" + typed + " isn't an option.");
goto getInput;
}
}
catch (Exception)
{
}
goto getInput;
what i want to do with this is when i press alt+f1 the program will terminate itself however because the program waits for some input from me to write even with the working version (without the alt part) it wants me to type the things then press enter, which i dont want. how does one handlde this??
static void Main(string[] args)
{
Console.TreatControlCAsInput = true;
var typed = ReadLine();
if (typed == "com")
{
Console.WriteLine("com");
//things happen here
}
//other else if's happen here
else
{
Console.WriteLine("\n" + typed + " isn't an option.");
}
}
public static string ReadLine() {
StringBuilder sb = new StringBuilder();
do
{
ConsoleKeyInfo key = Console.ReadKey();
if ((key.Modifiers & ConsoleModifiers.Alt) != 0)
{
if (key.Key == ConsoleKey.K)
{
Console.WriteLine("killing console");
System.Environment.Exit(0);
}
}
else
{
sb.Append(key.KeyChar);
if (key.KeyChar == '\n'||key.Key==ConsoleKey.Enter)
{
return sb.ToString();
}
}
} while (true);
}
that code will help you with your problem,
just be aware that when you reading a line by char's you will need to handle things like backspace
First of all, please consider using loops instead of goto, as gotos are dangerous. Why? Have a look here: 'Goto' is this bad?
To solve your problem you can use the ConsoleKeyInfo class in combination with the Console.ReadKey() method to get information about single key presses. With this you can check for any key-combination right before adding up the single characters to a string. A working example could look like:
namespace Stackoverflow
{
using System;
class Program
{
public static void Main(string[] args)
{
ConsoleKeyInfo keyInfo = default(ConsoleKeyInfo);
string input = string.Empty;
// loop while condition is true
while (true)
{
// read input character-wise as long as user presses 'Enter' or 'Alt+F1'
while (true)
{
// read a single character and print it to console
keyInfo = Console.ReadKey(false);
// check for close-combination
if (keyInfo.Key == ConsoleKey.F1 && (keyInfo.Modifiers & ConsoleModifiers.Alt) != 0)
{
// program terminates
Environment.Exit(0);
}
// check for enter-press
if (keyInfo.Key == ConsoleKey.Enter)
{
// break out of the loop without adding '\r' to the input string
break;
}
// add up input-string
input += keyInfo.KeyChar;
}
// optional: enter was pressed - add a new line
Console.WriteLine();
// user pressed enter, do something with the input
try
{
if (input == "com")
{
// right option - do something
}
else
{
// wrong option - reset ConsoleKeyInfo + input
Console.WriteLine("\n" + input + " isn't an option.");
keyInfo = default(ConsoleKeyInfo);
input = string.Empty;
continue;
}
}
catch (Exception)
{
// handle exceptions
}
}
}
}
}

How can I display a text and then let the user edit it? (console application)

I would like to call the database for a text and display it. Then let the user edit the displayed text as if she/he opened it in a text editor. Of course at the end I would like to save the edited version back to the database.
Unfortunately all of my ideas were dead ends, so eventually I decided to ask you, professionals and more experienced programmers, to help me as I am really just a beginner.
Here is my starting point:
Database.xml
<?xml version="1.0" encoding="utf-8" ?>
<Database>
<Texts>
<Text Id="00">Default text 00</Text>
<Text Id="01">Default text 01</Text>
<Text Id="02">Default text 02</Text>
</Texts>
</Database>
C# file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace EditableText
{
class Program
{
static void Main(string[] args)
{
SelectMenuOption();
Console.WriteLine("Thanks for stopping by!");
Console.ReadLine();
}
private static void SelectMenuOption()
{
bool tf = true;
while (tf)
{
Menu();
string userInput = Console.ReadLine().ToLower();
Console.WriteLine("--------------------------------------------------");
if (userInput == "text_00")
{
Console.Write(CallDatabase("00"));
tf = false;
}
else if (userInput == "text_01")
{
Console.Write(CallDatabase("01"));
tf = false;
}
else if (userInput == "text_02")
{
Console.Write(CallDatabase("02"));
tf = false;
}
else if (userInput == "quit")
{
tf = false;
}
else
{
Console.WriteLine("Error");
}
Console.ReadLine();
Console.Clear();
}
}
private static void Menu()
{
Console.WriteLine("You may play or write quit to say bye.");
Console.WriteLine("");
string[] texts = new string[]
{
"Text_00",
"Text_01",
"Text_02"
};
Console.WriteLine("Choose: ");
foreach (var text in texts)
{
Console.Write(" " + text);
}
Console.WriteLine("");
}
private static string CallDatabase(string idNumber)
{
XElement database = XElement.Load(#"Database.xml");
string dText = database.Element("Texts").Elements("Text").Where(x => x.Attribute("Id").Value == idNumber).FirstOrDefault().Value.ToString();
return dText;
}
}
}
Edited
I've tried this:
string text = "It's a text.";
char[] textC = text.ToCharArray();
foreach (var textL in textC)
{
Console.Write(textL);
}
int n = 0;
while (0 <= textC.Length - n)
{
if (Console.ReadKey().Key == ConsoleKey.LeftArrow)
{
Console.SetCursorPosition(textC.Length - n, 0);
n++;
}
}
And the problem was that when the cursor moved, the previous letter disappeared.
private static void SelectMenuOption()
{
bool tf = true;
while (tf)
{
Menu();
string userInput = Console.ReadLine().ToLower();
Console.WriteLine("--------------------------------------------------");
string id = string.Empty;
if (userInput == "text_00")
{
Console.Write(CallDatabase("00"));
id = "00";
tf = false;
}
else if (userInput == "text_01")
{
Console.Write(CallDatabase("01"));
id = "01";
tf = false;
}
else if (userInput == "text_02")
{
Console.Write(CallDatabase("02"));
id = "02";
tf = false;
}
else if (userInput == "quit")
{
tf = false;
}
else
{
Console.WriteLine("Error");
}
var chage = Console.ReadLine();
Replace(id, chage);
Console.Clear();
}
}
private static void Replace(string id, string chage)
{
XmlDocument xml = new XmlDocument();
xml.Load(#"Database.xml");
XmlNodeList elements = xml.SelectNodes("//Text");
foreach (XmlNode element in elements)
{
if (element.Attributes["Id"].Value == id)
{
element.InnerText = chage;
xml.Save("Database.xml");
}
}
}
Replace your functions(SelectMenuOption) from the code below. and Add one more method Replace in it as below. It will work. You can improve the code for sure, I just provided a solution. Hope it will help.

How do I only allow number input into my C# Console Application?

Console.WriteLine("Enter the cost of the item");
string input = Console.ReadLine();
double price = Convert.ToDouble(input);
Hello, I want the keyboard buttons, A-Z, brackets, question mark, etc to be disabled. I want it so if you type it in, it will not show up in the Console. I only want the numbers 1-9 to show up. This is in C# Console application. Thanks for the help!
try this code snippet
string _val = "";
Console.Write("Enter your value: ");
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
double val = 0;
bool _x = double.TryParse(key.KeyChar.ToString(), out val);
if (_x)
{
_val += key.KeyChar;
Console.Write(key.KeyChar);
}
}
else
{
if (key.Key == ConsoleKey.Backspace && _val.Length > 0)
{
_val = _val.Substring(0, (_val.Length - 1));
Console.Write("\b \b");
}
}
}
// Stops Receving Keys Once Enter is Pressed
while (key.Key != ConsoleKey.Enter);
Console.WriteLine();
Console.WriteLine("The Value You entered is : " + _val);
Console.ReadKey();
This MSDN article explains how to read characters one at a time in a console window. Test each character as it is input with the Char.IsNumber() method, and reject those characters that fail the test.
In a while, I got a solution really short:
double number;
Console.Write("Enter the cost of the item: ");
while (!double.TryParse(Console.ReadLine(), out number))
{
Console.Write("This is not valid input. Please enter an integer value: ");
}
Console.Write("The item cost is: {0}", number);
See you!
Here is one approach. It's probably overkill if you're just starting out in C#, since it uses some more advanced aspects of the language. In any case, I hope you find it interesting.
It has some nice features:
The ReadKeys method takes an arbitrary function for testing whether the string so far is valid. This makes it easy to reuse whenever you want filtered input from the keyboard (e.g. letters or numbers but no punctuation).
It should handle anything you throw at it that can be interpreted as a double, e.g. "-123.4E77".
However, unlike John Woo's answer it doesn't handle backspaces.
Here is the code:
using System;
public static class ConsoleExtensions
{
public static void Main()
{
string entry = ConsoleExtensions.ReadKeys(
s => { StringToDouble(s) /* might throw */; return true; });
double result = StringToDouble(entry);
Console.WriteLine();
Console.WriteLine("Result was {0}", result);
}
public static double StringToDouble(string s)
{
try
{
return double.Parse(s);
}
catch (FormatException)
{
// handle trailing E and +/- signs
return double.Parse(s + '0');
}
// anything else will be thrown as an exception
}
public static string ReadKeys(Predicate<string> check)
{
string valid = string.Empty;
while (true)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
{
return valid;
}
bool isValid = false;
char keyChar = key.KeyChar;
string candidate = valid + keyChar;
try
{
isValid = check(candidate);
}
catch (Exception)
{
// if this raises any sort of exception then the key wasn't valid
// one of the rare cases when catching Exception is reasonable
// (since we really don't care what type it was)
}
if (isValid)
{
Console.Write(keyChar);
valid = candidate;
}
}
}
}
You also could implement an IsStringOrDouble function that returns false instead of throwing an exception, but I leave that as an exercise.
Another way this could be extended would be for ReadKeys to take two Predicate<string> parameters: one to determine whether the substring represented the start of a valid entry and one the second to say whether it was complete. In that way we could allow keypresses to contribute, but disallow the Enter key until entry was complete. This would be useful for things like password entry where you want to ensure a certain strength, or for "yes"/"no" entry.
This code will allow you to:
Write only one dot (because numbers can have only one decimal separator);
One minus at the begining;
One zero at the begining.
It means that you not be able to write something like: "00000.5" or "0000...-5".
class Program
{
static string backValue = "";
static double value;
static ConsoleKeyInfo inputKey;
static void Main(string[] args)
{
Console.Title = "";
Console.Write("Enter your value: ");
do
{
inputKey = Console.ReadKey(true);
if (char.IsDigit(inputKey.KeyChar))
{
if (inputKey.KeyChar == '0')
{
if (!backValue.StartsWith("0") || backValue.Contains('.'))
Write();
}
else
Write();
}
if (inputKey.KeyChar == '-' && backValue.Length == 0 ||
inputKey.KeyChar == '.' && !backValue.Contains(inputKey.KeyChar) &&
backValue.Length > 0)
Write();
if (inputKey.Key == ConsoleKey.Backspace && backValue.Length > 0)
{
backValue = backValue.Substring(0, backValue.Length - 1);
Console.Write("\b \b");
}
} while (inputKey.Key != ConsoleKey.Enter); //Loop until Enter key not pressed
if (double.TryParse(backValue, out value))
Console.Write("\n{0}^2 = {1}", value, Math.Pow(value, 2));
Console.ReadKey();
}
static void Write()
{
backValue += inputKey.KeyChar;
Console.Write(inputKey.KeyChar);
}
}
You can do it with a single line code as follows:
int n;
Console.WriteLine("Enter a number: ");
while (!int.TryParse(Console.ReadLine(), out n)) Console.WriteLine("Integers only allowed."); // This line will do the trick
Console.WriteLine($"The number is {n}");
You can change int into double in case you wanted to allow double instead of integers and so on.
string input;
double price;
bool result = false;
while ( result == false )
{
Console.Write ("\n Enter the cost of the item : ");
input = Console.ReadLine ();
result = double.TryParse (input, out price);
if ( result == false )
{
Console.Write ("\n Please Enter Numbers Only.");
}
else
{
Console.Write ("\n cost of the item : {0} \n ", price);
break;
}
}

How to disallow all non-numeric input in console during an input prompt?

Talking console here.
The idea is that if user presses any key except numbers(the ones above the letter keys, and numpad) during an input prompt in the console, then nothing will be typed. Its's as if console will ignore any non-numeric key presses.
How would one do it the right way?
Try the ReadKey method:
while (processing input)
{
ConsoleKeyInfo input_info = Console.ReadKey (true); // true stops echoing
char input = input_info.KeyChar;
if (char.IsDigit (input))
{
Console.Write (input);
// and any processing you may want to do with the input
}
}
private static void Main(string[] args) {
bool inputComplete = false;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
while (!inputComplete ) {
System.ConsoleKeyInfo key = System.Console.ReadKey(true);
if (key.Key == System.ConsoleKey.Enter ) {
inputComplete = true;
}
else if (char.IsDigit(key.KeyChar)) {
sb.Append(key.KeyChar);
System.Console.Write(key.KeyChar.ToString());
}
}
System.Console.WriteLine();
System.Console.WriteLine(sb.ToString() + " was entered");
}
This little experiment works like that:
static void Main()
{
while (true)
{
var key = Console.ReadKey(true);
int i;
if (int.TryParse(key.KeyChar.ToString(), out i))
{
Console.Write(key.KeyChar);
}
}
}

Categories