如何保持同步更新我的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

如何保持同步更新我的ListBox

你只是发帖太多了。此代码按预期工作:

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);
        }            
    }