2012-05-21 195 views
1

我想改變進程線程事件火災窗體控件屬性中,我有以下的代碼,但我收到此異常類:委託調用

調用線程不能訪問此對象,因爲不同的 線程擁有它。

代碼:

public partial class main : Window 
{   
    public main() 
    { 
     InitializeComponent(); 
    } 

    public void change() 
    { 
     label1.Content = "hello"; 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     nmap nmap = new nmap(this); 
     nmap.test("hello"); 
    } 
} 

class nmap 
{ 
    private main _frm; 
    private Process myprocess; 

    public nmap(main frm) 
    { 
     _frm = frm; 
    } 

    public void test(object obj) 
    { 
     string s1 = Convert.ToString(obj); 
     ProcessStartInfo startInfo = new ProcessStartInfo(); 
     myprocess = new Process(); 
     myprocess.StartInfo.FileName = "C:\\nmap\\nmap.exe"; 
     myprocess.EnableRaisingEvents = true; 
     myprocess.Exited += new EventHandler(myProcess_Exited); 

     myprocess.Start(); 
    } 

    private void myProcess_Exited(object sender, System.EventArgs e) 
    { 
     try 
     { 
      _frm.change(); 
     } 
     catch{} 
    } 
} 

請幫我在這,我想代表調用必須工作

我的項目是一個WPF C#項目。

答案是:

class nmap 
    { 
     private main _frm; 
     private Process myprocess; 


     public nmap() 
     { 

     } 
     public nmap(main frm) 
     { 
      _frm = frm; 
     } 
     public void test(object obj) 
     { 
      string s1 = Convert.ToString(obj); 
      ProcessStartInfo startInfo = new ProcessStartInfo(); 
      myprocess = new Process(); 
      myprocess.StartInfo.FileName = "C:\\nmap\\nmap.exe"; 
      //myprocess.StartInfo.CreateNoWindow = true; 
      myprocess.EnableRaisingEvents = true; 
      //myprocess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; 
      myprocess.Exited += new EventHandler(myProcess_Exited); 
      myprocess.Start(); 

     } 

     private void myProcess_Exited(object sender, System.EventArgs e) 
     { 
      try 
      { 
       String s; 
       s = "hello"; 
       _frm.Dispatcher.Invoke(_frm.USD, new Object[] { s }); 
      } 
      catch{} 
     } 

    } 

public partial class main : Window 
    { 
     public delegate void UpdateStatusDelegate(string value); 
     public UpdateStatusDelegate USD; 

     public main() 
     { 
      InitializeComponent(); 
     } 

     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 
      USD = new UpdateStatusDelegate(this.AddString); 

     } 
     private void AddString(String s) 
     { 
      label1.Content = s; 

     } 
     public void change() 
     { 
      label1.Content = "hello"; 
     } 


     private void button1_Click(object sender, RoutedEventArgs e) 
     { 
      nmap nmap = new nmap(this); 
      nmap.test("hello"); 

     } 
} 

回答

2

不能從除擁有該對象的線程以外的任何線程接觸任何UI元素。要做到這一點,你可以在調用方法這樣換電話:

delegate void UpdateStatusDelegate (string value); 

private void UpdateStatus(string value) 
{ 
    if (InvokeRequired) 
    { 
     // We're not in the UI thread, so we need to call BeginInvoke 
     BeginInvoke(new UpdateStatusDelegate(UpdateStatus), new object[]{value}); 
     return; 
    } 
    // Must be on the UI thread if we've got this far 
    statusIndicator.Text = value; 
} 

在WPF的世界裏,你可以通過使用Dispatcher.Invoke方法得到同樣的事情。

+0

嗨哈迪我在WPF工作沒有InvokeRequired方法,但無論如何,我仍然有這個問題!請描述更多謝謝! –

+0

我應該在nmap類或主窗口窗體中使用delegete調用? –

+0

啊,你沒有注意到你提到你在使用WPF。在WPF中,您應該能夠使用Dispatcher.Invoke方法(幾乎)執行相同的操作。 –

0

試試這個在您的公共無效變化的方法:

public void change(string text) 
{ 
    if (label1.InvokeRequired) 
    { 
     var a = new Action<string>(change); 
     this.Invoke(a, new object[] { text }); 
    } 
    else 
    { 
     label1.Content = "hello"; 
    } 
} 

http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx採取稍作修改,以適應您的問題。我建議您在那裏閱讀,以便了解發生了什麼

0

您必須在UI線程上調用該方法。使用此代碼:

public partial class main : Window 
{   
    //... 
    public void change() 
    { 
     if(Dispatcher.Thread.ManagedThreadId == Thread.ManagedThreadId) 
     { 
      // The method was called within the UI thread 
      label1.Content = "hello"; 
     } 
     else 
     { 
      // The method was called from different thread and we need to call Invoke 
      var callback = new Action(change); 
      Dispatcher.Invoke(callback); 
     } 
    } 
    //.. 
} 
0

因此調用主(UI)線程時你只需要你的myProcess_Exited功能的微小變化:

private void myProcess_Exited(object sender, System.EventArgs e) 
{ 
    Application.Current.Dispatcher.BeginInvoke(() => { 
     _frm.change(); 
    }); 
}