2017-02-08 7 views
1

Я создаю приложение с WPF и Caliburn.Micro. Я хочу, чтобы обновить ProgressBar из задач/Темы и мне интересно, что мне нужно, чтобы правильно обновить пользовательский интерфейс:Обновить свойство ViewModel из задачи

public class DemoViewModel : PropertyChangedBase 
{ 
    private int m_Progress; 

    public int Progress 
    { 
     get { return m_Progress; } 
     set 
     { 
      if (value == m_Progress) return; 
      m_Progress = value; 

      NotifyOfPropertyChange(); 
      NotifyOfPropertyChange(nameof(CanStart)); 
     } 
    } 

    public bool CanStart => Progress == 0 || Progress == 100; 

    public void Start() 
    { 
     Task.Factory.StartNew(example); 
    } 

    private void example() 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      Progress = i + 1; // this triggers PropertChanged-Event and leads to the update of the UI 
      Thread.Sleep(20); 
     } 
    } 
} 

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

+0

События INPC автоматически сортируются по потоку пользовательского интерфейса, поэтому вам не нужно беспокоиться. Но ... если вы обновите пользовательский интерфейс каждые 20 черных миллисекунд (Thread.Sleep (20) !!!!!!!), вы не увидите разъем в пользовательском интерфейсе, потому что он будет слишком занят, чтобы фактически обновить. – Will

ответ

2

Это будет зависеть от того, как вы внедрили INotifyPropertyChanged. Реализация должна делить все обновления пользовательского интерфейса на соответствующий диспетчер.

Пример реализация:

public void RaisePropertyChanged([CallerMemberName]string name) { 
     Application.Current.Dispatcher.Invoke(() => { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 
     }, System.Windows.Threading.DispatcherPriority.Background); 
    } 

Кроме того, чтобы очистить задачу начать немного:

Edit: Удалены ненужные BOOL возвращаемого значения, и установить ConfigureAwait остаться у UI нити при завершении задачи ,

public async void Start() 
{ 
    await Task.Run(() => example()).ConfigureAwait(false); 
} 

private async Task example() 
{ 
    for (int i = 0; i < 100; i++) 
    { 
     Progress = i + 1; // this triggers PropertChanged-Event and leads to the update of the UI 
     await Task.Delay(20); 
    } 
} 
+0

Спасибо. Я проверил исходный код Caliburn.Micro, и если вы вывели ViewModel из PropertyChangedBase, тогда синхронизация выполняется Caliburn.Micro. Существует удобный класс помощника Execute в CM для синхронизации, который я тоже узнал. –

+1

@ Ranga Полезно знать, CM очень удобная структура. – JSteward

+0

В чем преимущество использования await/async в этом контексте? Пример метода() не имеет возвращаемого значения, но вам нужен один для задачи, о которой я думаю. –