按第二类更改文本
本文关键字:二类 文本 | 更新日期: 2023-09-27 18:11:29
我现在正在学习c#。
我的问题是:我有2类。MainWindow.xaml.cs
用于UI,另一个称为dosomething.cs
。
如果点击UI上的一个按钮,应该调用dosomething.cs
中的一个方法。这很好。我希望dosomething.cs
在运行点击处理程序(需要一些时间)时告诉UI的实际状态。
status_textblock = "test";
for (int i = 1; i<1000000; i++)
i += i;
Thread.sleep(100);
Status_textblock = i.tostring();
}
我该怎么做才能让每个新值立即出现在UI中?我已经尝试了Backgroundworker
和Dispatcher
,但没有成功。
我会使用BackgroundWorker here
。在dosomething.cs
的函数中,您启动worker,并且您的UI-CodeBehind订阅dosomething事件。
小例子:
UI-Codebehind:
private void ButtonClick(object sender, ...)
{
var doSomething = new DoSomething();
doSomething.StatusChanged += OnStatusChanged;
doSomething.Do();
}
private void OnStatusChagned(string state)
{
// Update the UI with the state
}
是的,public class DoSomething
{
public void Do()
{
var worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += WorkerOnDoWork;
worker.ProgressChanged += WorkerOnProgressChanged;
worker.RunWorkerAsync("Paremeter to pass to the BackgroundWorker");
}
private void WorkerOnProgressChanged(object sender, ProgressChangedEventArgs e)
{
var temp = StatusChanged;
if (temp != null)
temp((string) e.UserState);
}
private void WorkerOnDoWork(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker) sender;
// If you want to get the passed argument you can call
var parameter = e.Argument;
for (int i = 0; i < 100000; i++)
{
// do your background-stuff here
// ...
// Notify the UI
worker.ReportProgress(0, "STATUS-OBJECT");
}
}
public delegate void OnStatusChanged(string status);
public event OnStatusChanged StatusChanged;
}
问题1:参考MainWindow.cs:
在面向对象编程中,你解耦组件以获得更好的概述、可测试性继承等。但是你必须考虑如何在对象之间传播引用。我的意思是:类dosomething的实例必须有一个对主窗口的引用,以便能够更新它的任何东西。你现在要做的是:在方法中创建一个MainWindow的新实例,并改变其状态(但不是实际可视化的MainWindow)
您可以将对实际MainWindow的引用传递给函数。这叫做依赖注入。通常情况下,你只注入一个由MainWindow类实现的接口,所以另一个类也可以使用这个功能,但这有点过头了。快速修复:
public void Do(MainWindow window)
{
window.status_textblock = "test";
for (int i = 1; i<1000000; i++)
i += i;
Thread.sleep(100);
window.status_textblock = i.tostring();
}
并在主窗口中调用它:
new Dosomething().Do(this);
但是这仍然不起作用,因为线程被阻塞(使用Thread. sleep),并且只会在线程空闲时显示结果。
问题2:您必须在另一个线程/任务
中运行它public void Do(MainWindow window)
{
Task.Factory.StartNew(() => {
window.status_textblock = "test";
for (int i = 1; i < 1000000; i++)
i += i;
Thread.sleep(100);
window.status_textblock = i.tostring();
});
}
但是等一下,这也不会工作,因为你试图从另一个线程更新UI,这是不允许的
问题3:使用STA线程更新UI在MainWindow类中,你创建了一个方法来更新STA线程上的状态文本(STA线程是唯一允许更新UI上任何东西的线程)。
public void UpdateStatus(string status)
{
if (this.Dispatcher.CheckAccess())
this.status_textblock = status;
else
this.Dispatcher.Invoke(new Action<string>(UpdateStatus), status);
}
在DoSomething类中调用UpdateStatus方法:
public void Do(MainWindow window)
{
Task.Factory.StartNew(() => {
window.UpdateStatus("test");
for (int i = 1; i < 1000000; i++)
i += i;
Thread.sleep(100);
window.UpdateStatus(i.tostring());
});
}
->它工作!
在更多关于这个主题的文章中推荐使用Backgroundworker。你要做的是:
-
当按钮被点击时启动一个新的Backgroundworker
-
绑定
DoWork
、ProgressChanged
事件 -
在DoWork委托中,您可以使用自定义对象或单个整数调用
ReportProgress
-
绑定到
ProgressChanged
的方法将在UI线程上触发,在那里你可以更新标签或任何你喜欢的东西。 -
也许你应该"refresh"这篇文章的答案的页面/视图。
有关Backgroundworker的更多信息,请查看此处。