【问题标题】:Delegate invoke委托调用
【发布时间】:2012-05-21 06:23:29
【问题描述】:

我想从类中的进程线程事件触发中更改表单控件属性,我有以下代码但收到此异常:

调用线程无法访问该对象,因为不同的 线程拥有它。

代码:

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

        }
}

【问题讨论】:

    标签: c# wpf delegates invoke


    【解决方案1】:

    除了拥有该对象的线程之外,您不能触摸来自任何线程的任何 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 方法获得相同的结果。

    【讨论】:

    • 嗨,HADI,我在 WPF 中工作,没有 InvokeRequired 方法,但无论如何我对此仍有问题!请描述更多谢谢!
    • 我应该在哪里使用 nmap 类或主窗口形式的 delegate 调用?
    • 啊,你没有注意到你提到你正在使用 WPF。在 WPF 中,您应该能够(几乎)使用 Dispatcher.Invoke 方法做同样的事情。
    【解决方案2】:

    在你的公共无效更改方法上试试这个:

    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,稍作修改以适应您的问题。我建议您阅读那里,以便您了解正在发生的事情

    【讨论】:

      【解决方案3】:

      您必须在 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);
              }
          } 
          //..
      } 
      

      【讨论】:

        【解决方案4】:

        您只需对 myProcess_Exited 函数稍作更改,以便调用发生在主 (UI) 线程上:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-20
          • 1970-01-01
          • 1970-01-01
          • 2011-07-23
          • 2016-04-06
          • 2011-07-08
          • 2014-03-18
          • 2019-08-11
          相关资源
          最近更新 更多