ShowDialog 跟 vs 有什么关系吗?为什么在在vs打开时,模式窗口关闭后,焦点转到vs上面?

oldhunter 2016-06-03 10:22:40
在主线程中,用 ShowDialog 阻塞线程并显示进度条,然后等 BackgroundWorker 线程完成工作后再关闭进度条窗口,很简单的逻辑,理解不了,为什么进度条窗口关闭后,焦点会转给 vs2005?(如果vs最小化,就不会发生)

static public void DoWork(Work workMethod)
{
//
// 不带参数的工作方法
//
_workMethod = workMethod; // 保存委托到全局变量。
//
// 带参数的工作方法
//
_parameterizedWorkMethod = null; // 设置委托变量为空值,避免被调用。

DoWorkMethod(null);
}

static public object DoWork(ParameterizedWork workMethod, object parameter)
{
//
// 不带参数的工作方法
//
_workMethod = null; // 设置委托变量为空值,避免被调用。
//
// 带参数的工作方法
//
_parameterizedWorkMethod = workMethod; // 保存委托到全局变量。

return DoWorkMethod(parameter);
}

static private object DoWorkMethod(object parameter)
{
//
// 注意,DoWorkMethod 不能叫 DoWork,数字签名与 DoWork(Work workMethod) 重合。
//

if (waitingForm == null)
{
//
// 主窗口失去焦点与 Hide 方法没有关系,与VS有问题。(参考 CloseForm 方法中的注释)
//
waitingForm = new WaitingForm();
}

//
// DoWork 只能由界面主线程调用,不支持多线程并发。
//
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

//
// 开始异步工作
//
worker.RunWorkerAsync(parameter);


waitingForm.ShowDialog();

if (error != null)
{
//
// 由主线程抛出异常
//
throw error;
}

//
// 加载成功,返回结果。
//
return result;
}

static void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (_workMethod != null)
{
//
// 调用“不带参数的工作方法”
//
_workMethod();
}
else
{
//
// 调用“带参数的工作方法”,完成数据加载,并保存返回结果。
//
result = _parameterizedWorkMethod(e.Argument);
}
}

static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
//
// 将异常转递给主线程,由主线程抛出。
//
error = e.Error;
}
else
{
//
// 由于是静态变量,所以没有出错时,要设置为空,避免被抛出。
//
error = null;
}

//
// 关闭登录窗口
//
CloseForm();
}


static private void CloseForm()
{
if (waitingForm.InvokeRequired)
{
waitingForm.BeginInvoke(new MethodInvoker(CloseForm));
}
else
{
waitingForm.Hide(); // 这句执行以后,主窗口的焦点奇怪消失,转给了VS(不知道跟VS2005有毛关系?如果VS是最小化的,就不会发生)
}
}
...全文
271 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
小污云姐姐 2017-03-16
  • 打赏
  • 举报
回复
我也遇到过你这个问题。 后来终于解决了。
  • 打赏
  • 举报
回复
那你应该在dialog关闭的同时,将你的form给show出来,或者应该说是 让你的form获取焦点
Forty2 2016-06-06
  • 打赏
  • 举报
回复
[quote=引用 7 楼 oldhunter 的回复:]
...
直接打开exe也不行:现在发现不是把焦点转给 vs ,而是转给 windows 的上一个活动窗体(当时正好 vs 是活动窗体,所以误以为焦点转给了 vs)
[quote]

试试用ShowDialog(IWin32Window owner)。如果不传owner或owner为null,看源代码会发现它将找当前的活动窗体。

假定this指Form1,你把Form1传入:
List list = WaitingForm.DoWork(this, new ParameterizedWork(GetList_Work), folderID) as List;
然后waitingForm使用传入的form1值作为owner:
waitingForm.ShowDialog(ower);

另:WaitingForm最好不要写成静态类。
oldhunter 2016-06-06
  • 打赏
  • 举报
回复
引用 5 楼 starfd 的回复:
你可以试下直接执行生成的exe,看效果是否符合你的期望,一般来说在vs中调试总是符合我们期望的,但偶尔也会有些意外发生,最典型的就是代码修改config,如果你通过vs执行,你会发现根本就改不了配置,而直接通过exe就可以,究其原因是同样的代码,在vs下和exe下,指向了不同的文件,所以如果你在exe下正确,那也就不要纠结了 另外如果你调试时,在整个showdialog期间都没切换焦点到vs过,那应该不会发生焦点自动给到vs,而是应该在form上
直接打开exe也不行:现在发现不是把焦点转给 vs ,而是转给 windows 的上一个活动窗体(当时正好 vs 是活动窗体,所以误以为焦点转给了 vs) 例如:我正在使用浏览器写这个回复,打开我的程序后,调用 showdialog 后(等待窗口 -> 加载数据 -> 关闭窗口),当前窗口切换到了浏览器进程!
无涯大者 2016-06-04
  • 打赏
  • 举报
回复
5楼兄台说的挺有道理的,直接执行生成的exe
  • 打赏
  • 举报
回复
你可以试下直接执行生成的exe,看效果是否符合你的期望,一般来说在vs中调试总是符合我们期望的,但偶尔也会有些意外发生,最典型的就是代码修改config,如果你通过vs执行,你会发现根本就改不了配置,而直接通过exe就可以,究其原因是同样的代码,在vs下和exe下,指向了不同的文件,所以如果你在exe下正确,那也就不要纠结了 另外如果你调试时,在整个showdialog期间都没切换焦点到vs过,那应该不会发生焦点自动给到vs,而是应该在form上
oldhunter 2016-06-04
  • 打赏
  • 举报
回复
对了,说明一下,这个进度窗口( WaitingForm)只是一个动画效果,并非进度条。封装的目的,主要是方便外部调用。
oldhunter 2016-06-04
  • 打赏
  • 举报
回复
引用 2 楼 sp1234 的回复:
记住。如果你不是真正异步的操作,不要乱学人家玩儿什么“线程”概念。这里的线程对你没意义。
我是封装了一个 Form (进度窗口)和 BackgroundWorker (子线程异步,主线等待),调用时然后传一个 delegate 进去。这样,主要是外部调用时,代码比较简单。 一条语句就可以打开进度窗口,加载数据(传一个 delegate 和 一个object 参数进去): List list = WaitingForm.DoWork(new ParameterizedWork(GetList_Work), folderID) as List; 现在发现不是把焦点转给 vs ,而是转给 windows 的上一个活动窗体(当时正好 vs 是活动窗体,所以误以为焦点转给了 vs) 觉得可能原因出在 windows 消息机制上, 这方面就不太懂了,需要请教各位!也就是说,ShowDialog() 窗体关闭后,焦点为什么会落在另一个进程的窗体上?而为什么不是当前进程的 form?
  • 打赏
  • 举报
回复
记住。如果你不是真正异步的操作,不要乱学人家玩儿什么“线程”概念。这里的线程对你没意义。
  • 打赏
  • 举报
回复
看不懂什么叫做“焦点转给了VS”? 从你的代码上,看不出你的 DoWorkMethod 方法是 UI 线程中被调用的,还是其它子线程中被调用的。很显然对于界面的任何操作(new一个窗体实例并且显示它)应该从UI线程调用。 另外,你写 .ShowDialog() 这个是要干什么啊?如果不想主线程操作,那么你何必要用什么 BackgroundWorker?直接在主线程中用你的有用的那点代码来操作、它自然就卡死了主线程了,它可以直接操作 waitingForm 窗口。何必要写 ShowDialog() ? 你的代码的大部分,都是多余、无用的代码。线程概念让你混乱了,你用异步线程的语法写了模拟同步执行的代码,你额外地用子线程的东西不但让程序更慢、而且更乱。

111,128

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧