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

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

呼び出しがメイン (UI) スレッドで発生するように、 myProcess_Exited 関数を少し変更する必要があります。

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

public void change メソッドでこれを試してください:

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 に答える