fix: 收敛旧控件资源与后台线程生命周期
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user