2012-01-06 66 views
2

假設我有一個顯示用戶好友列表的應用程序。朋友列表以TabItem形式顯示。用戶必須首先登錄到服務器,以獲取朋友列表。根據狀態在視圖之間切換

我創建了兩個用戶控件,一個用於用戶登錄時,另一個用戶未登錄時。一些僅此行:

UnloggedView.xaml

<UserControl x:Class="UnloggedView" ...> 
    <TextBlock ...>You need to <Hyperlink Command="{Binding LoginCmd}"> 
     Login</Hyperlink>too see your friends list</TextBlock> 
</UserControl> 

LoggedView.xaml:

<UserControl x:Class="LoggedView" ...> 
    ... 
    <ListView ItemSource={Binding Path=friends}">... 
</UserControl> 

主窗口下面的代碼:

.... 
<TabItem Header="Friends"> 
    <vw:UnloggedView /> 
</TabItem> 

我相信一切是根據到MVVM主體。 LoginCmd是在ViewModel中實現的DelegateCommand(來自棱鏡)的簡化變體。這兩個視圖都能正常工作,並且隨着列表的填充(異步),通知被觸發並且視圖被更新。我很高興。所以我有兩個問題:第一個問題是如何激發LoginWindow(用戶被提示輸入他的憑據?現在,我只需創建LoginWindow(一個視圖對象)並使用ShowDialog顯示它。看起來好像我在這裏通過直接操縱ViewModel中的UI來打破MVVM的規則。

主要問題是在我用服務器登錄後,什麼是用TabItem替換內容的正確方法LoggedView。根據MVVM原則,ViewModel不應該對View的內部有所瞭解,我在ViewModel中公開IsLogged屬性(它會觸發PropertyChanged通知),但是我應該綁定什麼才能使所有東西發生?我真的不希望ViewModel操縱使用視圖。

感謝

回答

7

我看得出來這個問題了很多,寫了關於switching between Views/UserControls here東西。通常我使用ContentControl和轉出基於ContentTemplateDataTrigger,但相同的主要工作切換一個TabControl的ItemTemplate

<DataTemplate x:Key="LoggedOutTemplate"> 
    <local:UnloggedView /> 
</DataTemplate> 

<DataTemplate x:Key="LoggedInTemplate"> 
    <local:LoggedView /> 
</DataTemplate> 

<TabControl> 
    <TabControl.Style> 
     <Style TargetType="{x:Type TabControl}"> 
      <Setter Property="ItemTemplate" Value="{StaticResource LoggedOutTemplate}" /> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding IsLoggedIn}" Value="True"> 
        <Setter Property="ItemTemplate" Value="{StaticResource LoggedInTemplate}" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </TabControl.Style> 
</TabControl> 

您可能需要使用ElementNameRelativeSource在DataTrigger約束力找到IsLoggedIn財產您的DataContext

至於從註銷視圖觸發登錄命令,有多種方式。

我的首選方法是使用某種類型的郵件系統,如MVVM光的Messenger或Microsoft棱鏡的EventAggregator,和發射某種ShowLoginDialog消息的按鈕被按下時,則讓任何視圖模型正在顯示登錄的護理對話框訂閱接收這些消息並處理它們。

另一種方法是簡單地使用RelativeSource綁定來查找Visual Tree中的對象,該對象在其DataContext中有LoginCommand,並綁定到該對象。

你可以看到兩個例子here

+0

你的解決方案是完整的,很好的。非常感謝。我還探討了DataTemplateSelector,它也是可行的,但最終如您所建議的那樣使用DataTrigger。 – Uri 2012-01-08 18:52:27

1

首先我會回答你的第二個問題......只需創建一個枚舉作爲SessonState

enum SesionState 
{ 
     LoggedOut=0, 
     LoggedIn 
} 

之後創建一個名爲SessionState的窗在你的ViewModel屬性和更新,隨着房產登錄和登出時所需的值。

XAML中需要切換視圖

<Window> 
     <Window.Resources>   
    <DataTemplate x:Key="LoggedOutView"> 
     <ViewLayer: LoggedOutView/> 
    </DataTemplate> 
    <DataTemplate x:Key="LoggedInView"> 
     <ViewLayer:LoggedInView/> 
    </DataTemplate> 
    <Style x:Key="mainContentControlStyle" 
      TargetType="{x:Type ContentControl}"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding Path=SessionState}" 
         Value="0"> 
       <Setter Property="ContentTemplate" Value="{StaticResource ResourceKey=LoggedOutView}" /> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding Path=Mode}" 
         Value="1"> 
       <Setter Property="ContentTemplate" Value="{StaticResource ResourceKey=LoggedInView}" /> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</Window.Resources> 
    <Grid> 
     <TabControl> 
      <TabItem> 
         <ContentControl Grid.Row="0" 
        Content="{Binding}" 
        Style="{StaticResource ResourceKey=mainContentControlStyle}"> 
      </TabItem> 
     </TabControl> 
    </Grid> 
</Window> 
+0

謝謝。你的解決方案很好。 @Rachel稍微簡單一點,代碼少一點,但是你的解決方案也可以工作 – Uri 2012-01-08 18:55:53

0

你的第一個問題:你可以簡單地用一個ILogindialogservice從您的視圖模型。我使用following作爲對話框和mvvm。其「單元測試」能夠並且不會破壞mvvm。

編輯。在您的視圖模型,你必須再行是這樣的:

var result = this.loginservice.ShowDialog("Login", loginvm);