2017-05-30 250 views
0

林有一点麻烦,在我的列表框中显示的列表。 当我在一堂课中学到了所有东西的时候,事情似乎很顺利,但我无法弄清楚它为什么现在不起作用。当我点击扫描按钮时,我的应用程序会转到另一个类,其中有一个新线程用于扫描可用的蓝牙设备,并创建一个包含这些设备的列表。一旦列表传递回Form1类中的方法,它不会更新列表框。在调试模式下,我可以看到列表中有项目,但列表框中没有任何内容。如果我通过扫描按钮单击方法执行listBox1.Items.Add(“Hello World”),列表框将显示项目。我有点卡在这里。我刚开始学习C#,如果有人能帮助我,将不胜感激。无法填充列表框

public partial class Form1 : Form 
{ 
    int PanelWidth; 
    bool PanelCalShow; 

    public Form1() 
    { 
     InitializeComponent(); 
     PanelWidth = PanelCal.Width; 
     PanelCalShow = false;   
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     timer1.Start(); 
    } 

    private void timer1_Tick(object sender, EventArgs e) 
    { 
     if (PanelCalShow) 
     { 
      PanelCal.Width = PanelCal.Width + 10; 

      if (PanelCal.Width >= PanelWidth) 
      { 
       timer1.Stop(); 
       PanelCalShow = false; 
       this.Refresh(); 
      } 
     } 
     else 
     { 
      if (PanelCalShow != true) 
      { 
       PanelCal.Width = PanelCal.Width - 10; 

       if (PanelCal.Width <= 0) 
       { 
        timer1.Stop(); 
        PanelCalShow = true; 
        this.Refresh(); 
       } 
      } 
     } 
    } 

    // Bluetooth connection 
    private void BtnScan_Click(object sender, EventArgs e) 
    { 
     var instance = new BtCom(); 
     instance.Scan(); 
    }   

    public void LbClientUpdate(List<string> DiscoveredDevices) 
    {       
     listBox1.DataSource = DiscoveredDevices;    
    }   
} 

和蓝牙连接类

public class BtCom 
{ 
    public List<string> DiscoveredDevices = new List<string>(); 
    Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB"); 

    public void Scan() 
    {    
     Thread bluetoothScanThread = new Thread(new ThreadStart(Scanning)); 
     bluetoothScanThread.Start(); 
    } 

    BluetoothDeviceInfo[] devices; 

    public void Scanning() 
    {    
     var form1 = new Form1(); 

     BluetoothClient client = new BluetoothClient(); 
     devices = client.DiscoverDevicesInRange(); 

     foreach (BluetoothDeviceInfo d in devices) 
     { 
      DiscoveredDevices.Add(d.DeviceName); 
     }   
     form1.LbClientUpdate(DiscoveredDevices); 
    } 
} 
+0

您有一个函数'LbClientUpdate'来设置ListBox的DataSource,但它不会从任何地方调用。 – James

+1

原因是你没有看到原始表单上的任何更新,因为你正在BtCom类中创建一个'Form1'类的新实例,而不是使用原始实例。 –

+0

嗨,对不起。我正在删除评论,并且必须删除评论。在listBox1.DataSource之后,我有一个带有“hello world”的消息框,它弹出时应该像它应该但没有在列表框中。难道是因为该方法是从一个不同的线程调用的,它也在该线程中执行,而据我所知,listbox应该在其原始线程内编辑? – Rikas

回答

0

您没有看到您的原始形态上的任何更新的原因是,你创建BtCom类的内部Form1类的新实例,而不是使用原始实例。

您可以修复此问题的一种方法是将表单的原始实例通过参数传递给您的BtClass,然后将其传递给Scanning方法。这样你就可以在运行的窗体的同一个实例上调用方法。

问题在于,当等待线程完成时(假设您调用bluetoothScanThread.Join()来等待线程结果),您将阻塞您的UI。

稍微不同的解决方案是使用Tasks,async方法await结果。

要做到这一点,你会让你的scan方法返回一个Task<List<string>>(这是一个Task返回代表设备的List<string>)。

然后在form1您可以创建一个async方法(以下称为GetDatasource)创建您的BtCom类的实例,awaitsscan方法,并返回Task<List<string>>

最后,您还可以制作Click方法async,并让它分配等待GetDatasource方法并在返回时指定数据源。

通过这样做,您可以将BtCon类与必须知道有关Form1类的任何详细信息分开,因为您最终创建了更多可重用且独立的代码,所以这是一个很好的习惯。

这里是在代码中所有这些单词的一个例子:

充分利用scan方法返回一个可用于数据源一个Task<List<string>>(并有Scanning返回List<string>)。注意列表现在对扫描方法是私有的。将变量的范围限制在他们所需的级别是一种很好的做法。:

public class BtCom 
{ 
    Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB"); 

    public Task<List<string>> Scan() 
    { 
     var bluetoothScanTask = Task.Factory.StartNew(Scanning); 
     bluetoothScanTask.Wait(); 
     return bluetoothScanTask; 
    } 

    private List<string> Scanning() 
    { 
     BluetoothClient client = new BluetoothClient(); 
     devices = client.DiscoverDevicesInRange(); 

     List<string> discoveredDevices = new List<string>(); 

     foreach (BluetoothDeviceInfo d in devices) 
     { 
      discoveredDevices.Add(d.DeviceName); 
     } 

     return discoveredDevices; 
    } 
} 

然后,写一个async方法,将通过创建这个类的一个新实例得到的数据源,并await该方法返回。此外,使Click方法异步,因此它可以await数据源方法:

public partial class Form1 : Form 
{ 
    // Other form code omitted... 

    private async void BtnScan_Click(object sender, EventArgs e) 
    { 
     listBox1.DataSource = await Task.Run(GetDatasource); 
    } 

    private async Task<List<string>> GetDatasource() 
    { 
     var btCom = new BtCom(); 
     List<string> results = await btCom.Scan(); 
     return results; 
    } 

现在,用户可以点击按钮和形式将继续在扫描发生反应,和你的列表框将填充扫描时方法结束。

有关asyncawait的更多信息,请查看您最喜爱的搜索引擎(例如,此页上的Asynchronous programming)。

+0

非常感谢您的帮助。我今晚下班回家时试试一切。正如我所说的,我刚刚开始使用C#,并且或多或少地将代码编写在一起,因此我非常感谢您的帮助。 – Rikas