2016-07-25 5 views
0

タイマが呼び出されるたびにUpdateDocumentsListFromServer UIが3秒間フリーズします。 .net 3.5で非同期スタイルのリストを更新するには?DispatcherTimer WPF async

のViewModel:

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; } 

    } 

GetDocumentsFromServerが

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() 'や' '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へのアクセスを派遣。

0

コメントに記載されているとおり、DispatcherTimerの代わりにTimersを使用できます。 DispactherTimerはTimerがスレッドプールから別のスレッドを使用する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です –

関連する問題