2010-02-22 40 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