如何保持同步更新我的ListBox
本文关键字:我的 ListBox 更新 同步 何保持 | 更新日期: 2024-10-21 12:17:20
我正在使用以下代码计算素数bw和两个数
private static IEnumerable<int> GetPrimes(int from, int to)
{
for (int i = from; i <= to; i++)
{
bool isPrime = true;
int limit = (int)Math.Sqrt(i);
for (int j = 2; j <= limit; j++)
if (i % j == 0)
{
isPrime = false;
break;
}
if (isPrime)
{
yield return i;
}
}
}
我想在不阻塞UI线程的情况下更新我的列表框,所有素数都使用上面的代码。我正在使用的方法如下,但这不起作用。
public MainWindow()
{
InitializeComponent();
_worker = new BackgroundWorker();
_worker.DoWork += _worker_DoWork;
this.DataContext = this;
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
PrimeNumbers = new ObservableCollection<int>();
foreach (var item in GetPrimes(1, 10000000))
{
Dispatcher.BeginInvoke(new Action<int>(Test), item);
}
}
private void Test(int obj)
{
PrimeNumbers.Add(obj);
}
public ObservableCollection<int> PrimeNumbers
{
get
{
return primeNumbers;
}
set
{
primeNumbers = value;
OnPropertyChanged("PrimeNumbers");
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
_worker.RunWorkerAsync();
}
但是这种方法冻结了我的UI。我希望GetPrimes方法的结果持续不断,并不断添加到我的listboz
你只是发帖太多了。此代码按预期工作:
public partial class MainWindow
{
public ObservableCollection<int> PrimeNumbers { get; set; }
public MainWindow()
{
InitializeComponent();
PrimeNumbers = new ObservableCollection<int>();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
PrintPrimes(PrimeNumbers.Add, 1, 10000000, SynchronizationContext.Current);
}
private static void PrintPrimes(Action<int> action, int from, int to,
SynchronizationContext syncContext)
{
Task.Run(() =>
{
for (var i = from; i <= to; i++)
{
var isPrime = true;
var limit = (int) Math.Sqrt(i);
for (var j = 2; j <= limit; j++)
{
if (i%j == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
syncContext.Post(state => action((int)state), i);
Thread.Sleep(1);
}
}
});
}
}
考虑避开旧的BackgroundWorker类。此外,不要使用平台的同步机制,而是尝试切换到独立于平台的SynchronizationContext。
不睡线程,你可以发布你的结果束:
public partial class MainWindow
{
public ObservableCollection<int> PrimeNumbers { get; set; }
public MainWindow()
{
InitializeComponent();
PrimeNumbers = new ObservableCollection<int>();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
PrintPrimes(items => items.ForEach(PrimeNumbers.Add),
1, 10000000, SynchronizationContext.Current);
}
private static void PrintPrimes(Action<List<int>> action, int from, int to,
SynchronizationContext syncContext)
{
Task.Run(() =>
{
var primesBuffer = new List<int>();
for (var i = from; i <= to; i++)
{
var isPrime = true;
var limit = (int) Math.Sqrt(i);
for (var j = 2; j <= limit; j++)
{
if (i%j == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
primesBuffer.Add(i);
if (primesBuffer.Count >= 1000)
{
syncContext.Post(state => action((List<int>) state),
primesBuffer.ToList());
primesBuffer.Clear();
}
}
}
});
}
}
如果使用旧版本的框架,可以使用Thread
而不是Task.Run
。
该代码看起来不错,您只是忘记了通过调用BackgroundWorker.RunWorkerSync.启动您的后台工作程序
PrimeNumbers = new ObservableCollection<int>();
这一行需要在工作线程之外(或者在UI线程中也被调用)。
我的UI似乎经常更新,所以我在后台工作线程上使用了1秒的延迟。它帮助我实现了的功能
private void _worker_DoWork(对象发送方,DoWorkEventArgs e){
foreach (var item in GetPrimes(1, 1000000))
{
Thread.Sleep(1000);
Dispatcher.BeginInvoke(new Action<int>(Test), item);
}
}