2010-02-22 42 views
2

我在应用MVVM模式。我有一个按钮,点击后,在我的ViewModel中调用委托命令。在该委托方法的一开始,我设置了一个属性值(WaitOn),通过显示一个动画控件来通知用户返回到UI中等待。为什么绑定刷新延迟直到完成委托命令? (MVVM)

但是,绑定显示动画控件不会刷新,直到委托完成执行,此时等待完成。为什么会发生这种情况,我该如何解决这个问题?

样品XAML:从视图模型

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

摘录:

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(); 
    } 

回答

4

我没有得到Rory的解决方案的工作,有一些调整。最后我做这个:

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

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

使用“(动作)”来创建新的动作来包装的代码意味着我没有在任何地方申报的委托,并使用“背景”优先级允许的UI它有更新的机会。

+1

很高兴你能工作。只是想知道如果剧组转换为“动作”是绝对必要的,我敢肯定,lambda语法已经为你照顾到了...... – Rory 2010-02-26 07:42:51

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制定者目前正在烧制,即使该属性设置回值相同的通知,你应该实现这样的:

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

感谢有关转换器的信息。我一定会利用这一点。但对于Dispatcher位来说,ViewModel内部并不那么简单。我的ViewModel的方法是从UI中的一个直接的Command绑定中调用的,所以我不能控制事情,直到方法已经在进行中。我已经看过使用带有MVVM的Dispatcher的这篇有趣的文章 - > http://www.wintellect.com/CS/blogs/jlikness/archive/2009/12/16/dispatching-in-silverlight.aspx I我不确定它会在更新UI之前更新UI,因为它会覆盖我的方法的全部内容。 – 2010-02-22 18:40:03

+0

@ml_black:我已经使用View模型中的Dispatcher的几个示例更新了我的答案。您的'DoStuff'方法仍然由UI线程调用,并且在工作开始之前设置了“WaitOn”,但其他所有内容都通过调度程序调用。我知道这个方法是可行的,因为我之前使用过它,但如果它不适合你,你可以用手动创建的线程或ThreadPool来完成。你只需要注意从后台线程设置'WaitOn'属性(以及UI可能绑定的其他属性)。希望能帮助到你。 – Rory 2010-02-22 19:54:21

+0

谢谢。我正在探索你的建议,但没有看到代码写得很清楚。我有这个功能,但是,它不工作。我不知道这是否可能是因为我交给Dispatcher的“很多东西”也会引发视图在代码隐藏中处理的事件。我会稍微更新代码示例。 – 2010-02-22 20:42:26