我已经尝试了几种方法来实现它,后台工作者,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,也会有一个更新,太奇怪了。
5条答案
按热度按时间bvk5enib1#
我希望有什么有用的...
ozxc1zmp2#
解决它是的,哇,三天的测试,测试,测试。
我决定用上面的扩展方法和一个简单的for循环来开始一个新的项目来测试UI更新功能。我开始测试不同的DispatchPrioraties(全部测试)。
奇怪的是,我发现最高优先级的标签更糟糕,例如,使用Send根本不更新标签,而Render平均更新两次。这就是我在尝试不同优先级时遇到的奇怪行为。我发现背景:
枚举值为4。在所有其他非闲置作业完成之后,才会行程作业。
现在这听起来正是我不想要的,因为很明显标签应该在处理过程中更新,因此我从来没有尝试过它。我猜一旦我的一个方法完成,在它调用下一个方法之前,UI就会更新。我猜,但它在两个单独的操作上100%一致地正确更新。
谢谢大家。
dphi5xsq3#
这听起来很愚蠢,但您可以只引用窗体名称空间,然后就可以这样做了
现在使用这个的问题是你使用的是wpf但是你仍然可以引用表单和使用这个命名空间。另一个问题是que中的内容将直接执行到ui。然而这是我能想到的最简单的标签更新方法。
uurity8g4#
将状态信息作为属性添加到这个对象上,并让它只触发属性更改通知,这是否更容易/更好?
这样标签文本(或任何东西)就可以绑定到属性,而不是让异步工作尝试更新标签?
或者如果必须更新状态,添加一个类似这样方法来更新状态?
否则,我认为我们还没有足够的细节来帮助....
j9per5c45#
我希望这能有所帮助:
用法: