我有一个WPF的程序,按钮的单击响应函数的执行需要2秒以上的时间。在测试的时候发现,如果连续单击了两次按钮,那么这个函数就会执行两次,而不像Win32里面的那样,函数没有执行完之前是不会再次发出单击消息的。这个特性正是我不需要的。
如果我想在按钮响应函数执行完毕之前的所有单击事件都取消掉,就像Win32里面一样,函数执行完毕之前,不再发出单击消息的话,该如何处理?我曾尝试过,在函数执行之前,Disable按钮,退出之前Enable按钮,依然解决不了问题。

解决方案 »

  1.   


    bool processing;
    void 响应函数(object sender, RoutedEventArgs e)
    {
       if(processing == true) return;
       try
       {
          processing = true;
          //执行需要2秒以上
       }
       finally
       {
          processing = false;
       }
    }
      

  2.   

    在函数执行之前,Disable按钮,退出之前Enable按钮不行?
      

  3.   

    这样是不可以的。因为响应Click事件的函数实在界面线程里面执行的,所以是单线程的。
    也许是我有个地方没有说清楚。
    我只是想让响应函数执行完毕之前得所有点击都无效,也就是那些重复的点击。一旦函数执行完毕之后,后续的点击还是要执行这个函数的。只是屏蔽函数执行过程中的点击事件。
      

  4.   

    我刚测试了下,直接按钮里面延迟2秒,然后输出一个消息,连续点击按钮,没有执行2次的情况,代码如下:        private void button_Click(object sender, RoutedEventArgs e)
            {
                System.Threading.Thread.Sleep(2000);
                MessageBox.Show("M");
            }
    另外按钮灰化是有效的,要设置IsEnabled属性为false。
      

  5.   

    帅哥,已经看的很明白了。这种处理方式,只在多线程的时候部分有效。而目前的情况下是WPF的消息系统在发完一个事件之后,又重新发了一个,都在一个线程中,顺序处理的,怎么可能解决问题?
      

  6.   

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

  7.   

    你的是WPF应用程序,还是WinForm的?
      

  8.   

    我的是WPF的应用程序,不会添加两次事件处理函数的。
    的确是点几次就是几。
      

  9.   

    当然是WPF了,按钮点击事件里的RoutedEventArgs 参数,也只有WPF里面才有,你看到它还不知道吗?
      

  10.   

    我想知道你的按钮是不是微软提供的原始按钮控件,如果被二次封装过了,就有可能出现问题。
    我是基于最干净的WPF项目,最原始的微软WPF按钮来测试的,请确保测试条件一致。
      

  11.   

    我的天哪,难道哪里配置错误了吗?我的怎么点几次就是几呢?
    你能不能把你的项目文件发给我看一下,我对比一下哪里有问题?
    WinForm的使用的还是Win32的消息循环,我知道是没问题的。但是我的WPF就有问题,唉。
      

  12.   

    晕,是我太心急了,因为后面的事件要等好几秒才会开始执行,因此先出现了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();来让按钮灰化得以立刻执行,否则你禁用按钮是要在整个事件结束后才会响应,那样就没有意义了。
      

  13.   

    在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();
            }
        }
      

  14.   

    这跟单线程都多线程没什么关系。
    bool processing;
    void 响应函数(object sender, RoutedEventArgs e)
    {
       if(processing == true) return;
       try
       {
          processing = true;
          //执行需要2秒以上
       }
       finally
       {
          processing = false;
       }
    }
    不考虑多线程的话这是一个很简单的锁,不是同时触发的话应该不会多次进入。
    唯一的可能就是你事件添加了多次。
      

  15.   

    我刚新建了一个WPF工程,拖进去一个按钮原始的WPF按钮,重新敲了一遍代码:
    int i = 0;
    private void button1_Click(...)
    {
      i++;
      button1.Content = i.ToString();
      Thread.Sleep(2000);
    }
    问题依旧。按理说,.net的目的就是在任何机器上运行都一致,这下麻烦了。
    顺便问一下,你的处理器是几个核心的?装过VS2010 SP1没有?
    我的是双核的,装了VS2010 SP1
      

  16.   

    在Thread.Sleep(2000);的期间UI是卡住的,你点击是不会有反应的。
      

  17.   

    绝对没有多次添加,因为这是XAML里面自动生成的,不是手动添加的。
      

  18.   

    试一试
    按钮名.Click-=响应事件;