Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用backgroundWorker和大量动画维护响应迅速的用户界面_C#_Multithreading_Backgroundworker - Fatal编程技术网

C# 使用backgroundWorker和大量动画维护响应迅速的用户界面

C# 使用backgroundWorker和大量动画维护响应迅速的用户界面,c#,multithreading,backgroundworker,C#,Multithreading,Backgroundworker,我有一个C#应用程序(winforms和wpf,但对于这个问题,我关注的是winforms),其中backgroundWorker用于处理数据集,对ProgressChanged的调用随后调用form Refresh方法强制重新绘制。然后根据数据集的当前帧绘制一组椭圆 一个给定的框架可能需要绘制零到几百个椭圆之间的任意位置 此外,我还有一个滑块控件,允许用户调整播放速率(基本上是循环中的thread.sleep值) 当用户将sleep值设置得太低时,有时重新绘制方法会排队,UI会变得无响应。(这

我有一个C#应用程序(winforms和wpf,但对于这个问题,我关注的是winforms),其中backgroundWorker用于处理数据集,对ProgressChanged的调用随后调用form Refresh方法强制重新绘制。然后根据数据集的当前帧绘制一组椭圆

一个给定的框架可能需要绘制零到几百个椭圆之间的任意位置

此外,我还有一个滑块控件,允许用户调整播放速率(基本上是循环中的thread.sleep值)

当用户将sleep值设置得太低时,有时重新绘制方法会排队,UI会变得无响应。(这取决于帧中椭圆的数量和计算机的速度。在UI上重新绘制时,延迟为100%,而不是任何其他处理,基本上只是增加计数器和设置标签文本。)

我希望能够检测排队并自动调整速度滑块,以适应更大的数据集和/或更慢的计算机。如何判断UI线程是否通过多次调用Map_Paint进行备份

现行守则(释义):

publicmap()
{
初始化组件();
_worker=新的BackgroundWorker();
_worker.DoWork+=\u worker\u DoWork;
_worker.ProgressChanged+=\u worker\u ProgressChanged;
_worker.WorkerReportsProgress=true;
}
私有void\u worker\u DoWork(对象发送方,DoWorkEventArgs e)
{
_frameCount=_frames.frameCount();
//对于此特定示例,帧计数可能在30000-40000左右
对于(变量i=0;i<\u帧数;i++)
{
var f=_frames.frames(i+1);
_工人进度报告(i,f);
线程。睡眠(_tickCount);
_suspend.WaitOne();//用于暂停播放
}
}
void\u worker\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
//根据此处截取的状态和百分比设置一些变量
// ...
//此时,我想检测是否备份了屏幕重新绘制
//如果是这样,调整_tickCount的值以降低程序的速度。
这个。刷新();
}
私有void Map_Paint(对象发送器,PaintEventArgs e)
{
//这里有很多省略号绘图的东西
//可能每个周期绘制0-1000个椭圆。
}
私有void tbSpeed_滚动(对象发送方,事件参数e)
{
//这是滑块的滚动事件。
//数值范围为10-300
//当UI线程备份时,滑块将变得无响应。
//我想检测备份并覆盖_tickCount的值
_滴答声=tbSpeed.值;
}
私有静态对象_lock=new object();
私有静态int_queuedCount=0;
公共地图()
{
初始化组件();
_worker=新的BackgroundWorker();
_worker.DoWork+=\u worker\u DoWork;
_worker.ProgressChanged+=\u worker\u ProgressChanged;
_worker.WorkerReportsProgress=true;
}
私有void\u worker\u DoWork(对象发送方,DoWorkEventArgs e)
{
_frameCount=_frames.frameCount();
//对于此特定示例,帧计数可能在30000-40000左右
对于(变量i=0;i<\u帧数;i++)
{
var f=_frames.frames(i+1);
锁
{
_queuedCount++;
}
_工人进度报告(i,f);
线程。睡眠(_tickCount);
_suspend.WaitOne();//用于暂停播放
}
}
void\u worker\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
如果(_queuedCount>1)
//现在排队的人越来越多了
这个。刷新();
锁
{
_队列计数--;
}
}

解决您描述的问题的第一步是降低工作线程的线程优先级,以确保UI线程(以“正常”优先级运行)在有工作要做时始终获得优先级。请注意,WM_PAINT消息不是真实的消息;当消息队列为空且需要绘制时,Windows会根据需要生成它们。因此,您无法实际检查WM_PAINT消息是否正在备份(它们从未备份)。您可以使用本机代码检查消息队列长度本身,但此处不需要这样做。建议不错。我也要试试。
public Map()
{
  InitializeComponent();

  _worker = new BackgroundWorker();
  _worker.DoWork += _worker_DoWork;
  _worker.ProgressChanged += _worker_ProgressChanged;
  _worker.WorkerReportsProgress = true;
}

private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
    _frameCount = _frames.FrameCount();
    // For this specific example, _frameCount may be around 30000-40000
    for (var i = 0; i < _frameCount; i++)
    {
      var f = _frames.Frame(i + 1);
      _worker.ReportProgress(i, f);
      Thread.Sleep(_tickCount);
      _suspend.WaitOne(); // Used to Pause the playback
    }
}
void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  // set some variables according to state and progresspercentage snipped here
  // ...

  // I would like to detect at this point whether the screen repainting is backed up
  // and if so, adjust the value of _tickCount to slow down the program.

  this.Refresh();
}

private void Map_Paint(object sender, PaintEventArgs e)

{
    // Lots of ellipsis drawing stuff here
    // Maybe 0-1000 ellipses drawn per cycle.
}

private void tbSpeed_Scroll(object sender, EventArgs e)
{
  // This is the Scroll event for the slider.
  // Value range is 10-300
  // The slider becomes unresponsive when the UI thread backs up.
  // I'd like to detect the back up and override the value of _tickCount
  _tickCount = tbSpeed.Value;
}
private static object _lock = new object();
private static int _queuedCount = 0;

public Map()
{
  InitializeComponent();

  _worker = new BackgroundWorker();
  _worker.DoWork += _worker_DoWork;
  _worker.ProgressChanged += _worker_ProgressChanged;
  _worker.WorkerReportsProgress = true;
}

private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
    _frameCount = _frames.FrameCount();
    // For this specific example, _frameCount may be around 30000-40000
    for (var i = 0; i < _frameCount; i++)
    {
      var f = _frames.Frame(i + 1);
      lock(_lock)
      {
          _queuedCount++;
      }
      _worker.ReportProgress(i, f);
      Thread.Sleep(_tickCount);
      _suspend.WaitOne(); // Used to Pause the playback
    }
}
void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  if (_queuedCount > 1)
      //now queue is building up

  this.Refresh();
  lock(_lock)
  {
      _queuedCount--;
  }
}