单独的UI线程上的WPF控件?

时间:2012-11-07 15:53:40

标签: c# wpf multithreading user-interface wpf-controls

我正在制作一个媒体播放器,现在..我已经添加了一个实时搜索功能来搜索歌曲等等(有些东西,比如WMP实时搜索),即输入关键字时搜索就会发生。

在搜索过程中,访问数据库并加载IEnumerable是通过BackGroundProcess在另一个线程上完成的。通过调用UIElement的调度程序来更新UI。

这个过程相当快,但是当你在文本框中输入搜索关键字时,似乎有一个小的延迟,这是因为Listbox.ItemSource更新需要一些时间。 也就是说你要搜索“Adele”,当你输入“a”时,搜索功能会加载“A”的结果,但是当我们输入整个单词“Adele”时,它有时间显示“d” “”e“”“l”“e”并且这些字母之间存在轻微的滞后。

在此搜索过程中,当我停止更新UI时,搜索过程看起来非常流畅,这只对我意味着Listbox锁定了线程,因此当Listbox完成时,播放器的UI的其余部分被卡在那里随着它的处理。

所以我相信如果我可以将Listbox Control放到另一个UI线程,我可以保持播放器的流畅,无论加载列表框所花费的时间。 仅供参考:数据虚拟化是存在的。 ListBox的UI虚拟化正在运行

如何将ListBox控件放到另一个UI线程上? WPF,C#

提前致谢:)

2 个答案:

答案 0 :(得分:5)

如果您在每次按键时查询数据库 - 这会导致您在快速键入(甚至正常)时出现延迟

您最好限制请求,我们使用它来限制调度程序线程。

public static class DispatcherExtensions
{
    private static Dictionary<string, DispatcherTimer> timers =
        new Dictionary<string, DispatcherTimer>();
    private static readonly object syncRoot = new object();

    public static string DelayInvoke(this Dispatcher dispatcher, string namedInvocation,
        Action action, TimeSpan delay,
        DispatcherPriority priority = DispatcherPriority.Normal)
    {
        lock (syncRoot)
        {
            if (String.IsNullOrEmpty(namedInvocation))
            {
                namedInvocation = Guid.NewGuid().ToString();
            }
            else
            {
                RemoveTimer(namedInvocation);
            }
            var timer = new DispatcherTimer(delay, priority, (s, e) =>
                {
                    RemoveTimer(namedInvocation);
                    action();
                }, dispatcher);
            timer.Start();
            timers.Add(namedInvocation, timer);
            return namedInvocation;
        }
    }


    public static void CancelNamedInvocation(this Dispatcher dispatcher, string namedInvocation)
    {
        lock (syncRoot)
        {
            RemoveTimer(namedInvocation);
        }
    }

    private static void RemoveTimer(string namedInvocation)
    {
        if (!timers.ContainsKey(namedInvocation)) return;
        timers[namedInvocation].Stop();
        timers.Remove(namedInvocation);
    } 


} 

假设您没有使用MVVM,您可以在按钮单击

中轻松使用它
Dispatcher.CurrentDispatcher.DelayInvoke("UpdateSearch",
       YourMethodThatStartsBackgroundThread,Timespan.FromSeconds(1));

另外值得注意的是:如果您使用的是4.5,那么您可以查看绑定上的Delay属性。

答案 1 :(得分:1)

在ASP.NET中,我们通常使用两种技术

  • 等待最多3个字符开始搜索。
  • 在用户停止输入后和开始搜索之前等待几毫秒,因为用户输入的速度超过几毫秒,您的搜索字词将包含多个字符。 第二个选项包括在用户开始输入时启动计时器,并在按下每个键时将此计时器设置为零(不停止)。当用户停止键入2000毫秒(例如)时,执行搜索

一种完美的方法是将这两种技术结合起来:只搜索搜索条件中是否有3个或更多字符,并使用计时器。