防止 GUI 在 WPF 中挂起
Preventing GUI hangs in WPF
我是 C# WPF 项目的新手,我的代码存在问题,用户界面 "locks up" 而我 运行 是一项任务。这是相关代码:
public partial class MainWindow : Window {
// handles to ManagedDLAContainer objects
private ManagedDLA2DContainer dla_2d;
public MainWindow() {
InitializeComponent();
// initalise aggregate containers
dla_2d = new ManagedDLA2DContainer();
}
private void GenerateAggregate() {
// generate the 2D aggregate of size given by particles_slider value
Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); }));
// TODO: add particles to "canvas" on GUI as they are generated
}
private void GenerateButtonClick(object sender, RoutedEventArgs e) {
// set the coefficient of stickiness of aggregate
// to current value of stickiness_slider
dla_2d.SetCoeffStick(stickiness_slider.Value);
// start asynchronous task calling GenerateAggregate method
Task.Factory.StartNew(() => GenerateAggregate());
}
}
此处 ManagedDLA2DContainer
是一些本机非托管 C++
代码的托管 C++/CLI
包装器,stickiness_slider
只是 WPF 接口的 Slider
元素;同时,类似地,particles_slider
是界面的另一个 Slider 元素。我应该注意到以下代码也会导致 GUI 挂起:
public partial class MainWindow : Window {
// lock object for multi-threading tasks
private static readonly object locker = new object();
// handles to ManagedDLAContainer objects
private ManagedDLA2DContainer dla_2d;
public MainWindow() {
InitializeComponent();
// initalise aggregate containers
dla_2d = new ManagedDLA2DContainer();
}
private void GenerateAggregate() {
// lock around aggregate generation
lock (locker) {
// generate the 2D aggregate of size given by particles_slider value
Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); }));
// TODO: add particles to "canvas" on GUI as they are generated
}
}
private void GenerateButtonClick(object sender, RoutedEventArgs e) {
// set the coefficient of stickiness of aggregate
// to current value of stickiness_slider
dla_2d.SetCoeffStick(stickiness_slider.Value);
Thread agg_gen_thread = new Thread(GenerateAggregate);
agg_gen_thread.Start();
agg_gen_thread.Join();
}
}
感谢任何可以帮助我理解我在这里可能做错了什么的信息。
此外,如果您很好奇,可以在此处获取该项目的所有代码:https://github.com/SJR276/DLAProject
您开始了您 运行 GenerateAggregate
的新线程。然后立即通过 Dispatcher.Invoke
将所有工作 back 分派给用户界面线程。所以基本上你在 UI 线程上 运行ning long 运行ning 任务并且它阻塞了。
相反,您应该只向 UI 线程分配需要它的操作(例如更新 UI 控件),而不是整个操作。
假设您的生成函数如下所示:
void Generate() {
MakeCpuIntensiveWork();
UpdateUIWithResults();
}
您只需将第二部分分派到 UI 线程。在您的情况下,正如我们在评论中发现的那样,唯一的 UI 部分是获取滑块的值。所以你可以这样拆分:
private void GenerateAggregate()
{
uint sliderValue = 0;
// generate the 2D aggregate of size given by particles_slider value
Dispatcher.Invoke(() => { sliderValue = (uint)particles_slider.Value; });
dla_2d.Generate(sliderValue);
// TODO: add particles to "canvas" on GUI as they are generated
}
我是 C# WPF 项目的新手,我的代码存在问题,用户界面 "locks up" 而我 运行 是一项任务。这是相关代码:
public partial class MainWindow : Window {
// handles to ManagedDLAContainer objects
private ManagedDLA2DContainer dla_2d;
public MainWindow() {
InitializeComponent();
// initalise aggregate containers
dla_2d = new ManagedDLA2DContainer();
}
private void GenerateAggregate() {
// generate the 2D aggregate of size given by particles_slider value
Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); }));
// TODO: add particles to "canvas" on GUI as they are generated
}
private void GenerateButtonClick(object sender, RoutedEventArgs e) {
// set the coefficient of stickiness of aggregate
// to current value of stickiness_slider
dla_2d.SetCoeffStick(stickiness_slider.Value);
// start asynchronous task calling GenerateAggregate method
Task.Factory.StartNew(() => GenerateAggregate());
}
}
此处 ManagedDLA2DContainer
是一些本机非托管 C++
代码的托管 C++/CLI
包装器,stickiness_slider
只是 WPF 接口的 Slider
元素;同时,类似地,particles_slider
是界面的另一个 Slider 元素。我应该注意到以下代码也会导致 GUI 挂起:
public partial class MainWindow : Window {
// lock object for multi-threading tasks
private static readonly object locker = new object();
// handles to ManagedDLAContainer objects
private ManagedDLA2DContainer dla_2d;
public MainWindow() {
InitializeComponent();
// initalise aggregate containers
dla_2d = new ManagedDLA2DContainer();
}
private void GenerateAggregate() {
// lock around aggregate generation
lock (locker) {
// generate the 2D aggregate of size given by particles_slider value
Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); }));
// TODO: add particles to "canvas" on GUI as they are generated
}
}
private void GenerateButtonClick(object sender, RoutedEventArgs e) {
// set the coefficient of stickiness of aggregate
// to current value of stickiness_slider
dla_2d.SetCoeffStick(stickiness_slider.Value);
Thread agg_gen_thread = new Thread(GenerateAggregate);
agg_gen_thread.Start();
agg_gen_thread.Join();
}
}
感谢任何可以帮助我理解我在这里可能做错了什么的信息。
此外,如果您很好奇,可以在此处获取该项目的所有代码:https://github.com/SJR276/DLAProject
您开始了您 运行 GenerateAggregate
的新线程。然后立即通过 Dispatcher.Invoke
将所有工作 back 分派给用户界面线程。所以基本上你在 UI 线程上 运行ning long 运行ning 任务并且它阻塞了。
相反,您应该只向 UI 线程分配需要它的操作(例如更新 UI 控件),而不是整个操作。
假设您的生成函数如下所示:
void Generate() {
MakeCpuIntensiveWork();
UpdateUIWithResults();
}
您只需将第二部分分派到 UI 线程。在您的情况下,正如我们在评论中发现的那样,唯一的 UI 部分是获取滑块的值。所以你可以这样拆分:
private void GenerateAggregate()
{
uint sliderValue = 0;
// generate the 2D aggregate of size given by particles_slider value
Dispatcher.Invoke(() => { sliderValue = (uint)particles_slider.Value; });
dla_2d.Generate(sliderValue);
// TODO: add particles to "canvas" on GUI as they are generated
}