C# WPF文本框搜索
我有一个快速查找文本框。我想筛选包含quickFind字符串的记录集合C# WPF文本框搜索,c#,wpf,reactiveui,C#,Wpf,Reactiveui,我有一个快速查找文本框。我想筛选包含quickFind字符串的记录集合 我怎样才能延迟搜索,直到用户停止键入2秒钟?下面是一个我希望能帮你解决问题的类。包括底部显示的示例用法 public class EventDelayer { /// <summary> /// Contains info on an individual event that was queued; /// </summary> public class Delay
我怎样才能延迟搜索,直到用户停止键入2秒钟?下面是一个我希望能帮你解决问题的类。包括底部显示的示例用法
public class EventDelayer
{
/// <summary>
/// Contains info on an individual event that was queued;
/// </summary>
public class DelayedEventInfo
{
private readonly object _sender;
private readonly EventArgs _eventArgs;
private readonly DateTime _eventTime;
public DelayedEventInfo(object sender, EventArgs eventArgs, DateTime eventTime)
{
_sender = sender;
_eventArgs = eventArgs;
_eventTime = eventTime;
}
public object Sender { get { return _sender; } }
public EventArgs EventArgs { get { return _eventArgs; } }
public DateTime EventTime { get { return _eventTime; } }
}
/// <summary>
/// contains a list of
/// </summary>
public class DelayedEventArgs : EventArgs, IEnumerable<DelayedEventInfo>
{
private readonly List<DelayedEventInfo> _eventInfos;
public DelayedEventArgs(IEnumerable<DelayedEventInfo> eventInfos)
{
_eventInfos = new List<DelayedEventInfo>(eventInfos);
}
public IEnumerator<DelayedEventInfo> GetEnumerator()
{
return _eventInfos.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _eventInfos.GetEnumerator();
}
}
private readonly List<DelayedEventInfo> _infoList = new List<DelayedEventInfo>();
private readonly TimeSpan _delayTime;
private readonly object _lock = new object();
private System.Threading.Timer _timer;
public event EventHandler<DelayedEventArgs> DelayedEvent;
public EventDelayer(TimeSpan delayTime)
{
_delayTime = delayTime;
}
/// <summary>
/// call to 'enqueue' an event.
/// </summary>
public void Enqueue(object sender, EventArgs args)
{
lock (_lock)
{
_infoList.Add(new DelayedEventInfo(sender, args, DateTime.Now));
if (_timer != null)
{
_timer.Dispose();
_timer = null;
}
_timer = new System.Threading.Timer(ThreadProc, this, _delayTime, TimeSpan.FromMilliseconds(-1));
}
}
/// <summary>
/// raises the event.
/// </summary>
private void HandleTimer()
{
lock (_lock)
{
var ev = this.DelayedEvent;
if (ev != null)
{
DelayedEventArgs args = new DelayedEventArgs(_infoList);
Invoke(()=> ev(this, args));
}
_infoList.Clear();
}
}
private static void ThreadProc(Object stateInfo)
{
EventDelayer thisObj = (EventDelayer)stateInfo;
thisObj.HandleTimer();
}
private static Lazy<System.Windows.Threading.Dispatcher> _dispatchObject = new Lazy<System.Windows.Threading.Dispatcher>(() =>
{
if (Application.Current != null)
{
return Application.Current.Dispatcher;
}
else
{
return null;
}
});
public static void Invoke(Action action)
{
if (_dispatchObject.Value == null || _dispatchObject.Value.CheckAccess())
{
action();
}
else
{
_dispatchObject.Value.Invoke(action);
}
}
}
private class ExampleUsage
{
/// <summary>
/// shows how to create a event delayer and use it to listen to the events from a text box and call if no further changes for 2 seconds.
/// </summary>
private static void ShowUsage(System.Windows.Controls.TextBox textBox)
{
EventDelayer eventDelayer = new EventDelayer(TimeSpan.FromSeconds(2));
textBox.TextChanged += eventDelayer.Enqueue;
eventDelayer.DelayedEvent += eventDelayer_DelayedEvent;
}
/// <summary>
/// redo search here. if required you can access the event args originally raised from the textbox through the event args of this method
/// </summary>
static void eventDelayer_DelayedEvent(object sender, EventDelayer.DelayedEventArgs e)
{
foreach (var eventInfo in e)
{
var originalSender = eventInfo.Sender;
var args = eventInfo.EventArgs;
var timeInitiallyCalled = eventInfo.EventTime;
}
}
}
公共类事件延迟器
{
///
///包含排队的单个事件的信息;
///
公共类DelayedEventInfo
{
私有只读对象\u发送方;
私有只读事件args\u事件args;
私有只读日期时间_eventTime;
public DelayedEventInfo(对象发送方、EventArgs EventArgs、DateTime eventTime)
{
_发送方=发送方;
_eventArgs=eventArgs;
_eventTime=eventTime;
}
公共对象发送方{get{return}\u Sender;}
public EventArgs EventArgs{get{return\u EventArgs;}}
public DateTime EventTime{get{return\u EventTime;}}
}
///
///包含以下内容的列表:
///
公共类DelayedEventArgs:EventArgs,IEnumerable
{
私有只读列表_eventInfos;
公共延迟事件目标(IEnumerable eventInfos)
{
_eventInfos=新列表(eventInfos);
}
公共IEnumerator GetEnumerator()
{
返回_eventInfos.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
返回_eventInfos.GetEnumerator();
}
}
私有只读列表_infoList=新列表();
私有只读时间span\u delayTime;
私有只读对象_lock=新对象();
专用系统.Threading.Timer\u Timer;
公共事件处理程序DelayedEvent;
公共事件延迟器(TimeSpan delayTime)
{
_延迟时间=延迟时间;
}
///
///调用“排队”事件。
///
public void排队(对象发送方、事件args args)
{
锁
{
_Add(newdelayedeventinfo(sender,args,DateTime.Now));
如果(_timer!=null)
{
_timer.Dispose();
_定时器=空;
}
_timer=new System.Threading.timer(ThreadProc,this,_delayTime,TimeSpan.frommilless(-1));
}
}
///
///引发事件。
///
私有void HandleTimer()
{
锁
{
var ev=此.DelayedEvent;
如果(ev!=null)
{
DelayedEventTargets args=新的DelayedEventTargets(\u信息列表);
调用(()=>ev(this,args));
}
_infoList.Clear();
}
}
私有静态void ThreadProc(对象状态信息)
{
EventDelayer thisObj=(EventDelayer)状态信息;
thisObj.HandleTimer();
}
private static Lazy_dispatchObject=新的Lazy(()=>
{
if(Application.Current!=null)
{
返回Application.Current.Dispatcher;
}
其他的
{
返回null;
}
});
公共静态无效调用(操作)
{
如果(_dispatchObject.Value==null | | | _dispatchObject.Value.CheckAccess())
{
动作();
}
其他的
{
_dispatchObject.Value.Invoke(操作);
}
}
}
私有类示例用法
{
///
///演示如何创建事件延迟器,并使用它从文本框中侦听事件,并在2秒钟内没有进一步更改时调用。
///
专用静态void ShowUsage(System.Windows.Controls.TextBox TextBox)
{
EventDelayer EventDelayer=新的EventDelayer(TimeSpan.FromSeconds(2));
textBox.TextChanged+=eventDelayer.Enqueue;
eventDelayer.DelayedEvent+=eventDelayer\u DelayedEvent;
}
///
///重做此处搜索。如果需要,您可以通过此方法的事件参数访问最初从文本框中引发的事件参数
///
静态void eventDelayer\u DelayedEvent(对象发送方,eventDelayer.DelayedEventArgs e)
{
foreach(e中的var eventInfo)
{
var originalSender=eventInfo.Sender;
var args=eventInfo.EventArgs;
var timeInitiallyCalled=eventInfo.EventTime;
}
}
}
将文本框文本绑定到字符串,然后设置绑定延迟
<TextBox>
<TextBox.Text>
<Binding Path="searchText" UpdateSourceTrigger="PropertyChanged" Delay="2000" />
</TextBox.Text>
</TextBox>
以下是完成整个过程的反应式UI方法(在2秒延迟后过滤项目):
我喜欢计时器和锁的例子,因为它显示了反应UI是多么简单:)时间戳框从空变为有字符的点,然后每次发生更改时,检查以确保在调用搜索函数之前至少2秒。嗯,这很有效,很简单,但事实也是如此untestable@Paul“不稳定”是什么意思。您当然可以编写一个测试来进行搜索,因为您可以将绑定绑定到自己的字符串。您不必测试延迟,它是framework.BTW的一部分,延迟属性仅在WPF 4.5或更高版本中可用。
// These are defined in your ViewModel class as settable Properties
string FilterText;
ReactiveList<Record> ListOfRecords;
IReactiveDerivedList<Record> FilteredRecords;
// This is in your ViewModel constructor
FilteredRecords = ListOfRecords.CreateDerivedCollection(
x => !String.IsNullOrWhiteSpace(FilterText) ? recordContainsString(FilterText) : true,
x => x.Id,
this.WhenAnyValue(x => x.FilterText).Throttle(TimeSpan.FromSeconds(2.0));
this.WhenAnyValue(x => x.SomeProperty)
.Throttle(TimeSpan.FromSeconds(2.0), RxApp.MainThreadScheduler)
.Subscribe(x => Console.WriteLine("The item is " + x);