委托调用

时间:2012-05-21 06:23:29

标签: c# wpf delegates invoke

我想从类中的进程线程事件触发器更改Form控件属性,我有以下代码但是我收到了这个例外:

  

调用线程因为不同而无法访问此对象   线程拥有它。

代码:

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 个答案:

答案 0 :(得分:2)

您不能从拥有该对象的线程以外的任何线程触摸任何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方法获得相同的东西。

答案 1 :(得分: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稍加修改以适合您的问题。我建议你在那里阅读,以便了解正在发生的事情

答案 2 :(得分: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);
        }
    } 
    //..
} 

答案 3 :(得分:0)

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

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