我怎样才能保持同步更新我的列表框
How can I keep updating my ListBox synchronously
我正在使用以下代码计算两个数字之间的素数
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
该代码看起来不错,您只是忘记通过调用 BackgroundWorker.RunWorkerAsync.
来 启动 您的后台工作程序
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);
}
}
你只是 post 太多了。此代码按预期工作:
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 class。此外,不要使用平台的同步机制,而是尝试切换到平台独立的 SynchronizationContext。
您可以 post 成串地获得结果,而不是休眠一个线程:
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
。
我正在使用以下代码计算两个数字之间的素数
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
该代码看起来不错,您只是忘记通过调用 BackgroundWorker.RunWorkerAsync.
来 启动 您的后台工作程序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);
}
}
你只是 post 太多了。此代码按预期工作:
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 class。此外,不要使用平台的同步机制,而是尝试切换到平台独立的 SynchronizationContext。
您可以 post 成串地获得结果,而不是休眠一个线程:
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
。