2012-11-07 3 views
5

저는 미디어 플레이어를 만들고 있습니다. 검색하는 키워드를 입력하는 등 실시간 검색 기능을 추가하여 노래 등을 검색했습니다 (WMP 실시간 검색과 같은 일부 기능).별도의 UI 스레드에서 WPF 컨트롤?

검색 프로세스 중에 데이터베이스에 액세스하고 IEnumerable을로드하는 작업은 BackGroundProcess를 통해 다른 스레드에서 수행됩니다. UI는 UIElement의 디스패처를 호출하여 업데이트됩니다.

이 과정은 다소 빠르지 만 텍스트 상자에 검색 키워드를 입력 할 때 약간의 지연이있는 것처럼 보입니다. 이는 Listbox.ItemSource 업데이트에 약간의 시간이 걸리는 것입니다. 즉, "Adele"을 검색하고 싶다고 말하면 "a"를 입력하면 검색 기능이 "A"에 대한 결과를로드하지만 단어 "Adele"을 입력 할 때 " d ""e ""l ""e "이 문자 사이에 약간의 지연이 있습니다.

이 검색 프로세스 중에 UI 업데이트를 중지하면 검색 프로세스가 매우 부드럽게 보입니다. 이것은 목록 상자가 스레드를 잠그고 있다는 것을 의미하기 때문에 Listbox가있는 동안 나머지 플레이어 UI가 거기에 붙어 있습니다. 처리가 완료되었습니다.

목록 상자 컨트롤을 다른 UI 스레드에 넣을 수 있으면 목록 상자를로드하는 데 걸리는 시간과 관계없이 플레이어의 부드러운 흐름을 유지할 수 있다고 생각합니다. FYI : 데이터 가상화가 있습니다 & ListBox에 UI 가상화가 있습니다.

ListBox 컨트롤을 다른 UI 스레드에 넣을 수 있습니까? WPF, C#을 사전 : ASP.NET에서

+0

사실 내가 본 적이있는 실현 가능한 방법은 없습니다. – Servy

+0

.net 4.5 사용?여기에 당신을 위해 쉬운 승리가 될 수있는 바인딩에 좋은 Delay 속성이 있습니다. 기본적으로 100ms와 같은 값으로 설정됩니다. 사용자가 해당 시간 동안 타이핑을 멈 추면 (또는 Enter 또는 텍스트 상자를 누르면 바인딩 만 업데이트됩니다. 포커스를 잃음) – Andy

+1

하나 뿐인 UI 스레드가 있습니다. –

답변

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를 사용하는 f를 바인딩 당신의 Delay 특성이있다 볼 수 있습니다.

+0

고마워요, 지금 확인해 볼게요 !! – Xero

+0

Yessss !! 매력처럼 작동합니다! 매우 유용한 코드 조각! – Xero

+0

@ Xero를 사용하면 Microsoft의 ReactiveExtensions를 살펴 보는 것이 좋습니다. (Rx). 제가 본 많은 튜토리얼은 쿼리를 매우 쉽게 조절할 수있는 방법을 보여주기위한 요점이되었습니다. – Thelonias

1

에서

덕분하는 데는 보통 우리는 검색을 시작하기에 대부분의 3 문자 두 techiniques

  • 대기를 사용합니다.
  • 사용자가 입력을 중지하고 검색을 시작하기 전에 몇 밀리 초가 지나면 사용자가 몇 밀리 초보다 빠르게 입력하므로 검색어에 둘 이상의 문자가 포함됩니다. 이 두 번째 옵션은 사용자가 타이핑을 시작하고이 키를 누를 때마다이 타이머를 0으로 설정 (중지하지 않고)하도록 설정할 때 타이머를 시작하는 것으로 구성됩니다. 당신이 검색 기준에 3 개 이상의 문자를 한 경우에만 검색하고를 사용 : 사용자 (예에 의해) 2000 밀리 초 동안 입력을 중지하면 당신은 완벽한 방법은이 두 techiniques을 결합하는 것입니다

검색을 수행 시간제 노동자. 당신이 모든 키를 누를 때의 데이터베이스를 조회하는 경우

관련 문제