【求教】WPF 按钮响应函数处理时间长,多次点击如何取消后续事件?

willbetrue 2012-04-25 09:11:35
我有一个WPF的程序,按钮的单击响应函数的执行需要2秒以上的时间。在测试的时候发现,如果连续单击了两次按钮,那么这个函数就会执行两次,而不像Win32里面的那样,函数没有执行完之前是不会再次发出单击消息的。这个特性正是我不需要的。
如果我想在按钮响应函数执行完毕之前的所有单击事件都取消掉,就像Win32里面一样,函数执行完毕之前,不再发出单击消息的话,该如何处理?

我曾尝试过,在函数执行之前,Disable按钮,退出之前Enable按钮,依然解决不了问题。
...全文
798 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
sorn990 2013-03-22
  • 打赏
  • 举报
回复
试一试 按钮名.Click-=响应事件;
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
绝对没有多次添加,因为这是XAML里面自动生成的,不是手动添加的。
[Quote=引用 18 楼 的回复:]

这跟单线程都多线程没什么关系。
bool processing;
void 响应函数(object sender, RoutedEventArgs e)
{
if(processing == true) return;
try
{
processing = true;
//执行需要2秒以上
}
finally
{
……
[/Quote]
cheng2005 2012-04-25
  • 打赏
  • 举报
回复
在Thread.Sleep(2000);的期间UI是卡住的,你点击是不会有反应的。
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
我刚新建了一个WPF工程,拖进去一个按钮原始的WPF按钮,重新敲了一遍代码:
int i = 0;
private void button1_Click(...)
{
i++;
button1.Content = i.ToString();
Thread.Sleep(2000);
}
问题依旧。按理说,.net的目的就是在任何机器上运行都一致,这下麻烦了。
顺便问一下,你的处理器是几个核心的?装过VS2010 SP1没有?
我的是双核的,装了VS2010 SP1

[Quote=引用 14 楼 的回复:]

我想知道你的按钮是不是微软提供的原始按钮控件,如果被二次封装过了,就有可能出现问题。
我是基于最干净的WPF项目,最原始的微软WPF按钮来测试的,请确保测试条件一致。
[/Quote]
cheng2005 2012-04-25
  • 打赏
  • 举报
回复
这跟单线程都多线程没什么关系。
bool processing;
void 响应函数(object sender, RoutedEventArgs e)
{
if(processing == true) return;
try
{
processing = true;
//执行需要2秒以上
}
finally
{
processing = false;
}
}
不考虑多线程的话这是一个很简单的锁,不是同时触发的话应该不会多次进入。
唯一的可能就是你事件添加了多次。
bwangel 2012-04-25
  • 打赏
  • 举报
回复
在winform里, disable之后要update一次才会生效。因为你全部是单线程执行,界面会卡住。
wpf时我没发现类似的方法。但感觉耗时操作,肯定要用多线程:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
label1.Content = i.ToString();
}

int i = 0;
private void button1_Click(object sender, RoutedEventArgs e)
{
button1.IsEnabled = false;

Thread thread = new Thread(new ThreadStart(delegate()
{
Thread.Sleep(2000);
this.Dispatcher.Invoke(new Action(() =>
{
button1.IsEnabled = true;
}));
}));

thread.Start();

label1.Content = (++i).ToString();
}
}
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
晕,是我太心急了,因为后面的事件要等好几秒才会开始执行,因此先出现了1,之后的没等出来就关闭了。
下面给出解决方案:

public class WpfApplication
{
private static DispatcherOperationCallback exitFrameCallback = new DispatcherOperationCallback(ExitFrame);

public static void DoEvents()
{
DispatcherFrame nestedFrame = new DispatcherFrame();
DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, exitFrameCallback, nestedFrame);

Dispatcher.PushFrame(nestedFrame);
if (exitOperation.Status != DispatcherOperationStatus.Completed)
{
exitOperation.Abort();
}
}

private static Object ExitFrame(Object state)
{
DispatcherFrame frame = state as DispatcherFrame;
frame.Continue = false;
return null;
}
}


private void button_Click(object sender, RoutedEventArgs e)
{
button.IsEnabled = false;
WpfApplication.DoEvents();
i++;
button.Content = i.ToString();
System.Threading.Thread.Sleep(2000);
button.IsEnabled = true;
}

添加WpfApplication.DoEvents();来让按钮灰化得以立刻执行,否则你禁用按钮是要在整个事件结束后才会响应,那样就没有意义了。
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
我的天哪,难道哪里配置错误了吗?我的怎么点几次就是几呢?
你能不能把你的项目文件发给我看一下,我对比一下哪里有问题?
WinForm的使用的还是Win32的消息循环,我知道是没问题的。但是我的WPF就有问题,唉。

[Quote=引用 13 楼 的回复:]

当然是WPF了,按钮点击事件里的RoutedEventArgs 参数,也只有WPF里面才有,你看到它还不知道吗?
[/Quote]
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
我想知道你的按钮是不是微软提供的原始按钮控件,如果被二次封装过了,就有可能出现问题。
我是基于最干净的WPF项目,最原始的微软WPF按钮来测试的,请确保测试条件一致。
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
当然是WPF了,按钮点击事件里的RoutedEventArgs 参数,也只有WPF里面才有,你看到它还不知道吗?
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
我的是WPF的应用程序,不会添加两次事件处理函数的。
的确是点几次就是几。

[Quote=引用 10 楼 的回复:]

我建议你检测下是否有地方添加了2次这个事件处理函数,或者由于事件传递设置错误,导致被执行了2次。如果是由于点击多次造成的,那么你做个测试,连点3下,看看会不会显示3.
[/Quote]
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
你的是WPF应用程序,还是WinForm的?

[Quote=引用 9 楼 的回复:]

引用 8 楼 的回复:

你这么试一下:
int i = 0;
private void button_Click(...)
{
i++;
button.Content = i.ToString();
Thread.Sleep(2000);
}
然后双击一下,i的值就变成2了。我用的是VS2010

我试过了,疯狂点击按钮,显示的值还是1。我用的也是VS2010
[/Quote]
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
我建议你检测下是否有地方添加了2次这个事件处理函数,或者由于事件传递设置错误,导致被执行了2次。如果是由于点击多次造成的,那么你做个测试,连点3下,看看会不会显示3.
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

你这么试一下:
int i = 0;
private void button_Click(...)
{
i++;
button.Content = i.ToString();
Thread.Sleep(2000);
}
然后双击一下,i的值就变成2了。我用的是VS2010
[/Quote]
我试过了,疯狂点击按钮,显示的值还是1。我用的也是VS2010
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
你这么试一下:
int i = 0;
private void button_Click(...)
{
i++;
button.Content = i.ToString();
Thread.Sleep(2000);
}
然后双击一下,i的值就变成2了。我用的是VS2010

[Quote=引用 5 楼 的回复:]

我刚测试了下,直接按钮里面延迟2秒,然后输出一个消息,连续点击按钮,没有执行2次的情况,代码如下:
C# code

private void button_Click(object sender, RoutedEventArgs e)
{
System.Threading.Thread.Sleep(2000);
……
[/Quote]
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
帅哥,已经看的很明白了。这种处理方式,只在多线程的时候部分有效。而目前的情况下是WPF的消息系统在发完一个事件之后,又重新发了一个,都在一个线程中,顺序处理的,怎么可能解决问题?

[Quote=引用 6 楼 的回复:]

楼主究竟看懂了1楼的代码了吗?
[/Quote]
cheng2005 2012-04-25
  • 打赏
  • 举报
回复
楼主究竟看懂了1楼的代码了吗?
qldsrx 2012-04-25
  • 打赏
  • 举报
回复
我刚测试了下,直接按钮里面延迟2秒,然后输出一个消息,连续点击按钮,没有执行2次的情况,代码如下:

private void button_Click(object sender, RoutedEventArgs e)
{
System.Threading.Thread.Sleep(2000);
MessageBox.Show("M");
}


另外按钮灰化是有效的,要设置IsEnabled属性为false。
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
这样是不可以的。因为响应Click事件的函数实在界面线程里面执行的,所以是单线程的。
也许是我有个地方没有说清楚。
我只是想让响应函数执行完毕之前得所有点击都无效,也就是那些重复的点击。一旦函数执行完毕之后,后续的点击还是要执行这个函数的。只是屏蔽函数执行过程中的点击事件。

[Quote=引用 1 楼 的回复:]

C# code

bool processing;
void 响应函数(object sender, RoutedEventArgs e)
{
if(processing == true) return;
try
{
processing = true;
//执行需要2秒以上
}
finally
{
processing ……
[/Quote]
willbetrue 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

在函数执行之前,Disable按钮,退出之前Enable按钮不行?
[/Quote]
是的。
加载更多回复(3)

111,126

社区成员

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

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

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