2010-02-23 32 views
7

我很想知道你們在那裏如何處理帶有MVVM模式的Silverlight應用程序中的視圖狀態。 假設我有一個簡單的搜索掩碼,異步調用Web服務。 而搜索過程中,我想相應改變GUI: - 禁用搜索按鈕 - 啓用一個取消按鈕 - 等用MVVM處理Silverlight中的視圖狀態

使用WPF我可以創建結合某些屬性在datatrigger視圖模型,然後對gui進行更改。 現在,因爲我沒有Silverlight中的數據觸發器,最類似於datatrigger的最明智的方式是什麼(整潔的代碼,如果可能的話在一個地方)?

I posted a similar question, but it was worded poorly

回答

7

我這樣做的標準方法是從暴露視圖模型(通常是一個枚舉)一個「視圖狀態」屬性。視圖然後綁定到屬性,並使用visualstatemanager根據枚舉切換到適當的視覺狀態。

Expression Samples的DataStateSwitchBehavior是如何切換到視覺狀態的一個很好的例子。

編輯在迴應置評

首先,與VisualStates打交道時使用混合(應該沒有人會被迫手工編寫那麼多XAML)。我相信它甚至是所有(大多數)MSDN訂閱。

使用Visual國Visual State Manager

<VisualStateManager.VisualStateGroups> 
    <VisualStateGroup x:Name="GroupOne"> 
     <VisualState x:Name="Normal"/> 
     <VisualState x:Name="Searching"/> 
    </VisualStateGroup> 
</VisualStateManager.VisualStateGroups> 

開始您最好將其添加到layoutroot。

可視狀態管理器由StateGroups的集合組成,StateGroups又由一組VisualState組成。

這些組保持相互排斥的狀態,因爲您可以在任何時間都有多個視覺狀態,但每個組只有一個狀態。標準模式是將一個空狀態稱爲「正常」或「默認」,用於關閉其他狀態。基本狀態。

在你的情況,你將不得不它將包含一個故事板這將禁用各種按鈕的「搜索」視覺狀態,激活忙動畫等

+0

那麼我可以在我的控件上定義視覺狀態(也在子窗口上?),然後使用DataStateSwitchBehavior切換它們?例如,一個州可能是'SearchInProgress'。那麼我該如何使用VSM來禁用該按鈕,以便在控件位於「SearchInProgress」中時該按鈕不可點擊? – 2010-02-23 12:30:40

+0

謝謝格雷姆。我得到這個在一個示例項目中工作,看起來這是一條路。但是,我似乎遇到了同樣的問題在這裏提到:http://stackoverflow.com/questions/2118814/how-can-i-use-visualstates-in-a-childwindow。 VSM似乎不適用於子窗口。我現在將把所有內容放在UserControl中並在子窗口中引用它。 我正在使用您提到的DataStateSwitcher使其成爲ViewModel驅動。 – 2010-02-23 14:47:00

0

最方便的辦法就是從Silverlight工具包使用BusyIndicator我想。由於它掩蓋了您應用的整個區域,所有按鈕都會自動禁用。

對於取消按鈕,您必須編輯BusyIndicator的模板,將其放置在我認爲的加載動畫旁邊。

你可以這樣簡單地BusyIndi​​cator控件的IsBusy屬性綁定到您的視圖模型的相應屬性,您加載之前設置,當你完成復位。

0

我的解決方案與Graeme Bradbury的類似,但我不使用DataStateSwitchBehavior,因爲如果我的X控件放置在選項卡面板(或類似的東西)中,並且狀態在另一個選項卡上發生變化,會得到一個異常('元素'沒有找到..)。拋出異常是因爲我在另一個選項卡上卸載了我的X控件,並且未找到需要更新的元素。

因此,這裏是我做的:

在我的視圖模型我有發送通知消息的屬性的VisualState當狀態改變(我用MVVM light toolkit):

private string visualState = XVisualStates.InitialState; 
    public string VisualState 
    { 
     get 
     { 
      return visualState; 
     } 

     set 
     { 
      visualState = value; 
      Messenger.Default.Send(new XStateChangedMessage(value)); 
     } 
    } 

,並在我看來代碼後面我訂閱通知:

public partial class XControl : UserControl 
{ 
    private string visualState = XVisualStates.InitialState; 
    public XControl() 
    { 
     InitializeComponent(); 

     //go to state when view is loaded 
     Loaded += (s, e) => ChangeState(); //every time a view is loaded go to current state 

     //change visual state when a notification is received 
     Messenger.Default.Register<XStateChangedMessage>(this, 
      state => 
      { 
       visualState = state.CurrentState; //save current state 
       ChangeState(); 
      }); 
    } 

    void ChangeState() 
    { 
     try 
     { 
      VisualStateManager.GoToState(this, visualState, true); //will throw an exception if current view is unloaded 
     } 
     catch 
     { 
      //NOTE: supress 'element' not found errors if user navigated to another view and state changes 
     } 
    } 
} 

和XStateChangedMessage是一個簡單的類:

public class XStateChangedMessage 
{ 
    public string CurrentState { get; private set; } 

    public XStateChangedMessage (string currentState) 
    { 
     CurrentState = currentState; 
    } 
} 
0

1)您可以在視圖模型中創建IsEnabledSearch屬性,並將其綁定到Button的IsEnabled或Visibility屬性(您需要一個Bool to Visibility Converter)。僅僅爲此創建新的視覺狀態效率不高,因爲您的按鈕已經具有各種視覺狀態來支持這種行爲。 2)Jounce mvvm框架有一個很好的實現來支持ViewModel中的VisualState; Jounce Visual State Manager