如何在单独的线程中更新UI ?



我有一个带有网格的WPF视图,其中有两个元素,RichText和Progressbar。当我向RichText加载大量文本时,我想向用户显示加载过程(只是一个动画)。主要思路是隐藏Richtext控件,显示进度条,开始加载文本,完成后再次显示Richtext。问题是,当我更新RichText控件我阻塞UI和进度条被冻结。是否有办法从另一个线程更新进度条,也许是一些代理主机?

谢谢。

是否有办法从另一个线程更新Progressbar

简短的回答:不。控件只能在最初创建它的线程上更新。

你可以做的是在另一个线程上运行的另一个窗口中显示ProgressBar,然后在原始线程上的RichTextBox被更新时关闭该窗口。

您可以将此添加到您的使用中:

using System.Windows.Threading;

为。net的5/6,这就足够了。对于。net框架,你还必须添加一个对System.Windows.Presentation.dll的引用。

这种类型的代码可以正常工作:

private void Button_Click(object sender, RoutedEventArgs e)
{
// here we're in UI thread
var max = 100;
pg.Maximum = max; // pg is a progress bar
Task.Run(() =>
{
// here we're in another thread
for (var i = 0; i < max; i++)
{
Thread.Sleep(100);
// this needs the System.Windows.Threading using to support lambda expressions
Dispatcher.BeginInvoke(() =>
{
// this will run in UI thread
pg.Value = i;
});
}
});
}

在表单上创建一个方法来更新您想要更新的元素,并使用invoke从您的线程中运行它

这样的:

private void Form1_Load(object sender, EventArgs e)
{
Thread _thread = new Thread(() =>
{
//do some work
upDateUiElements();//pass any parameters you want
});
_thread.Start();
}
public  void upDateUiElements()//input any parameters you need
{
BeginInvoke(new MethodInvoker(() =>
{            
//update ui elements
}));           
}

如果你需要从一个不同的类调用它,你可以传递你的表单作为一个对象,然后通过该对象访问该方法

这样的:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
OtherClass _class = new OtherClass(this);
_class.runthread();
}
public  void upDateUiElements()//input any parameters you need
{
BeginInvoke(new MethodInvoker(() =>
{
//update ui elements
}));
}
}
class OtherClass
{
private Form1 _accessForm1;
public OtherClass(Form1 accessform1)
{
_accessForm1 = accessform1;
}
public void runthread()
{
Thread _thread = new Thread(() =>
{
//do some work
_accessForm1.upDateUiElements();
});
_thread.Start();
}
}

最新更新