0

UIなしで実行されるFTPプロセスがあります。そして、このftpコントロールを使用するwinformがあります。そのウィンドウには、ftpアップロードの進行状況を示すプログレスバーがあります。進行状況は、基になるプレゼンターで更新される間期を介してウィンドウに到着します(私はMVPパターンを使用しています)。

私の問題は、進行状況を更新しようとすると、常にこの例外がスローされることです。

スレッドを介した不正な操作:コントロール'prgProgresoSubido'は、作成したスレッド以外のスレッドからアクセスされます。

フォームでBackGroundWorkerを使用しても、この問題は解決しません。

    // This is  a delegated on presenter when a File finish to upload
    void client_FileUploadCompletedHandler(object sender, FileUploadCompletedEventArgs e)
    {
        string log = string.Format("{0} Upload from {1} to {2} is completed. Length: {3}. ",
            DateTime.Now, e.LocalFile.FullName, e.ServerPath, e.LocalFile.Length);

        archivosSubidos += 1;
        _Publicacion.ProgresoSubida = (int)((archivosSubidos / archivosXSubir) * 100);
        //this.lstLog.Items.Add(log);
        //this.lstLog.SelectedIndex = this.lstLog.Items.Count - 1;
    }


    // This is My interfase 

public interface IPublicacion
{
    ...
    int ProgresoSubida { set; } 
}

/// And Here is the implementartion of the interfase on the form

public partial class PublicarForm : Form ,IPublicacion 
{
    //Credenciales para conectarse al servicio FTP 
    public FTPClientManager client = null;
    public XmlDocument conf = new XmlDocument();
    public string workingDir = null;
    public webTalk wt = new webTalk();
    private readonly PublicacionesWebBL _Publicador;

    public PublicarForm()
    {
        InitializeComponent();

        String[] laPath = { System.AppDomain.CurrentDomain.BaseDirectory};
        String lcPath = System.IO.Path.Combine(laPath);

        _Publicador = new PublicacionesWebBL(this, lcPath);
    }

    public int ProgresoSubida
    {
        set
        {
            //  This is my prograss bar, here it throw the exception.
            prgProgresoSubido.Value = value;
        }
    }
}

この問題を回避するにはどうすればよいですか?

4

2 に答える 2

2

一般に、ユーザーインターフェイスとコントロールのすべての更新は、メインスレッド(イベントディスパッチャー)から実行する必要があります。別のスレッドからコントロールのプロパティを変更しようとすると、例外が発生します。

UIを更新するメソッドをイベントディスパッチャーで呼び出すには、Control.Invokeを呼び出す必要があります。

Control.Invoke

ここで、フォームにボタンとラベルを配置してから、これを試してください

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(new ThreadStart(TestThread));
        t.Start();
    }

    private void TestThread()
    {
        for (int i = 0; i < 10; i++)
        {
            UpdateCounter(i);
            Thread.Sleep(1000);
        }
    }

    private void UpdateCounter(int i)
    {


        if (label1.InvokeRequired)
        {
            label1.Invoke(new ThreadStart(delegate { UpdateCounter(i); }));
        }
        else
        {
            label1.Text = i.ToString();
        }
    }
}

スレッドからイベントを発生させている場合、そのイベントは同じスレッド上にあることに注意してください。したがって、そのスレッドがイベントディスパッチャでない場合は、呼び出す必要があります。

また、BackgroundWorkerが(コメンテーターが言ったように)これを単純化するメカニズムがあるかもしれませんが、私はこれまで使用したことがないので、調査するのはあなたに任せます。

于 2013-02-22T15:32:46.520 に答える
1

Alanが指摘したように、UIスレッドのUIコントロールを使用してすべての操作を実行する必要があります。

次のようにプロパティを変更するだけです。

public int ProgresoSubida
{
    set
    {
        MethodInvoker invoker = delegate
                                {
                                    prgProgresoSubido.Value = value;
                                }
        if (this.InvokeRequired)
        {
            Invoke(invoker);
        }
        else
        {
            invoker();
        }

    }
}
于 2013-02-22T15:49:08.750 に答える