Winforms: обновить метку на форме из другого класса - PullRequest
2 голосов
/ 21 марта 2012

У меня есть проект, в котором мне нужно обновить текст метки из другого метода классов. Стоит отметить, что этот метод вызывается из фонового рабочего потока.

Я попытался передать текст для обновления в качестве объекта UserState в Workers ReportProgress (); метод, а затем обновить метку, когда в основной форме запускается событие изменения рабочих. Это работает, но, очевидно, обновляет текст меток только при возникновении события изменения прогресса.

У меня есть код, который постоянно загружает / удаляет прокси-серверы, и мне нужна метка, чтобы показать, как это происходит (в отличие от обновления, только когда bg worker прогрессирует, изменяя события). Надеюсь, кто-то может помочь.

Спасибо

Редактировать * Вот код, который немного облегчает понимание проблемы: -

  public string Request(string action)
    {

        if (string.IsNullOrWhiteSpace(action))
        {
            return "";
        }

        HttpWebRequest req;

        string response = string.Empty;
        while (response.Equals(string.Empty) && proxy != null)
        {
            try
            {
                req = (HttpWebRequest)WebRequest.Create(action);
                req.Proxy = proxy;
                response = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd();
            }
            catch (Exception ex)
            {
                RemoveProxy(proxy);
                MessageBox.Show("Proxy Removed: " + proxy.Address.ToString());

                proxy = GenNewProx();
                MessageBox.Show("New proxy" + proxy.Address.ToString());
            }
        }

        return response;
    }

^^^ - Там, где мне нужно установить текст меток, используя Msgbox на данный момент, но обновление метки в главной форме, очевидно, предпочтительнее

   foreach (string url in URLs)
        {
            result.URL = url;
            result.Shares = grabber.GetFacebookShares(url);
            result.Tweets = grabber.GetTweetCount(url);
            result.PlusOnes = grabber.GetPlusOnes(url);

            bgWorker.ReportProgress((outputGridView.Rows.Count * 100) / importGridView.Rows.Count, result);
        }

^^^ - Внутри bg рабочий метод do_work в главной форме.

2-е редактирование *

Я немного новичок в событиях, но могу ли я не запускать пользовательское событие, скажем, Proxy_Changed каждый раз, когда я переключаю прокси и передаю строковый аргумент с новым proxy / msg мы, а затем подписываемся на это событие в основной форме затем установите метку на главной форме text = строка args, когда сработает это событие? Я, вероятно, говорю о чепухе, хотя: /

Ответы [ 3 ]

3 голосов
/ 21 марта 2012

Вот что я думаю, что важные части вашего класса, которые должны выполнять фоновые работы, выглядят так:

public class Grabber
{
    public event EventHandler<MyArgs> NotifyParentUI;

    // other code.....

    public string Request(string action)
    {
        if (string.IsNullOrWhiteSpace(action))
        {
            return "";
        }

        HttpWebRequest req;

        string response = string.Empty;
        while (response.Equals(string.Empty) && proxy != null)
        {
            try
            {
                req = (HttpWebRequest)WebRequest.Create(action);
                req.Proxy = proxy;
                response = new StreamReader(req.GetResponse().GetResponseStream()).ReadToEnd();
            }
            catch (Exception ex)
            {
                RemoveProxy(proxy);
                NotifyParentUI(this, new MyArgs() 
                   { Message = string.Format("Proxy Removed: {0}", proxy.Address.ToString()) });

                proxy = GenNewProx();
                NotifyParentUI(this, new MyArgs() 
                   { Message = string.Format("New Proxy: {0}", proxy.Address.ToString()) });
            }
        }

        return response;
    } 
}

В основной форме у вас есть метод обновления ярлыка, который поддерживает потоки:

public void UpdateMyLabel(object sender, MyArgs ea)
{
    this.Invoke(new MethodInvoker(
        delegate()
        {
            labelControl1.Text = ea.Message;
        }
        ));
}

Также в главной форме вы должны создать экземпляр вашего "граббера":

Grabber grabber = new Grabber();
grabber.NotifyParentUI += UpdateMyLabel;

У вас должен быть метод, который работает в собственном потоке:

public void ThreadProc()
{

    // other code before this....

    foreach (string url in URLs)
    {
       result.URL = url;
       result.Shares = grabber.GetFacebookShares(url);
       Thread.Sleep(0); // may want to take the Sleeps out
       result.Tweets = grabber.GetTweetCount(url);
       Thread.Sleep(0);
       result.PlusOnes = grabber.GetPlusOnes(url);
       Thread.Sleep(0);
    }
}

Вот как вы начинаете тему в основной форме:

Thread t = new Thread(new ThreadStart(ThreadProc));
t.Start();

В качестве примечания: если вам нужно передать данные в ваш поток, посмотрите здесь: Передача данных в потоки и получение данных из потоков

2 голосов
/ 21 марта 2012

Используйте метод Invoke для запуска анонимной функции в потоке пользовательского интерфейса для обновления метки. Например:

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += (sender, args) =>
                        {
                            for (int i = 0; i < 10000; ++i)
                            {
                                DoSomeWorkInBackground();

                                // Update the label in UI thread
                                MyOtherFormInstance.Invoke((MethodInvoker)delegate()
                                                                            {
                                                                                MyOtherFormInstance.SetLabelText(i);
                                                                            });
                                DoSomOtherWorkInBackground();
                            }
                        };

В вашей форме:

    public void SetLabelText(int i)
    {
        myLabel.Text = i.ToString();
        // not sure that this needed, but try:
        myLabel.Invalidate();
    }
1 голос
/ 22 марта 2012

Из вашего вопроса и последующих комментариев к другим ответам звучит, что вы запускаете свой код в проекте WinForms, поправьте меня, если я ошибаюсь? В winform основной поток программы обычно всегда статичен (static void Main ()), поэтому вы должны сделать EventHandler static также, чтобы избежать нулевых исключений. Я полагаю, что это решит вашу проблему, так как кажется, что остальная часть вашего кода верна?

...