Я нахожусь в середине приложения MVVM. Здесь у меня есть коллекция (ObservableCollection), которая может иметь операции добавления, удаления, выполненные из другого потока.
Вот код Я старался сделать его как можно более полным:
private Thread _thread = null;
private Dispatcher _UIDispatcher = null;
public ObservableCollection<string> ListOfStrings { get; private set; }
Ктор:
public MainWindowViewModel(Dispatcher dispatcher)
{
this.ListOfStrings = new ObservableCollection<string>();
this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
this._UIDispatcher = dispatcher;
}
Я принимаю диспетчера View в качестве справочного материала (хотя это не очень хорошая практика, поскольку это затрудняет юнит-тестирование. Гэри Холл предложил хороший подход с использованием AOP. Однако я могу изменить это позже в любое время.). И тогда этот метод, который я вызываю с помощью команды
private void AsyncCall()
{
if (this.ListOfStrings.Count > 0)
this.ListOfStrings.Clear();
//_backgroundWorker.RunWorkerAsync();
this._thread = new Thread(new ThreadStart(AddNumbersToList));
this._thread.IsBackground = true;
this._thread.Start();
}
private void AddNumbersToList()
{
Action delAddNum = new Action(AddNumbersToList);
for (int i = 0; i < 100000000; i++)
{
if (null != this._UIDispatcher &&
!this._UIDispatcher.CheckAccess())
_UIDispatcher.Invoke(DispatcherPriority.Render,delAddNum);
else
{
this.ListOfStrings.Add(Convert.ToString(i.ToString()));
}
}
}
ObservableCollection привязывается к списку в представлении.
Эффект, который я ожидал, состоял в том, что, поскольку ObservableCollection добавляет новые числа, они должны отображаться в пользовательском интерфейсе. Пользовательский интерфейс тоже будет отзывчивым. Но, как ни странно, пользовательский интерфейс не отвечает. То же самое, когда я пытаюсь достичь с помощью фонового работника, прекрасно достигается. Может кто-нибудь, пожалуйста, укажите, где я иду не так. Я не хочу переходить к фоновому работнику, поскольку хочу гибкости использования более детального класса Thread.
Ниже приведен код, который я использую с BGWorker, и он работает нормально:
private BackgroundWorker _backgroundWorker = new BackgroundWorker();
CTOR:
public MainWindowViewModel()
{
this.ListOfStrings = new ObservableCollection<string>();
this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
_backgroundWorker.DoWork += AddNumbersToList;
_backgroundWorker.RunWorkerCompleted += this.LoadResultsCompleted;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
}
Методы:
private void AsyncCall()
{
if (this.ListOfStrings.Count > 0)
this.ListOfStrings.Clear();
this._backgroundWorker.RunWorkerAsync();
}
private void AddNumbersToList(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if(null!=bw)
for (int i = 0; i < 10; i++)
{
bw.ReportProgress(0, i);
Thread.Sleep(1000);
}
}
private void LoadResultsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
this.ListOfStrings.Add("Completed");
CommandManager.InvalidateRequerySuggested();
}
}
//This works just wonderful:
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ListOfStrings.Add(Convert.ToString(e.UserState.ToString()));
}
Заранее спасибо.
.. Джеймс