我必须在wpf中做一些用户行为回放。我让用户运行程序,然后我将文件写入我感兴趣的事件。现在我需要重新读取这些事件,然后让计算机以现实的方式调用它们(确切的时间不是重要)。我知道UI是变幻无常的,你必须担心线程所有权,但是,我通常使用Dispatcher
。这一次,它不起作用。
我有一个全局定义的文本框:
TextBox fromBox;
然后放在构造函数中:( myGrid是Canvas)
fromBox = textBoxFactory(260, 36, 244);
fromBox.GotFocus += fromBox_GotFocus;
fromBox.LostFocus += textBox_LostFocus;
fromBox.TextChanged += fromBox_TextChanged;
fromBox.Tag = "From TextBox";
myGrid.Children.Add(fromBox);
我的模拟鼠标点击的代码:
public static void LeftMouseClick(int xpos, int ypos)
{
//Random rand = new Random(Environment.TickCount);
double scale = 1.25;
SetCursorPos((int)(xpos * scale), (int)(ypos * scale));
mouse_event(MOUSEEVENTF_LEFTDOWN, (int)(xpos * scale), (int)(ypos * scale), 0, 0);
Thread.Sleep(200);
mouse_event(MOUSEEVENTF_LEFTUP, (int)(xpos * scale), (int)(ypos * scale), 0, 0);
}
现在,在测试中,我知道这一行可以创建一个能够成功激活文本框的事件。
Dispatcher.BeginInvoke(new Action(() => LeftMouseClick(200, 200)));
但是,在我的播放中,它会抛出一个InvalidOperationException
,因为该线程不拥有它。
播放时,我初始化一个计时器:
System.Timers.Timer viz = new System.Timers.Timer(30);
viz.Elapsed += viz_Elapsed;
viz.AutoReset = true;
viz.Enabled = true;
然后是经过的方法:
void viz_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (indexer >= readText.Length) {
((System.Timers.Timer)sender).AutoReset = false;
return;
}
String line = readText[indexer];
string[] tokens = line.Split(':');
if (tokens[4].Equals("Gaze"))
{
int x = Int32.Parse(tokens[5]);
int y = Int32.Parse(tokens[6]);
Dispatcher.BeginInvoke(new Action(() => UpdateUI(x, y)));
}
else if (tokens[4].Equals("FromBox"))
{
if (tokens[5].Equals("Focus")) {
Dispatcher.BeginInvoke(new Action(() => LeftMouseClick(200, 200)));
}
else if (tokens[5].Equals("TextChanged"))
{
Dispatcher.BeginInvoke(new Action(() =>fromBox.Text = tokens[6]));
}
}
else
{
Console.WriteLine(tokens);
}
indexer++;
}
最终将动态读取数字。这纯粹是概念代码的证明。用于更改文本的行有效,用于聚焦文本框的行则不然。为什么Dispatcher
在这种情况下不起作用,会发生什么?
答案 0 :(得分:0)
更新:答案的目的是避免访问文本框,无论操作如何。使用共享ViewModel来回传递状态操作的MVVM模型应该在非概念验证应用程序的下一次运行时考虑。
全局定义了一个文本框:
可以全局访问它,但文本框的性质仅限于GUI线程。
即使是读操作也会导致失败,因为文本框是在GUI线程上创建的。遗憾的是,并非所有内容都已被隔离,即使发送了该过程,文本框的重点也会导致问题。
如果将操作更改为View Model上的标志设置(或任何具有INotifyPropertyChanged的共享资源)并绑定到通过样式设置(?)会更好地关注文本框,那会更好。
我遇到了类似情况并在我的博客文章C# WPF: Linq Fails in BackgroundWorker DoWork Event上记录了它。