Я пытаюсь сделать нажатие Q, чтобы выйти из окна консоли. Мне не нравится моя текущая реализация. Есть ли способ, которым я могу асинхронно или использовать обратный вызов для получения ключей из консоли?Консоль ReadKey async или обратный вызов?
ответ
Вы можете позвонить Console.ReadKey()
из другого потока, чтобы он не блокировал основной поток. (Вы можете использовать .Net 4 Task
или старый Thread
, чтобы начать новую нить.)
class Program
{
static volatile bool exit = false;
static void Main()
{
Task.Factory.StartNew(() =>
{
while (Console.ReadKey().Key != ConsoleKey.Q) ;
exit = true;
});
while (!exit)
{
// Do stuff
}
}
}
Thats actially, что я делаю (ну, ReadKey часть на DIF нити). Эта фабрика задач выглядит круто. Проблема с моим кодом прямо сейчас .ReadKey, кажется, не возвращается, если я не заставляю окно фокусироваться. Поэтому почему мне не нравится мое решение. Когда основная нить заканчивается, другой поток все еще заблокирован. Ваше решение выглядит круто, возможно, потоки задач будут умирать, когда основной будет. В этом случае это должно работать, однако ATM. Это приложение только для 3.5. – 2010-08-01 15:41:31
Избегайте потока с помощью Console.KeyAvailable. –
Если вы хотите, чтобы «Thread» остановился при завершении основного потока, просто установите 'Thread.IsBackground' в' true'. – svick
Вы можете использовать KeyAvailable свойство (Framework 2.0):
if (System.Console.KeyAvailable)
{
ConsoleKeyInfo key = System.Console.ReadKey(true);//true don't print char on console
if (key.Key == ConsoleKey.Q)
{
//Do something
}
}
я не нашел любой из существующих ответов вполне удовлетворительный, поэтому я написал свои собственные, чтобы работать с TAP и .Net 4.5.
/// <summary>
/// Obtains the next character or function key pressed by the user
/// asynchronously. The pressed key is displayed in the console window.
/// </summary>
/// <param name="cancellationToken">
/// The cancellation token that can be used to cancel the read.
/// </param>
/// <param name="responsiveness">
/// The number of milliseconds to wait between polling the
/// <see cref="Console.KeyAvailable"/> property.
/// </param>
/// <returns>Information describing what key was pressed.</returns>
/// <exception cref="TaskCanceledException">
/// Thrown when the read is cancelled by the user input (Ctrl+C etc.)
/// or when cancellation is signalled via
/// the passed <paramred name="cancellationToken"/>.
/// </exception>
public static async Task<ConsoleKeyInfo> ReadKeyAsync(
CancellationToken cancellationToken,
int responsiveness = 100)
{
var cancelPressed = false;
var cancelWatcher = new ConsoleCancelEventHandler(
(sender, args) => { cancelPressed = true; });
Console.CancelKeyPress += cancelWatcher;
try
{
while (!cancelPressed && !cancellationToken.IsCancellationRequested)
{
if (Console.KeyAvailable)
{
return Console.ReadKey();
}
await Task.Delay(
responsiveness,
cancellationToken);
}
if (cancelPressed)
{
throw new TaskCanceledException(
"Readkey canceled by user input.");
}
throw new TaskCanceledException();
}
finally
{
Console.CancelKeyPress -= cancelWatcher;
}
}
Забрав из всех ответов здесь, это моя версия:
public class KeyHandler
{
public event EventHandler KeyEvent;
public void WaitForExit()
{
bool exit = false;
do
{
var key = Console.ReadKey(true); //blocks until key event
switch (key.Key)
{
case ConsoleKey.Q:
exit = true;
break;
case ConsoleKey.T:
// raise a custom event eg: Increase throttle
break;
}
}
while (!exit);
}
}
static void Main(string[] args)
{
var worker = new MyEventDrivenClassThatDoesCoolStuffByItself();
worker.Start();
var keyHandler = new KeyHandler();
keyHandler.KeyEvent+= keyHandler_KeyEvent; // modify properties of your worker
keyHandler.WaitForExit();
}
- Он не требует Main, чтобы сделать что-нибудь в цикле, что позволяет просто организовать между клавишами обработки и манипулируя свойствами рабочего класса.
- Принимая подсказку с @Hans, KeyHandler не нуждается в асинхронизации нового потока, поскольку Console.ReadKey блокируется до тех пор, пока не будет получен ключ.
Вот реализация, которую я создал с помощью KeyAvailable
. Это приводит к появлению подсказки в нижней части окна консоли, а все, что напечатано на консоли, начинается сверху.
public class Program
{
private static int consoleLine;
private static int consolePromptLine;
private static bool exit;
static string clearLine = new string(' ', Console.BufferWidth - 1);
public static void Main(string[] args)
{
StringBuilder commandCapture = new StringBuilder(10);
string promptArea = "Command> ";
consolePromptLine = Console.WindowTop + Console.WindowHeight - 1;
ClearLine(consolePromptLine);
Console.Write(promptArea);
while (!exit)
{
// Do other stuff
// Process input
if (Console.KeyAvailable)
{
var character = Console.ReadKey(true);
if (character.Key == ConsoleKey.Enter)
{
if (commandCapture.Length != 0)
{
ProcessCommand(commandCapture.ToString());
commandCapture.Clear();
ClearLine(consolePromptLine);
Console.Write(promptArea);
}
}
else
{
if (character.Key == ConsoleKey.Backspace)
{
if (commandCapture.Length != 0)
{
commandCapture.Remove(commandCapture.Length - 1, 1);
ClearLine(consolePromptLine);
Console.Write(promptArea);
Console.Write(commandCapture.ToString());
}
}
else
{
commandCapture.Append(character.KeyChar);
Console.SetCursorPosition(0, consolePromptLine);
Console.Write(promptArea);
Console.Write(commandCapture.ToString());
}
}
}
}
}
private static void ProcessCommand(string command)
{
if (command == "start")
{
Task<string> testTask = new Task<string>(() => { System.Threading.Thread.Sleep(4000); return "Test Complete"; });
testTask.ContinueWith((t) => { Print(t.Result); }, TaskContinuationOptions.ExecuteSynchronously);
testTask.Start();
}
else if (command == "quit")
{
exit = true;
}
Print(command);
consolePromptLine = Console.WindowTop + Console.WindowHeight - 1;
}
public static void Print(string text)
{
ClearLine(consoleLine);
Console.WriteLine(text);
consoleLine = Console.CursorTop;
}
public static void ClearLine(int line)
{
Console.SetCursorPosition(0, line);
Console.Write(clearLine);
Console.SetCursorPosition(0, line);
}
}
- 1. Консоль ReadKey таймаут
- 2. NodeJS получает возвращаемое значение async (обратный вызов)
- 3. callback() или обратный обратный вызов()
- 4. Обратный вызов «Inject» с async/await
- 5. Обратный вызов из Async в библиотеке функций
- 6. Javascript Async параллельно вызывает несвязанный обратный вызов
- 7. Функция Async Waterfall вызывает только обратный вызов
- 8. Обратный вызов после async Метод задачи
- 9. Node.js Async только делает один обратный вызов
- 10. nodejs async как установить обратный вызов
- 11. async дает обратный вызов уже называется ошибкой?
- 12. NodeJS async большой обратный вызов набора данных
- 13. Обратный вызов с async и ожидание
- 14. Когда использовать обратный или обратный вызов?
- 15. require.js прослушиватель или обратный вызов
- 16. Почему обратный вызов валидатора async не будет иметь контекст компонента?
- 17. Множественный вызов Async Ajax
- 18. Обратный вызов Javascript XmlHttpRequest
- 19. «Консоль» не содержит определения «ReadKey» в asp.net 5 console App
- 20. Выполнять обратный вызов после завершения всех задач async в forEach
- 21. Пользовательский обратный вызов Resty-GWT при запуске и окончании async
- 22. Node.js Обратный вызов Async waterfall() уже был вызван
- 23. множественный обратный вызов в async в узле js
- 24. Async ждет и GetAwaiter(). GetResult() и обратный вызов
- 25. Функция Async - обратный вызов с использованием объекта, принадлежащего основному потоку
- 26. Как передать объект состояния/данные в асинхронный обратный вызов (async)?
- 27. Почему мой обратный вызов async работает в одном потоке?
- 28. Как сделать обратный вызов ждать завершения async C#
- 29. Использование угловой службы для async HttpRequests - как обратный вызов?
- 30. Nodejs async вызывает обратный вызов дренажа до завершения
Показать нам codez – Oded