我尝试使用C#WPF创建一个应用来模拟Windows'命令提示符,但具有更多的灵活性和输出选项(如显示图像或表单)。我最近一直试图模拟Console.ReadLine()
。我需要保持GUI完全响应,允许用户输入输入。与此同时,我需要能够return
使用相同的方法得到答案。
我试图通过使用事件来解决这个问题,但我无法弄清楚如何以不会返回void
的方式使用它们。我查看了async
/ await
和question about it,但无法弄清楚如何使用该信息。我考虑了一个事件驱动的解决方案,其中结果将存储在所有输入的永久列表变量中,我可以读取最后一个以获取最新输入,但我认为它不足以满足我的需求。 #39; m模拟。
我计划在应用程序启动后立即在主线程中创建控制台GUI。但是,我将在另一个线程中使用逻辑,这将是我的代码的核心(我知道它不是一个专业的编程方式,但毕竟这是个人项目/学习经验。)然后,我想使用某种自定义ReadLine()
方法等待用户提交文本,然后返回它。如果可以,那怎么能在WPF中完成?
答案 0 :(得分:0)
以下是我认为可以做到的事情:
public class MyConsole
{
private readonly BlockingCollection<string> m_Lines = new BlockingCollection<string>();
public string ReadLine()
{
return m_Lines.Take();
}
private void AddNewLine(string new_line)
{
m_Lines.Add(new_line);
}
//...
}
AddNewLine方法是一种私有方法,当用户写入内容并命中输入时,您必须调用该方法。这发生在GUI线程中。
ReadLine方法是一个公共方法,您的其他线程将调用该方法来获取新行。
请注意,此调用将返回存储的项目(如果有),或者它将等待AddNewLine方法添加新项目。此阻塞是BlockingCollection类的一个功能。
答案 1 :(得分:0)
以下快速而肮脏的代码应该可以让您了解如何实现您的目标:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
var console = new MyConsole();
this.Content = console.Gui;
Task.Factory.StartNew(() => {
var read = console.ReadLine();
console.WriteLine(read);
});
}
}
public class MyConsole {
private readonly ManualResetEvent _readLineSignal;
private string _lastLine;
public MyConsole() {
_readLineSignal = new ManualResetEvent(false);
Gui = new TextBox();
Gui.AcceptsReturn = true;
Gui.KeyUp += OnKeyUp;
}
private void OnKeyUp(object sender, KeyEventArgs e) {
// this is always fired on UI thread
if (e.Key == Key.Enter) {
// quick and dirty, but that is not relevant to your question
_lastLine = Gui.Text.Split(new string[] { "\r\n"}, StringSplitOptions.RemoveEmptyEntries).Last();
// now, when you detected that user typed a line, set signal
_readLineSignal.Set();
}
}
public TextBox Gui { get; private set;}
public string ReadLine() {
// that should always be called from non-ui thread
if (Gui.Dispatcher.CheckAccess())
throw new Exception("Cannot be called on UI thread");
// reset signal
_readLineSignal.Reset();
// wait until signal is set. This call is blocking, but since we are on non-ui thread - there is no problem with that
_readLineSignal.WaitOne();
// we got signalled - return line user typed.
return _lastLine;
}
public void WriteLine(string line) {
if (!Gui.Dispatcher.CheckAccess()) {
Gui.Dispatcher.Invoke(new Action(() => WriteLine(line)));
return;
}
Gui.Text += line + Environment.NewLine;
}
}