2012-05-21 3 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{} 
    } 
} 

Пожалуйста, помогите мне в этом, я думаю, что делегат Invoke должен быть работа

Мой проект является # проект 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

Вы не можете коснуться любой элемент пользовательского интерфейса из любого другого, чем нити, которой принадлежит объект потоков. Для достижения этой цели вы можете обернуть вызов в методе Invoke, как это:

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

Hi Хади, я работаю в WPF нет InvokeRequired, но в любом случае у меня все еще есть проблемы с этим! PLS описать больше спасибо! –

+0

где я должен использовать delegete invoke в классе nmap или в форме главного окна? –

+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

Вы должны вызвать метод в потоке пользовательского интерфейса. Используйте этот код:

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

Вам просто нужно небольшое изменение в вашей myProcess_Exited функции так, что вызов происходит на главном (UI) резьбы:

private void myProcess_Exited(object sender, System.EventArgs e) 
{ 
    Application.Current.Dispatcher.BeginInvoke(() => { 
     _frm.change(); 
    }); 
} 
Смежные вопросы