2016-07-25 1 views
0

타이머를 호출 할 때마다 UpdateDocumentsListFromServer UI가 3 초 동안 정지합니다. .net 3.5에서 비동기 스타일로 목록을 업데이트하는 방법은 무엇입니까?DispatcherTimer WPF async

뷰 모델 :

public class ShippingDocumentsRegisterViewModel : ViewModelBase 
    { 
     ShippingDocumentsModel model = new ShippingDocumentsModel(); 

     DispatcherTimer timer = new DispatcherTimer(); 

     BackgroundWorker BW = new BackgroundWorker(); 

     public ShippingDocumentsRegisterViewModel() 
     { 
      timer = new DispatcherTimer(); 
      timer.Tick += new EventHandler(UpdateDocumentsListFromServer); 
      timer.Interval = new TimeSpan(0, 0, 10); 
      timer.Start(); 

      this.Columns = model.InitializeColumns(); 
      BW.DoWork += UpdateDocumentsList; 
      BW.RunWorkerAsync(); 
     } 

     public void UpdateDocumentsList(object o, EventArgs args) 
     { 
      this.ShippingDocuments = model.GetDocuments(); 
     } 

     public void UpdateDocumentsListFromServer(object o, EventArgs args) 
     { 
      // Taking a lot of time. How to do it async? 
      var tempDocuments = model.GetDocumentsFromServer(); 
      foreach (var item in tempDocuments) 
      { 
       this.shippingDocuments.Add(item); 
      } 
      // 
     } 

     private ObservableCollection<ShippingDocument> shippingDocuments; 

     public ObservableCollection<ShippingDocument> ShippingDocuments 
     { 
      get 
      { 
       return shippingDocuments; 
      } 

      private set 
      { 
       shippingDocuments = value; 
       RaisePropertyChanged("ShippingDocuments"); 
      } 
     } 

     public ObservableCollection<ShippingDocumentColumDescriptor> Columns { get; private set; } 

    } 

public ObservableCollection<ShippingDocument> GetDocumentsFromServer() 
    { 
     System.Threading.Thread.Sleep(3000); 
     return new ObservableCollection<ShippingDocument> { new ShippingDocument { Name = "Test" } }; 
    } 
+0

'Sleep (3000)'이 있기 때문에 얼어 버립니다. 아마도 바인딩 [IsAsync] (https://msdn.microsoft.com/en-us/library/system.windows.data.binding.isasync (v = vs.110) .aspx)을 설정하려고합니다. 재산이 되겠습니까?) 또 다른 * 옵션은'GetDocumentsFromServer'를'async'로 정의하고 비동기 메소드 (예 :'await Task.Delay()'또는'await Task.Run (() => Thread.Sleep())'를 사용하는 것입니다. 소원). – Sinatr

+0

@Sinatr, 그렇습니다. Sleep (3000) freez UI가 있습니다. 장기간 실행되는 작업을 모방합니다. .net 3.5에는 비동기식 메소드가 없습니다. – A191919

+5

나는 'DispactherTimer' 대신 [Timer] (https://msdn.microsoft.com/en-us/library/zdzx8wx8.aspx)로 갈 것을 제안합니다. 'DispactherTimer'는 스레드 풀에서'Timer' 스레드를 사용하는 UIThread에 접근합니다. – Gopichandar

답변

1

또한 /과 같이 기다리고 있습니다 그냥 작업 및 비동기를 사용하여 새 스레드에 오프로드 UI를

public ShippingDocumentsRegisterViewModel() 
{ 

    BW.DoWork += UpdateDocumentsListFromServer; 
    BW.RunWorkerCompleted += BW_RunWorkerCompleted; 

    BW.WorkerReportsProgress = true; 
    BW.ProgressChanged += UpdateGui; 
    BW.RunWorkerAsync(); 
} 
public void UpdateGui(object o, EventArgs args) 
{ 
    foreach (var item in tempDocuments) 
    { 
     this.shippingDocuments.Add(item); 
    } 
} 
public void UpdateDocumentsListFromServer(object o, EventArgs args) 
{ 

    while (true) { 
     System.Threading.Thread.Sleep(3000); 

     tempDocuments = GetDocumentsFromServer(); 
     BW.ReportProgress(0); 

    } 
} 

int num = 0; 
public ShippingDocument[] GetDocumentsFromServer() 
    { 
     System.Threading.Thread.Sleep(3000); 
     return new ShippingDocument[1] { new ShippingDocument { Name = "Test" + num++} }; 
    } 

private ShippingDocument[] tempDocuments = new ShippingDocument[0]; 
+0

분명히 RunWorkerCompleted가있는 행은 실행되지 않는 한 부적절합니다 ... –

0

를 사용하여 정기적으로 Timer처럼 만 shippingDocuments에 대한 액세스를 파견 GetDocumentsFromServer.

0

의견에서 언급했듯이 DispatcherTimer 대신 Timers을 사용할 수 있습니다. DispactherTimer은 Timer가 threadpool에서 다른 스레드를 사용하는 UIThread에 액세스합니다.

또한, 다른 스레드 도움이

Application.Current.Dispatcher.BeginInvoke(new Action(() => 
      { 
       //Do some UI stuffs     
      })); 

희망에서 UIThread에 작업을 전달할 수 있습니다. 마음에

public async void UpdateDocumentsListFromServer(object o, EventArgs args) 
     { 
      // This will execute async and return when complete 
      await Task.Run(()=>{ 
       var tempDocuments = model.GetDocumentsFromServer(); 
       foreach (var item in tempDocuments) 
       { 
        this.shippingDocuments.Add(item); 
       } 
      }); 
      // 
     } 

유지 :

0

에 진행 상황을보고하는 배경 노동자를 사용할 수 있습니다 이 스레드는 UI와 다른 스레드에서 업데이트됩니다. 따라서 UI 스레드에서 아무 것도 건드릴 수 없거나 스레딩 문제가 발생합니다. 따라서 shippingDocuments가 UI 스레드에서 생성되었고 스레드로부터 안전하지 않은 경우 대신 항목 모음을 반환하고 추가 할 수 있습니다.

public async void UpdateDocumentsListFromServer(object o, EventArgs args) 
     { 
      // Execute on background thread and put results into items 
      var items = await Task.Run(()=>{ 
       var tempDocuments = model.GetDocumentsFromServer();     
       return tempDocuments; 
      }); 
      //add occurs on UI thread. 
      this.shippingDocuments.AddRange(tempDocuments); 
     } 
+0

몇 가지 것들 1) 나는이 정확한 코드로 .NET 3.5를 사용하지 않는다고 추측합니다. 그러나 OP 질문의이 부분을 잊어 버렸습니다 :-) ... 2) 물론, ShippingDocuments는 UI입니다 –

관련 문제