为什么绑定刷新延迟到委托命令完成之前? (MVVM)

时间:2010-02-22 17:02:48

标签: data-binding mvvm refresh inotifypropertychanged

我正在应用MVVM模式。我有一个按钮,当点击它时,在我的ViewModel中调用一个委托命令。在该委托方法的最开始,我设置了一个属性值(WaitOn),它应该通过显示动画控件来通知UI中的用户等待。

但是,在委托完成执行之前,显示动画控件的绑定不会刷新,此时等待完成。为什么会发生这种情况,我应该怎么做才能解决它?

示例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 个答案:

答案 0 :(得分:6)

可能正在更新绑定,但由于你在UI线程上做了很多东西,应用程序没有机会更新屏幕。您应该考虑将处理移动到后台线程或使用Dispatcher.BeginInvoke(),以便UI可以自由更新并显示您的等待消息。

在WPF中,Dispatcher类具有静态CurrentDispatcher property,您可以在ViewModel中使用它来安排任务。您的DoStuff方法看起来像这样:

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

在Silverlight中,您可以使用Deployment类访问当前的调度程序:

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

另外,您可能希望使用BooleanToVisibilityConverter,这样您只需要OnWait属性进行绑定。此外,您的OnWait setter当前正在触发通知,即使该属性设置回相同的值,您应该像这样实现它:

public bool WaitOn
{
  get { return _waitOn; }
  set
  {
    if(value != _waitOn)
    {
      _waitOn = value;
      RaisePropertyChanged("WaitOn");
    }
  }
}

答案 1 :(得分:4)

我确实得到了Rory的解决方案,并进行了一些调整。我最终这样做了:

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

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

使用“(Action)”创建新的Action以包装代码意味着我不必在任何地方声明委托,并且使用“Background”的优先级允许UI有机会更新。