WPF -在处理过程中更新标签内容

kulphzqa  于 2022-11-18  发布在  其他
关注(0)|答案(5)|浏览(139)

我已经尝试了几种方法来实现它,后台工作者,Dispatcher.Invoke,在被调用的类中线程化,但似乎没有什么效果。目前为止最好的解决方案是一个Extension方法,它调用控件的invoke。我也尝试过避免通过我的事件类传递标签的数据,而只是在我的处理代码中调用,但这没有什么区别。
关于后台组件,我不断收到异常,说后台工作线程很忙碌,所以我多次示例化该类,但是标签只有在整个操作完成后才发生明显的变化。
我已经删除了我以前的代码,这里的一切都是相关的,因为它似乎是很难解决的问题。

正在调用的方法

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

        }

雅虎类

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();
            }

        }

调用了Refresh静态方法:

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

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

另一个EDIT:我盯着代码看了一会儿,我意识到foreach循环执行得很快,耗时的操作是

yahooResult = yahoo.ReturnLinkCount(modUri);

因此我声明了status类(处理事件并调用标签等)并订阅了它。我得到了更好的结果,尽管感觉仍然是随机的,有时我会看到几个标签更新,有时即使传递了完全相同的URI,也会有一个更新,太奇怪了。

bvk5enib

bvk5enib1#

我希望有什么有用的...

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);
        }
    });
}
ozxc1zmp

ozxc1zmp2#

解决它是的,哇,三天的测试,测试,测试。
我决定用上面的扩展方法和一个简单的for循环来开始一个新的项目来测试UI更新功能。我开始测试不同的DispatchPrioraties(全部测试)。
奇怪的是,我发现最高优先级的标签更糟糕,例如,使用Send根本不更新标签,而Render平均更新两次。这就是我在尝试不同优先级时遇到的奇怪行为。我发现背景:
枚举值为4。在所有其他非闲置作业完成之后,才会行程作业。
现在这听起来正是我不想要的,因为很明显标签应该在处理过程中更新,因此我从来没有尝试过它。我猜一旦我的一个方法完成,在它调用下一个方法之前,UI就会更新。我猜,但它在两个单独的操作上100%一致地正确更新。
谢谢大家。

dphi5xsq

dphi5xsq3#

这听起来很愚蠢,但您可以只引用窗体名称空间,然后就可以这样做了

using System.Windows.Forms;

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

     myLabel = "update"
     Application.doEvents();

现在使用这个的问题是你使用的是wpf但是你仍然可以引用表单和使用这个命名空间。另一个问题是que中的内容将直接执行到ui。然而这是我能想到的最简单的标签更新方法。

uurity8g

uurity8g4#

将状态信息作为属性添加到这个对象上,并让它只触发属性更改通知,这是否更容易/更好?
这样标签文本(或任何东西)就可以绑定到属性,而不是让异步工作尝试更新标签?
或者如果必须更新状态,添加一个类似这样方法来更新状态?

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

否则,我认为我们还没有足够的细节来帮助....

j9per5c4

j9per5c45#

我希望这能有所帮助:

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

相关问题