我知道这个问题已被问过几次,我花了一整天时间试图理解其他答案,但由于我对C#和WPF很新,所以到目前为止没有任何帮助。我将尝试尽可能多地解释我的确切问题,以便直接帮助我。
在我的MainWindow.xaml中,我有一个进度条和一些按钮开始一个新线程和一个长计算:
<ProgressBar Height="....... Name="progressBar1"/>
<Button Content="Button" Name="button1" Click="button1_Click" />
现在在我的MainWindow.xaml.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...
}
现在不知怎的,我必须在我的方法MyLongCalculations中包含一些不断更新progressBar1
的东西。但是,我无法让它运作起来。
我知道这一切都很简单,但不幸的是,这是我目前使用C#的水平,所以我希望答案不要太复杂,尽可能详细。
答案 0 :(得分:3)
后台工作人员很适合这个。
试试这个:
/// <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; }
}
答案 1 :(得分:0)
您可以使用Dispatcher.BeginInvoke()在UI线程而不是工作线程上推送UI更改。最重要的是 - 您需要访问与UI线程关联的Dispatcher,而不是您手动创建的工作线程。所以我建议缓存Dispatcher.Current
,然后在工作线程中使用,你可以通过ParametersClass执行此操作,或者只在类级别声明一个调度程序字段。
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*/);
}
}
此外,如果您需要在某个服务/类中传递UI调度程序(如ParametersClass
),我建议您查看this nice SO post,了解如何通过具有以下功能的接口来抽象它推送UI同步/异步更改,以便由调用者决定(基本上使用Invoke()
或BeginInvoke()
在UI消息管道中对委托进行排队)。