Почему обновление привязки задерживается до завершения делегирования команды? (MVVM) - PullRequest
2 голосов
/ 22 февраля 2010

Я применяю шаблон MVVM. У меня есть кнопка, которая при нажатии вызывает делегированную Команду в моей ViewModel. В самом начале этого метода делегата я установил значение свойства (WaitOn), которое должно уведомлять пользователя в пользовательском интерфейсе о необходимости ожидания, отображая анимированный элемент управления.

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

Образец XAML:

<Button Command="{Binding DoStuffCommand}" />
<ctl:MyAnimatedControl Name="ctlWait" Caption="Please Wait..." 
Visibility="{Binding WaitNotification}" />

Фрагменты из ViewModel:

public bool WaitPart1On
{
  get { return _waitPart1On; }
  set
  {
    _waitPart1On = value;
    if (_waitPart1On == true)
    {
      WaitNotification = "Visible";
    }
    else
    {
      WaitNotification = "Hidden";
    }
    RaisePropertyChanged("WaitPart1On");
  }
}

public string WaitNotification
{
  get { return _waitNotification; }
  set
  {
    _waitNotification = value;
    RaisePropertyChanged("WaitNotification");
  }
}


public void DoStuff()
{
  WaitPart1On = true;
  //Do lots of stuff (really, this is PART 1)
  //Notify the UI in the calling application that we're finished PART 1
  if (OnFinishedPart1 != null)
  {
    OnFinishedPart1(this, new ThingEventArgs(NewThing, args));
  }
  WaitPart1On = false;
}

А теперь код из XAML для отлова возбужденного события:

public void Part1FinishedEventHandler(NewThing newThing, ThingEventArgs e)
    {
      //at this point I expected the WaitPart1On to be set to false
      //I planned to put a new wait message up (WaitPart2)
      FinishPart2();
    } 

Ответы [ 2 ]

6 голосов
/ 22 февраля 2010

Скорее всего, привязка обновляется, но, поскольку вы выполняете "много всего" в потоке пользовательского интерфейса, приложение не получает возможности обновить экран. Вам следует рассмотреть возможность перемещения обработки в фоновый поток или использования Dispatcher.BeginInvoke(), чтобы пользовательский интерфейс мог свободно обновлять и отображать ваше сообщение ожидания.

В WPF класс Dispatcher имеет статическое свойство CurrentDispatcher , которое можно использовать из ViewModel для планирования задач. Ваш DoStuff метод будет выглядеть примерно так:

public void DoStuff()
{
  WaitOn = true;
  Dispatcher.CurrentDispatcher.BeginInvoke(() =>
    {
      //Do lots of stuff
      WaitOn = false;
    });
}

В Silverlight вы можете получить доступ к текущему диспетчеру, используя Deployment class:

public void DoStuff()
{
  WaitOn = true;
  Deployment.Current.Dispatcher.BeginInvoke(() =>
    {
      //Do lots of stuff
      WaitOn = false;
    });
}

В примечании вы можете использовать BooleanToVisibilityConverter , так что вам нужно только свойство OnWait для привязки. Кроме того, ваш установщик OnWait в данный момент запускает уведомления, даже если для свойства задано то же значение, вы должны реализовать его следующим образом:

public bool WaitOn
{
  get { return _waitOn; }
  set
  {
    if(value != _waitOn)
    {
      _waitOn = value;
      RaisePropertyChanged("WaitOn");
    }
  }
}
4 голосов
/ 24 февраля 2010

Я получил решение Рори, с небольшой настройкой. Я закончил тем, что сделал это:

public void DoStuff() 
{ 
  WaitPart1On = true; 
  Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, (Action)(() =>

    { 
      //Do lots of stuff 
      WaitPart1On = false; 
    }); 
}

Использование «(Action)» для создания нового Action для переноса кода означало, что мне не нужно было нигде объявлять делегата, а использование приоритета «Background» позволило пользовательскому интерфейсу обновляться.

...