2012-10-20 44 views
3

运行在单独的线程事件我试图避免问什么一些人似乎看到计算器为琐碎的问题。上次我问了一个问题时,我得到了很多负面答复,所以我想我会试图单独解决这个问题。所以可能大约一个月,两本书和一些视频教程后,我仍然很难过。 :)C#/ WPF:创建和启动

根据我的调试器调用我的MainWindow.xaml.cs类的第39行,但注意30或31似乎不会触发用户界面上的任何事情,有一点它,但它也给了我运行时错误。经过数周的困难之后,我有点休息并转移到其他方面,所以我不确定我是如何摆脱运行时错误的。所以,现在我寻求帮助,请:)

UPDATE

异常的MainWindow.xaml.cs的45行返回:

“对象,因为不同的线程拥有它。”

我MIDI类:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using NAudio.Midi; 

namespace StaveHelper 
{ 
public sealed class MIDIMain 
{ 
    private static MIDIMain midiMain = null; 
    public static int noteOnNumber; 
    public static int noteOffNumber; 
    public MidiIn midiIn; 
    public bool noteOn; 
    private bool monitoring; 
    private int midiInDevice; 

    private MIDIMain() 
    { 
     GetMIDIInDevices(); 
    } 

    public static MIDIMain GetInstance() 
    { 
     if (null == midiMain) 
     { 
      midiMain = new MIDIMain(); 
     } 
     return midiMain; 
    } 


    public string[] GetMIDIInDevices() 
    { 
     //Get a list of devices 
     string[] returnDevices = new string[MidiIn.NumberOfDevices]; 

     //Get the product name for each device found 
     for (int device = 0; device < MidiIn.NumberOfDevices; device++) 
     { 
      returnDevices[device] = MidiIn.DeviceInfo(device).ProductName; 
     } 
     return returnDevices; 
    } 

    public void StartMonitoring(int MIDIInDevice) 
    { 
     if (midiIn == null) 
     { 
      midiIn = new MidiIn(MIDIInDevice); 
     } 
     midiIn.Start(); 
     monitoring = true; 
    } 

    public void midiIn_MessageReceived(object sender, MidiInMessageEventArgs e) 
    { 
     //int noteNumber; 
     // Exit if the MidiEvent is null or is the AutoSensing command code 
     if (e.MidiEvent != null && e.MidiEvent.CommandCode == MidiCommandCode.AutoSensing) 
     { 
      return; 
     } 

     if (e.MidiEvent.CommandCode == MidiCommandCode.NoteOn) 
     { 
      // As the Command Code is a NoteOn then we need 
      // to cast the MidiEvent to the NoteOnEvent 
      NoteOnEvent ne; 
      ne = (NoteOnEvent)e.MidiEvent; 
      noteOnNumber = ne.NoteNumber; 
     } 

     if (e.MidiEvent.CommandCode == MidiCommandCode.NoteOff) 
     { 
      NoteEvent ne; 
      ne = (NoteEvent)e.MidiEvent; 
      noteOffNumber = ne.NoteNumber; 
     }   
    } 

    //// send the note value to the the MainWindow for display 
    //public int sendNoteNum(int noteNumber) 
    //{ 
    // noteOnNumber = noteNumber; 
    // noteOn = true; 
    // return noteOnNumber; 
    //} 
} 

}

我MainWindow.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Shapes; 
using NAudio.Midi; 
using System.Threading; 
using System.Windows.Threading; 

namespace StaveHelper 
{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    Config config; 
    MIDIMain midiMain; 

    public delegate void mon(object sender, MidiInMessageEventArgs e); 
    public MainWindow() 
    { 
     this.InitializeComponent(); 

     // Insert code required on object creation below this point. 
     midiMain = MIDIMain.GetInstance(); 
     config = new Config(); 
     config.load_MIDIIn_Devices(); 
     //Thread t = new Thread(monitorNotes); 
     midiMain.midiIn.MessageReceived += new EventHandler<MidiInMessageEventArgs>(monitorNotes); 
    } 

    public void monitorNotes(object sender, MidiInMessageEventArgs e) //LINE 39: MONITOR NOTES 
    { 

     switch (MIDIMain.noteOnNumber) 
     { 
      case 30: 
       C3.Opacity = 100;    //LINE 45: "The calling thread cannot access this 
       C3Dot.Opacity = 100;   //object because a different thread owns it." 
       break; 
      case 31: 
       D3Dot.Opacity = 100; 
       break; 
     } 
    } 

    ~MainWindow() 
    { 

    } 

    private void btnConfig_Click(object sender, RoutedEventArgs e) 
    { 
     config.Show(); 
    } 


} 
} 

如此看来,答案是改变:

switch (MIDIMain.noteOnNumber) 
    { 
     case 30: 
      C3.Opacity = 100;    //LINE 45: "The calling thread cannot access this 
      C3Dot.Opacity = 100;   //object because a different thread owns it." 
      break; 
     case 31: 
      D3Dot.Opacity = 100; 
      break; 
    } 
} 

switch (MIDIMain.noteOnNumber) 
     { 
      case 60: 
       C3.Dispatcher.BeginInvoke(
        System.Windows.Threading.DispatcherPriority.Normal, 
        new System.Windows.Threading.DispatcherOperationCallback 
         (delegate 
         { 
          C3.Opacity = 100; 
          C3Dot.Opacity = 100; 
          MIDIMain.noteOffNumber = -1; 
          return null; 
         }), null); 
       break; 
      case 61: 
       D3Dot.Dispatcher.BeginInvoke(
        System.Windows.Threading.DispatcherPriority.Normal, 
        new System.Windows.Threading.DispatcherOperationCallback 
         (delegate 
         { 
          D3Dot.Opacity = 100; 
          D3Dot.Opacity = 100; 
          MIDIMain.noteOnNumber = -1; 
          return null; 
         }), null); 
       break; 
     } 

感谢所有的帮助!

+0

你得到什么运行时错误? –

+0

诚实地说,在这一点上,我只能记得它在UI线程中使用midi类,因为它现在甚至不会发生。会发生什么情况是数字不会在我的开关中调用 – Laserbeak43

+0

您是否尝试过放置breakPoint,并在调试代码时查看“MIDIMain.noteOnNumber”的值? –

回答

2

你的例外是因为你正试图从后台线程修改WPF GUI组件。您需要使用分派器。这里有很多关于堆栈溢出的问题给出了帮助。例如,你可以使用代码this answer

yourControl.Dispatcher.BeginInvoke(
    System.Windows.Threading.DispatcherPriority.Normal, 
    new System.Windows.Threading.DispatcherOperationCallback(delegate 
    { 
     // update your GUI here  
     return null; 
    }), null); 
+0

Hello Mark,实际上它做到了!这是很多要理解的对象......哇!我有很多东西要学习! – Laserbeak43

1

如果你会看在StartMonitoring()方法 - 的情况下,当midiIn为null,它会创建一个新的实例,然后调用Start()但在这种情况下,没有人订阅MessageReceived如此看来,你忘了在这种情况下,认购midiIn.MessageReceived事件并且方法midiIn_MessageReceived从不被调用。所以noteOnNumber iremains因为只有在这个方法(midiIn_MessageReceived)未指定,我看到一个代码,它赋值给noteOnNumber变量。

试用更新StartMonitoring()方法:

if (midiIn == null) 
{ 
    midiIn = new MidiIn(MIDIInDevice); 
    midiIn.MessageReceived += midiIn_MessageReceived; 
} 
+0

啊好吧...非常抱歉有关解决办法,但似乎我在键盘上敲错了键(尽管早些时候我敲了每个键并没有得到任何东西)。运行时异常我get是**“调用线程不能访问这个对象,因为不同的线程拥有它。”** – Laserbeak43