WPF - обновление содержимого метки во время обработки - PullRequest
7 голосов
/ 02 августа 2010

Ну, я попробовал несколько способов заставить это работать, фоновый работник, Dispatcher.Invoke, поточная обработка в вызываемом классе и ничего, кажется, не работает.Наилучшим решением на данный момент является метод Extension, который вызывает вызов элемента управления.Также я старался избегать передачи данных для метки через мои классы событий и просто вызывать их в моем коде обработки, однако это не имело никакого значения.

Что касается компонента фона, я продолжал получать исключения, говоря фонработник был занят, поэтому я несколько раз создавал экземпляр класса, однако метка видимо менялась только после завершения всей операции.

Я удалил свой предыдущий код, здесь есть все, что имеет отношение к делу, как кажется,проблему трудно решить.

вызываемый метод

 private void TestUris()
        {
            string text = new TextRange(rtxturis.Document.ContentStart, rtxturis.Document.ContentEnd).Text;
            string[] lines = Regex.Split(text.Remove(text.Length - 2), "\r\n");

            foreach (string uri in lines)
            {
                SafeUpdateStatusText(uri);
                bool result;
                string modUri;

                if (!uri.Contains("http://"))
                {
                    modUri = uri;
                    result = StoreData.LinkUriExists(new Uri("http://" + modUri));
                }
                else
                {

                    modUri = uri.Substring(7);
                    result = StoreData.LinkUriExists(new Uri(uri));
                }

                if (!result)
                {
                    Yahoo yahoo = new Yahoo();
                    yahoo.Status.Sending += (StatusChange);
                    uint yahooResult = 0;

                    yahooResult = yahoo.ReturnLinkCount(modUri);

                    if (yahooResult > 1000 )
                    { results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, 1000, "Will be processed", true)); }
                    else
                    { results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, (int)yahooResult, "Insufficient backlinks", false)); }

                }
                else
                {
                    results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, 0, "Previously been processed", false));
                }
            }


            foreach (var record in results)
            {
                dgvresults.Items.Add(record);

            }

            EnableStartButton();

        }

класс Yahoo

public class Yahoo
    {        

        /// <summary>
        /// Returns the amount of links each Uri has.
        /// </summary>
        public uint ReturnLinkCount(string uri)
        {
            string html;
            Status.Update(uri, false); //this is where the status is called
            try
            {

                html = client.DownloadString(string.Format("http://siteexplorer.search.yahoo.com/search?p=http%3A%2F%2F{0}&fr=sfp&bwm=i", uri));

            }
            catch (WebException ex)
            {
               ProcessError(ex.ToString());
               return 0;
            }

           return (LinkNumber(html));

        }

Классы состояния

public class StatusEventArgs : EventArgs
    {
        private string _message;
        private bool _isidle;

        public StatusEventArgs(string message, bool isidle)
        {
            this._message = message;
            this._isidle = isidle;
        }

        public bool IsIdle
        {
            get { return _isidle; }
        }

        public string Message
        {
            get { return _message; }
        }
    }

   public class Status
    {
        public Status()
        {
        }

        // Declaring an event, with a custom event arguments class
        public event EventHandler<StatusEventArgs> Sending;

        // Some method to fire the event.
        public void Update(string message, bool isIdle)
        {
            StatusEventArgs msg = new StatusEventArgs(message, isIdle);
            OnUpdate(msg);
        }

        // The method that invokes the event.
        protected virtual void OnUpdate(StatusEventArgs e)
        {
            EventHandler<StatusEventArgs> handler = Sending;

            if (handler != null)
            {
                handler(this, e);
            }
        }
    }

Метод, который изменяет метки Содержимое

 private  void StatusChange(object sender, StatusEventArgs e)
        {

            if(!e.IsIdle)
            {
                lblstatus.Content = e.Message;
                lblstatus.Foreground = StatusColors.Green;
                lblstatus.Refresh();
            }
            else
            {
                lblstatus.Content = e.Message;
                lblstatus.Foreground = StatusColors.Grey;
                lblstatus.Refresh();
            }

        }

Статический метод Обновить называется:

 public static class ExtensionMethods
    {
        private static Action EmptyDelegate = delegate() { };

        public static void Refresh(this UIElement uiElement)
        {
            uiElement.Dispatcher.Invoke(DispatcherPriority.Render   , EmptyDelegate);
        }

Еще одно ИЗМЕНЕНИЕ: посмотрев на мой код немного дольше, я понял, что цикл foreach будет выполняться очень быстро, операция, которая занимает время, равна

yahooResult = yahoo.ReturnLinkCount(modUri); 

ПоэтомуЯ объявил класс статуса (который обрабатывает событие и вызывает метку и т. Д.) И подписался на него.Я получил лучшие результаты, хотя они все еще кажутся случайными, иногда я вижу пару обновлений меток, а иногда и одно, даже если передаются точно такие же URI, что странно.

Ответы [ 5 ]

6 голосов
/ 25 марта 2012

Я надеюсь, что есть что-то. полезно ...

 private void button1_Click(object sender, RoutedEventArgs e)
{
    ThreadPool.QueueUserWorkItem(o =>
    {
        int result = 0;
        for (int i = 0; i < 9999999; i++)
        {
            result++;
            Dispatcher.BeginInvoke(new Action(() =>
            {
                this.label1.Content = result;
            }));
            Thread.Sleep(1);
        }
    });
}
3 голосов
/ 01 декабря 2015

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

     using System.Windows.Forms;

     mylabel = "Start";
     Application.doEvents();

     myLabel = "update"
     Application.doEvents();

Теперь проблема использования этого заключается в том, что вы используете wpf, но вы все равно можете ссылаться на формы и использовать это пространство имен. Другая проблема заключается в том, что то, что когда-либо находится в очереди, будет выполняться непосредственно для пользовательского интерфейса. Однако это самый простой способ обновления ярлыков, о котором я только мог подумать. Я не уверен в другой причине, почему это было бы плохо использовать, но это решение OP. Если у вас есть веская причина, как это плохо, не голосуйте, просто сообщите себе и другим, оставив комментарий. Спасибо.

3 голосов
/ 03 августа 2010

РЕШЕНО, ЭТО ДА WOOHOOOOOOOO 3 дня тестирования, тестирования, тестирования.

Я решил начать новый проект только с описанным выше методом расширения и простым циклом for для проверки функциональности обновления пользовательского интерфейса.Я начал тестировать разные DispatchPrioraties (тестировал их все).

Странно, но я обнаружил, что самые высокие приоритеты были хуже, например, использование Send вообще не обновляло метку, Render обновляло ее в среднем дважды.Это было странное поведение, с которым я сталкивался, когда пробовал разные приоритеты.Я обнаружил фон:

Значение перечисления равно 4. Операции обрабатываются после того, как все другие неактивные операции завершены.

Теперь это звучит именно так, как я не хотел, как, очевидно, меткадолжен обновляться во время обработки, поэтому я никогда не пробовал.Я предполагаю, что как только один из моих методов будет завершен, до следующего вызова его, пользовательский интерфейс обновляется.Я нахожусь в догадках, но он постоянно корректно обновляется на две отдельные операции.

Спасибо всем.

1 голос
/ 02 августа 2010

Было бы проще / лучше добавить информацию о состоянии в качестве свойства для этого объекта, и он просто запускает уведомления об изменении свойства?

чтобы текст метки (или любой другой) мог быть привязан к свойству вместо того, чтобы асинхронная работа пыталась обновить метку?

или добавить метод, подобный этому, чтобы обновить статус, если вам нужно его обновить?

    void SafeUpdateStatusText(string text)
    {
        // update status text on event thread if necessary
        Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate
        {
            lblstatus.Content = text;
        }, null);
    }

в противном случае, я не думаю, что у нас еще достаточно деталей, чтобы помочь ....

0 голосов
/ 26 января 2017

Надеюсь, это поможет:

private delegate void UpdateLabelDelegate(DependencyProperty dp, object value);

public void UpdateLabelContent(Label label, string newContent)
{
    Dispatcher.Invoke(new UpdateLabelDelegate(label.SetValue), DispatcherPriority.Background, ContentProperty, newContent);
}

Использование:

while (true)
{
    UpdateLabelContent(this.lblStatus, "Next random number: " + new Random().Next());
    Thread.Sleep(1000);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...