【问题标题】:Need help getting threading working in a WinForm需要帮助让线程在 WinForm 中工作
【发布时间】:2012-03-19 23:02:02
【问题描述】:

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

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

这是我用于搜索蓝牙设备的代码。在代码中,我有两个 BindingList。一个是 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();
    }

当我在上面的代码中取消注释线程时,它什么也不做,也没有找到设备。在我注释掉线程后,它可以工作。有谁知道原因?我想以与正在搜索的设备相同的形式执行其他操作。

【问题讨论】:

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


    【解决方案1】:

    看看使用BackgroundWorker线程:

    MSDN - BackgroundWorker

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

    在您的情况下,我将创建一个 BackgroundWorker,将您上面的大部分代码放入填充列表的 DoWork 方法中,然后在 RunWorkerCompleted 方法中将您的“列表”绑定到您的用户控件。

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

    【讨论】:

    • 但在 Compact Framework 中,它没有 Backgroundworker。还有其他选择吗?
    • 是的,FindMeMyBluetoothDevices() 访问模型层以获取可发现的设备。在模型中,我有 BluetoothAccess 类,它将在那里完成所有蓝牙工作。
    • @CharlesLAU 您应该编辑原始问题,而不是新答案。其次,我上面提到的关于多线程技巧的链接显示了如何从线程内更新 UI 控件的示例。您遇到的问题是您在尝试访问某些 UI 控件的线程中。如果没有“MethodInvoker”,您基本上需要根据链接将对 UI 的调用包装在 Control.Invoke 中。您可能必须删除“BindingList”,然后将列表直接添加到 UI 控件(在 Invoke 下)。
    【解决方案2】:

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

    两个选项是:

    1) 按照 BradRem 的回答使用 BackgroundWorker。

    2) 任何时候访问 UI 控件和修改绑定到控件的 BindingList 时都调用 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();
    }
    

    【讨论】:

    • 我无法访问新的 MethodInoker
    • 在应用程序中,我使用MVC模型。在上面的代码中,我将它们放在了控制器层,如何在控制器层使用“this.Invoke(...)”来更新UI控件。我只能在课堂上使用线程。因此,当 DiscoverableDevice 或 ConnectedSEMDevices 绑定列表更新时,它将调用其接口将它们传递给视图。我通过接口访问视图,我不直接在控制器层类中访问表单。任何的想法?提前致谢。
    • 向您的 IView 界面添加一个方法 - void Invoke(Action action)。将其传递给您的控制器。所以在你的控制器中,你调用:view.Invoke(...做你的绑定列表的东西...)。因此,实现 IView 的控件或表单已经有了该方法。只需调用操作即可实现测试中的模拟视图。
    • 我刚刚试过你的方法,但是当我运行代码时,它会自动停止调试。不知道为什么
    • 在线程代码周围放置一个 try/catch 并中断任何异常?
    猜你喜欢
    • 2017-09-22
    • 2015-02-11
    • 2011-02-25
    • 1970-01-01
    • 2014-10-10
    • 2021-08-08
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多