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");

        }
}
4

4 回答 4

3

除了拥有该对象的线程之外,您不能触摸来自任何线程的任何 UI 元素。为此,您可以将调用包装在 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 方法获得相同的结果。

于 2012-05-21T06:31:14.407 回答
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,稍作修改以适应您的问题。我建议您继续阅读,以便您了解正在发生的事情

于 2012-05-21T08:06:57.347 回答
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);
        }
    } 
    //..
} 
于 2012-05-21T09:28:08.513 回答
0

您只需要对 myProcess_Exited 函数进行细微更改,以便调用发生在主 (UI) 线程上:

private void myProcess_Exited(object sender, System.EventArgs e)
{
    Application.Current.Dispatcher.BeginInvoke(() => {
        _frm.change();
     });
}
于 2012-05-21T09:31:36.317 回答