2012-08-31 12 views
6

Używam WMI do odpytywania urządzeń. Muszę zaktualizować interfejs użytkownika po włożeniu lub usunięciu nowego urządzenia (aby zaktualizować listę urządzeń).Aplikacja nazywana interfejsem, który został skierowany dla innego wątku

private void LoadDevices() 
{ 
    using (ManagementClass devices = new ManagementClass("Win32_Diskdrive")) 
    { 
     foreach (ManagementObject mgmtObject in devices.GetInstances()) 
     { 
      foreach (ManagementObject partitionObject in mgmtObject.GetRelated("Win32_DiskPartition")) 
      { 
       foreach (ManagementBaseObject diskObject in partitionObject.GetRelated("Win32_LogicalDisk")) 
       { 
        trvDevices.Nodes.Add(...); 
       } 
      } 
     } 
    } 
} 

protected override void WndProc(ref Message m) 
{ 
    const int WM_DEVICECHANGE = 0x0219; 
    const int DBT_DEVICEARRIVAL = 0x8000; 
    const int DBT_DEVICEREMOVECOMPLETE = 0x8004; 
    switch (m.Msg) 
    { 
     // Handle device change events sent to the window 
     case WM_DEVICECHANGE: 
      // Check whether this is device insertion or removal event 
      if (
       (int)m.WParam == DBT_DEVICEARRIVAL || 
       (int)m.WParam == DBT_DEVICEREMOVECOMPLETE) 
     { 
      LoadDevices(); 
     } 

     break; 
    } 

    // Call base window message handler 
    base.WndProc(ref m); 
} 

Ten kod wyrzuca wyjątek z następującym tekstem

The application called an interface that was marshalled for a different thread.

kładę

MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString()); 

na początku metody LoadDevices i widzę, że jest zawsze nazywane z tego samego wątek (1). Czy mógłbyś wyjaśnić, co tu się dzieje i jak pozbyć się tego błędu?

Odpowiedz

2

W końcu rozwiązałem go, używając nowego wątku. Rozdzielam tę metodę, więc teraz mam metody GetDiskDevices() i LoadDevices(List<Device>) i mam metodę InvokeLoadDevices().

private void InvokeLoadDevices() 
{ 
    // Get list of physical and logical devices 
    List<PhysicalDevice> devices = GetDiskDevices(); 

    // Check if calling this method is not thread safe and calling Invoke is required 
    if (trvDevices.InvokeRequired) 
    { 
     trvDevices.Invoke((MethodInvoker)(() => LoadDevices(devices))); 
    } 
    else 
    { 
     LoadDevices(devices); 
    } 
} 

Kiedy się jeden z komunikatów DBT_DEVICEARRIVAL lub DBT_DEVICEREMOVECOMPLETE Wzywam

ThreadPool.QueueUserWorkItem(s => InvokeLoadDevices()); 

Dzięki.

0

Dla UWP na w10 można użyć:

public async SomeMethod() 
{ 
    await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.High,() => 
     { 
      // Your code here... 
     }); 
} 
Powiązane problemy