2012-05-14 2 views
1

У меня есть пример, который повторяет то, что я пытаюсь выполнить. Как будет выглядеть следующий код: у меня есть ViewModel, который обновляет свойство ObservableCollection, связанное с представлением. Обычно я обновлял коллекцию из результата, полученного из модели, но, надеюсь, этого примера будет достаточно.Использование MVVM в представлении с длинным ходом

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Windows.Controls; 

namespace MVVMWpf.ViewModel 
{ 
    public class ListViewModel 
    { 

     public ObservableCollection<int> SomeObjectCollection { get; set; } 

     public ListViewModel() 
     { 

      SomeObjectCollection = new ObservableCollection<int>(); 

     } 

     public void Do() 
     { 
      for (int i = 1; i < 1000000; i++) 
      { 
       int i1 = i; 
       SomeObjectCollection.Add(i1); 
      } 
     } 

    } 
} 

К сожалению, этот элемент блокирует этот пользовательский интерфейс. Он будет обновлять только представление, когда цикл завершается. То, как я это решил, нарушает концепции MVVM. Вот почему мне нужна твоя помощь. Я сделал это так.

public class ListViewModel 
{ 
    private delegate void LongRunningProcess(); 
    public ObservableCollection<int> SomeObjectCollection { get; set; } 
    private ListBox listBox; 
    public ListViewModel(ListBox listBox) 
    { 
     this.listBox = listBox; 
     SomeObjectCollection = new ObservableCollection<int>(); 

    } 

    public void Do() 
    { 
     Thread thread = new Thread(() => 
     { 
      for (int i = 1; i < int.MaxValue; i++) 
      { 
       int i1 = i; 
       listBox.Dispatcher.Invoke(
        new LongRunningProcess(() => 
        SomeObjectCollection.Add(i1); 
       }}); 

     thread.SetApartmentState(ApartmentState.STA); 
     thread.Start(); 
    } 

} 

Как вы можете видеть, теперь ViewModel знает о элементе listBox из пользовательского интерфейса. И, глядя на диаграмму MVVM, только View должен иметь ссылку на ViewModel через привязку. Как решить эту проблему? Спасибо.

+0

Как решить какую проблему? –

ответ

3

Вам нужно, чтобы ваш цикл раскрутить обновления экрана - своего рода DoEvents() будет делать:

public static void DoEvents() 
{ 
    Application.Current.Dispatcher.Invoke(
    DispatcherPriority.Background,new Action(delegate { })); 
} 

Добавьте его и называют, что из вашего цикла.


Использование таймера в качестве другого варианта, ваш код должен выглядеть Somthing так:

private System.Timers.Timer operationsTimer = new System.Timers.Timer(); 
private int x; 

в вашем CTOR:

operationsTimer.Elapsed += new System.Timers.ElapsedEventHandler 
(operationsTimer_Elapsed); 
operationsTimer.Enabled = true; 

в таймер elpased:

operationsTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    operationsTimer.Enabled = false; 
    //add item to collection code 
    x++; 
    if(x<100) 
     operationsTimer.Enabled = true; 
} 
+0

Lol funny, я действительно нашел это сразу после размещения вопроса. Но это вызывает исключение, когда я закрываю программу ... –

+0

Другой вариант - использовать таймер вместо цикла в потоке. –

+0

Если я могу справиться с этим исключением, это звучит как решение, которое я хочу. Есть ли способ закрыть все потоки приложения. Может быть, я должен слушать события window.close –

0

Рассмотрите возможность использования BackgroundWorker, простой способ выполнения асинхронных задач с функциональностью для отчетности о прогрессе, а также завершенное событие. Лучше всего, вам не нужно вызывать что-либо на диспетчере, так как функции BackgroundWorker синхронизируются с потоком пользовательского интерфейса.

Смежные вопросы