Files
lserp_cs_6.0/插件库/Lskj.Control/LatestValueWorker.cs
T

118 lines
3.0 KiB
C#

using System;
using System.Threading;
namespace Lskj.Control
{
/// <summary>
/// 串行处理请求,并在繁忙时只保留最后一次请求。
/// 用于输入联想控件,避免每次 TextChanged 都创建独立线程。
/// </summary>
internal sealed class LatestValueWorker<T> : IDisposable
{
private readonly object _syncRoot = new object();
private readonly Action<T, int> _work;
private T _pendingValue;
private bool _hasPendingValue;
private bool _workerRunning;
private bool _disposed;
private int _version;
public LatestValueWorker(Action<T, int> work)
{
if (work == null)
{
throw new ArgumentNullException("work");
}
_work = work;
}
public int Queue(T value)
{
bool startWorker = false;
int version;
lock (_syncRoot)
{
if (_disposed)
{
return -1;
}
version = ++_version;
_pendingValue = value;
_hasPendingValue = true;
if (!_workerRunning)
{
_workerRunning = true;
startWorker = true;
}
}
if (startWorker && !ThreadPool.QueueUserWorkItem(Run))
{
lock (_syncRoot)
{
_workerRunning = false;
}
throw new InvalidOperationException("无法启动输入联想查询任务。");
}
return version;
}
public bool IsCurrent(int version)
{
lock (_syncRoot)
{
return !_disposed && version == _version;
}
}
private void Run(object state)
{
while (true)
{
T value;
int version;
lock (_syncRoot)
{
if (_disposed || !_hasPendingValue)
{
_workerRunning = false;
return;
}
value = _pendingValue;
version = _version;
_pendingValue = default(T);
_hasPendingValue = false;
}
try
{
_work(value, version);
}
catch
{
// 查询异常由控件自身转换为空结果;这里确保工作循环能够继续或退出。
}
}
}
public void Dispose()
{
lock (_syncRoot)
{
_disposed = true;
_hasPendingValue = false;
_pendingValue = default(T);
_version++;
}
}
}
}