从不同的线程更新主窗口中的进度条
本文关键字:窗口 更新 线程 | 更新日期: 2023-09-27 18:17:25
我知道这个问题已经被问过好几次了,我花了一整天的时间试图理解其他答案,但是因为我对c#和WPF非常陌生,所以到目前为止没有任何帮助。我将尽我所能解释我的确切问题,这样它将直接帮助我。
在我的主窗口。我有一个进度条和一些按钮开始一个新的线程和一个长计算:
<ProgressBar Height="....... Name="progressBar1"/>
<Button Content="Button" Name="button1" Click="button1_Click" />
现在在我的mainwindow . example .cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(new ParameterizedThreadStart(MyLongCalculation));
ParameterClass myParameters = new ParameterClass();
thread.Start(myParameters);
}
public void MyLongCalculations(object myvalues)
{
ParameterClass values = (ParameterClass)myvalues;
//some calculations
}
}
public class ParameterClass
{
//public variables...
}
现在不知何故,我必须在我的方法mylongcalculation中包含一些东西,它将不断更新progressBar1
。然而,我就是不能让它工作。我知道这一切都很简单,但不幸的是,这是我目前对c#的水平,所以我希望答案不要太复杂,尽可能详细。
Background worker非常适合这个。
试试这个:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
// Initialize UI
InitializeComponent();
// Process data
ProcessDataAsync(new ParameterClass { Value = 20 });
}
/// <summary>
/// Processes data asynchronously
/// </summary>
/// <param name="myClass"></param>
private void ProcessDataAsync(ParameterClass myClass)
{
// Background worker
var myWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
};
// Do Work
myWorker.DoWork += delegate(object sender, DoWorkEventArgs e)
{
// Set result
e.Result = MyLongCalculations(myClass);
// Update progress (50 is just an example percent value out of 100)
myWorker.ReportProgress(50);
};
// Progress Changed
myWorker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e)
{
myProgressBar.Value = e.ProgressPercentage;
};
// Work has been completed
myWorker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
{
// Work completed, you are back in the UI thread.
TextBox1.Text = (int) e.Result;
};
// Run Worker
myWorker.RunWorkerAsync();
}
/// <summary>
/// Performs calculations
/// </summary>
/// <param name="myvalues"></param>
/// <returns></returns>
public int MyLongCalculations(ParameterClass myvalues)
{
//some calculations
return (myvalues.Value*2);
}
}
/// <summary>
/// Custom class
/// </summary>
public class ParameterClass
{
public int Value { get; set; }
}
您可以使用Dispatcher.BeginInvoke()将UI更改推送到UI线程而不是工作线程。最重要的是——你需要访问Dispatcher,它与UI线程相关联,而不是你手动创建的工作线程。所以我建议缓存Dispatcher.Current
,然后在一个工作线程中使用,你可以通过ParametersClass或只是在类级别上声明一个dispatchr字段。
public partial class MainWindow
{
private Dispatcher uiDispatcher;
public MainWindow()
{
InitializeComponents();
// cache and then use in worker thread method
this.uiDispatcher = uiDispatcher;
}
public void MyLongCalculations(object myvalues)
{
ParameterObject values = (ParameterObject)myvalues;
this.uiDispatcher.BeginInvoke(/*a calculations delegate*/);
}
}
另外,如果你需要在一些服务/类(如ParametersClass
)中传递一个UI调度程序,我建议看看这个漂亮的SO帖子,它展示了如何通过一个接口抽象它,能够同步/异步地推送UI更改,因此它将取决于调用者(基本上使用Invoke()
或BeginInvoke()
在UI消息管道中排队委托)。