我正在使用Kinect和COM在C#中编写一个小型WPF应用程序,以便与arduino进行通信。
我有一个组合框,用户可以选择他想要使用的端口,我的COM上有一个观察者,每次设备插入/拔出时我想刷新我的组合框。
我的问题是调用该函数是在另一个类中,所以我有一个线程错误
以下是不起作用的代码部分:
namespace Microsoft.Samples.Kinect.SkeletonBasics
{
using System.IO;
using System.IO.Ports;
using System;
using System.Management;
using System.Windows;
using System.Windows.Media;
using System.Collections.Generic;
using System.Windows.Controls;
using Microsoft.Kinect;
using Microsoft.Kinect.Toolkit;
public partial class MainWindow : Window
{
private WMIReceiveEvent receiveEvent = new WMIReceiveEvent();
internal static ComboBox comboBox; //Internal static variable so it can be used in static method
public MainWindow()
{
InitializeComponent();
}
private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
using (receiveEvent) {}
}
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
comboBox = Com_ComboBox;
string[] ports = SerialPort.GetPortNames();
if (ports.Length == 0)
{
Default_Text.Content = "Aucun port détecté";
comboBox.IsHitTestVisible = false;
comboBox.Focusable = false;
}
else Default_Text.Content = "Arduino sur le port :";
comboBox.SelectedIndex = 0;
foreach (string port in ports)
{
comboBox.Items.Add(port);
}
}
internal static void Refresh_Coms() //I'm trying to call this function from the other class but I get a thread error
{
comboBox.Items.Clear();
ComboBoxItem Default_Text = (ComboBoxItem) comboBox.ItemContainerGenerator.ContainerFromIndex(0);
string[] ports = SerialPort.GetPortNames();
if (ports.Length == 0)
{
Default_Text.Content = "Aucun port détecté";
comboBox.IsHitTestVisible = false;
comboBox.Focusable = false;
comboBox.SelectedIndex = 0;
}
else Default_Text.Content = "Arduino sur le port :";
foreach (string port in ports)
{
comboBox.Items.Add(port);
}
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
}
public class WMIReceiveEvent : IDisposable
{
private ManagementEventWatcher watcherAttach;
private ManagementEventWatcher watcherDetach;
public WMIReceiveEvent()
{
try
{
watcherAttach = new ManagementEventWatcher();
watcherAttach.EventArrived += Attaching;
watcherAttach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
watcherAttach.Start();
watcherDetach = new ManagementEventWatcher();
watcherDetach.EventArrived += Detaching;
watcherDetach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
watcherDetach.Start();
return;
}
catch (ManagementException err)
{
MessageBox.Show("An error occurred while trying to receive an event: " + err.Message);
}
}
public void Dispose()
{
try
{
watcherAttach.Stop();
watcherDetach.Stop();
watcherAttach.Dispose();
watcherDetach.Dispose();
}
catch
{
MessageBox.Show("An error occurred while trying to close COM event Handler");
}
}
void Attaching(object sender, EventArrivedEventArgs e)
{
if (sender != watcherAttach) return;
Console.WriteLine("Attaching");
MainWindow.Refresh_Coms(); //I can call the function but the thread can't modify the ComboBox
}
void Detaching(object sender, EventArrivedEventArgs e)
{
if (sender != watcherDetach) return;
Console.WriteLine("Detaching");
MainWindow.Refresh_Coms();
}
~WMIReceiveEvent()
{
this.Dispose();
}
}
}
我对C#有点新鲜,我在网上搜索过但我找不到一个简单的解决方案,有人可以帮我吗?
答案 0 :(得分:1)
将SynchronizationContext
添加到您的WMIReceiveEvent
课程中,例如:
public class WMIReceiveEvent : IDisposable
{
private readonly SynchronizationContext _syncContext;
public WMIReceiveEvent(SynchronizationContext syncContext)
{
_cyncContext = syncContext;
}
}
并使用MainWindow.Refresh_Coms();
Send
方法调用SynchronizationContext
包裹:
_syncContext.Send(o => MainWindow.Refresh_Coms(), null);
最后一件事是创建你的WMIReceiveEvent
课程:
private WMIReceiveEvent receiveEvent = new WMIReceiveEvent(SynchronizationContext.Current);
关于SynchronizationContext的More。