需要帮助让线程在WinForm中工作

时间:2012-03-19 23:02:03

标签: c# winforms .net-3.5 thread-safety

在我的智能设备应用程序中,我有搜索所有可发现的蓝牙设备并使用Windows Mobile 6.5连接到设备的功能。当我按下按钮搜索蓝牙设备时,UI冻结,我无法做任何其他事情。在找到所有可发现的设备之后,UI再次响应。

我知道我应该使用线程来处理这个问题。但是,我没有成功地让它发挥作用。

这是我用于搜索蓝牙设备的代码。在代码中,我有两个BindingLists。一个是DiscoverableDevices,另一个是ConnectedSEMDevices,它们分别绑定到一个列表框和一个组合框。

    private void SearchBTDevices()
    {
     // Thread thread = new Thread(new ThreadStart(delegate{
        List<BluetoothDevice> list = new List<BluetoothDevice>();
        this.discoverableDevices.Clear();  //DiscoverableDevices is binding to the form
        list.foreach(x => this.Discoverable.Add(x));
        ConnectedSEMDevices.Clear()
        list.Where(x => x.HasAuthenticated).ToList().ForEach(x => ConnectedSEMDevices.Add(x));  // ConnectedSEMDevices is binding to the Form
     // }));
     // thread.Start();
    }

当我在上面的代码中取消注释掉线程时,它没有做任何事情,也没有找到任何设备。在我评论出该帖子之后,它就有效了。有谁知道原因?我想以与搜索设备相同的形式做其他事情。

2 个答案:

答案 0 :(得分:5)

看一下使用BackgroundWorker线程:

MSDN - BackgroundWorker

我怀疑您遇到的问题是,在您创建的主题中,您正试图将结果立即绑定到UI控件。基本上,当您创建这样的线程时,不允许与任何UI元素通信,因为它们位于不同的线程上。

在您的情况下,我将创建一个BackgroundWorker,将上面的大部分代码放在DoWork方法中,该方法填充您的列表,然后在RunWorkerCompleted方法中绑定您的&#39; Lists&lt;&gt;&#39;到您的用户控件。

Compact Framework 3.5的更新:

您仅限于使用Thread.Start和Timer进行线程处理:

Threading in Compact Framework

这似乎更像你要做的事情:

Microsoft .NET Compact Framework Multi-threading Tips

在这种情况下,我会回到你正在做的事情。我对你的代码片段感到担心的是,似乎没有一个方法调用实际上有你的蓝牙设备的方法。这是我要开始的地方:

private void SearchBTDevices()
{
    Thread thread = new Thread(new ThreadStart(delegate
    {
        List<BluetoothDevice> list = new List<BluetoothDevice>();

        // isn't there some method you have that populates your List<BluetoothDevices>????
        list = FindMeMyBluetoothDevices();

        this.Invoke(new MethodInvoker(() => 
        {
            this.discoverableDevices.Clear();
            list.ForEach(x => this.discoverableDevices.Add(x)); 
        }));

        this.Invoke(new MethodInvoker(() => 
        {
            ConnectedSEMDevices.Clear();
            list.Where(x => x.HasAuthenticated).ToList().ForEach(x => ConnectedSEMDevices.Add(x)); 
        }));
    }));

    thread.Start();
} 

答案 1 :(得分:0)

BindingLists修改后立即引发事件。如果您将它们绑定到控件,那么将通知这些控件,但是在错误的线程上。

有两个选项:

1)根据BradRem的回答使用BackgroundWorker。

2)只要您修改绑定到控件的BindingList,就可以在任何时候访问UI控件时调用Invoke

 private void SearchBTDevices()
    {
      Thread thread = new Thread(new ThreadStart(delegate{
        List<BluetoothDevice> list = new List<BluetoothDevice>();
        this.Invoke(new MethodInvoker(() => this.discoverableDevices.Clear()); //DiscoverableDevices is binding to the form
        list.foreach(x => this.Discoverable.Add(x));

        var connectedDevices = list.Where(x => x.HasAuthenticated).ToList());  
        this.Invoke(new MethodInvoker(() => {
            ConnectedSEMDevices.Clear()
            ConnectedSEMDevices.AddRange(connectedDevices)));}
        }
      }));
  thread.Start();
}