2012-10-15 60 views
2

我已經搜索並嘗試了幾天,最後必須在這裏提出問題。 我有一個Silverlight 5應用程序,使用MVVM Light,我希望能夠在主視圖中動態切換視圖。Silverlight在使用MVVM Light框架的視圖中切換視圖

爲了簡單起見,可以說我有2個按鈕。

Button1將切換到TestView1。

Button2將切換到TestView2。

<Button Content="TestView1" Grid.Column="1" Command="{Binding CallTestView1Command}" HorizontalAlignment="Left" Margin="185,17,0,0" VerticalAlignment="Top" Width="75"/> 
    <Button Content="TestView2" Grid.Column="1" Command="{Binding CallTestView2Command}" HorizontalAlignment="Left" Margin="280,17,0,0" VerticalAlignment="Top" Width="75"/> 

我做它是由relaycommand結合的按鈕,然後instanciating對應視圖的新視圖模型的方式。 即:

private RelayCommand _callTestView1Command; 
    public RelayCommand CallTestView1Command 
    { 
     get 
     { 
      return _callTestView1Command ?? 
        (_callTestView1Command = new RelayCommand(() => 
         { 
          CurrentView = ViewModelLocator.NinjectKernel.Get<TestViewModel1>(); 
         })); 
     } 
    } 

的CurrentViewmodel然後設置爲新視圖模型。 在的MainView我已綁定了CurrentView到ContentControl中:

<Border x:Name="displayedView" Grid.Row="2"> 
     <ContentControl Content="{Binding CurrentView}" /> 
    </Border> 

這將實際工作在一定程度上,因爲CurrentView會改變,但不是實際顯示視圖的內容也只是顯示出的命名空間ViewModel是instanciated。

到目前爲止,我主要使用從這些來源採取的知識:

http://rachel53461.wordpress.com/2011/05/28/switching-between-viewsusercontrols-using-mvvm/

Loading Views into ContentControl and changing their properties by clicking buttons

,但他們不解決我的問題,還是我不太明白如何實際顯示views :-(

因此,沒有人有一個很好的解釋,如何使用GalaSoft的MVVM Light在Silverlight 5中正確切換視圖。

感謝

+0

在CallTestView1Command第一設定CurrentView = NULL;然後分配新的項目,它也許可以解決這個問題 – Masoomian

回答

0

這將實際工作在一定程度上,因爲CurrentView會,而是的 變化實際上顯示視圖它 的內容簡單地顯示了實例化視圖模型的命名空間。

因爲您正在將CurrentView屬性更改爲viewmodel實例並將其綁定爲內容。這是錯誤的,因爲內容應該是一個視圖,您應該將該視圖的DataContext設置爲視圖模型。

您可以在此處執行的最簡單的操作是在命令中創建一個View實例,並將viewmodel設置爲其DataContext,然後您可以將該視圖設置爲CurrentView屬性。當然,這將違反 MVVM模式,所以你應該把這個責任移到一個單獨的組件。我建議你選擇一個現有的解決方案,而不是編寫自己的導航邏輯,因爲這種任務並不像看起來那麼簡單。

我建議使用Prism library

+0

嗨,彼得。 我也很好奇,它實際上是ViewModel,我發現的「指南」應該綁定到內容。 如果我添加: ' <查看:TestView1 /> <查看:TestView2 /> ' 它實際上會切換視圖,但是我必須在xaml中指定任何可能顯示的視圖。這不是很有活力。 – ThBlitz

+0

那麼你應該發佈描述數據模板的xaml。 –

1

標識首先建議您不要顯示通過ContentControl中你的意見,但看看在Silverlight工具包使用導航框架。另外,我們不希望我們的ViewModel創建視圖...那不會那麼好。但是,如果我們的ViewModel執行業務邏輯和決定顯示哪個視圖,我們並不介意。這裏獲取該工具包:http://silverlight.codeplex.com/

現在設置您的XAML爲使您的主頁:

<Border x:Name="displayedView" Grid.Row="2"> 
     <navigation:Frame x:Name="ContentFrame" /> 
    </Border> 

由於您使用的MVVM光,我們將使用消息。您的View模型將獲得命令來更改視圖,確定要更改哪個視圖,然後將消息發送到主頁以指示它更改視圖。

安裝在您的主頁偵聽器的導航要求像這樣:

public MainPage() 
{ 
    InitializeComponent(); 
    Messenger.Default.Register<Uri>(this, "NavigationRequest", (uri) => ContentFrame.Navigate(uri)); 
} 

接下來,安裝在您的視圖模型的命令。

private RelayCommand _callTestView1Command;   
public RelayCommand CallTestView1Command   
{   
    get   
    {   
     return _callTestView1Command ??   
       (_callTestView1Command = new RelayCommand(() =>   
        {   
         Messenger.Default.Send<Uri>(new Uri("/Views/.../Page.xaml", UriKind.Relative), "NavigationRequest"); 

        }));   
    }   
} 

這些是爲我工作的基礎知識。你可以擴展這個並獲得真正的「建築師」。例如,您可以爲您創建一個基類來查看發送導航請求的模型,創建一個生成URI的助手類(因此它們在您的應用中無處不在硬編碼等等)。祝您好運!

+0

嗨。我會研究這種方法。我確實解決了這個問題(請參閱我的其他帖子),但我有點喜歡你的方法,即消息實際上允許實現新視圖。 – ThBlitz

1

因此,我實際上解決了這個問題,這樣就不需要在我不喜歡的情況下創建數據模板,當我們正在談論切換的時候,它應該對它正在顯示的視圖一無所知。

先決條件:您必須使用來自GalaSoft的MVVM Light此解決方案

這是我的測試解決方案: 兩個按鈕被添加到我的MainView,每個按鈕將打開一個新的視圖。 clickevent綁定到命令。

<Button Content="TestView1" Grid.Column="1" Command="{Binding CallTestView1Command}" HorizontalAlignment="Left" Margin="185,17,0,0" VerticalAlignment="Top" Width="75"/> 
<Button Content="TestView2" Grid.Column="1" Command="{Binding CallTestView2Command}" HorizontalAlignment="Left" Margin="280,17,0,0" VerticalAlignment="Top" Width="75"/> 

的MainView我有一個包含有除了可以切換視圖的邊界。 由於所有的觀點從用戶控件繼承我的內容結合到的MainViewModel

<Border x:Name="displayedView" Grid.Row="2"> 
     <UserControl Content="{Binding CurrentView}" /> 
    </Border> 

財產CurrentViewMainViewModel我有物業CurrentView。

public const string CurrentViewPropertyName = "CurrentView"; 

    private UserControl _currentView; 

    /// <summary> 
    /// Sets and gets the "CurrentView property. 
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary> 
    public UserControl CurrentView 
    { 
     get 
     { 
      return _currentView; 
     } 

     set 
     { 
      if (_currentView == value) 
      { 
       return; 
      } 

      RaisePropertyChanging(CurrentViewPropertyName); 
      _currentView = value; 
      RaisePropertyChanged(CurrentViewPropertyName); 
     } 
    } 

當點擊一個按鈕,在MainViewModel相應的命令被稱爲:

 private RelayCommand _callTestView1Command; 
    public RelayCommand CallTestView1Command 
    { 
     get 
     { 
      return _callTestView1Command ?? 
        (_callTestView1Command = new RelayCommand(() => 
         { 
          CurrentView = new TestView1(); 
         })); 
     } 
    } 

    private RelayCommand _callTestView2Command; 
    public RelayCommand CallTestView2Command 
    { 
     get 
     { 
      return _callTestView2Command ?? 
        (_callTestView2Command = new RelayCommand(() => 
        { 
         CurrentView = new TestView2(); 
        })); 
     } 
    } 

如所看到的每個命令將CurrentView設置爲一個新的視圖,而視圖將切換在在的MainView,因爲CurrentView將引發PropertyChanged事件。

+1

雖然這可能工作,'ViewModel'不應該包含直接這樣到'View'參考因爲違反的擔憂層之間的分離,這是最強的原因首先使用MVVM之一。你最好使用隱式'DataTemplate'(一個'DataTemplate'僅指定一個'TargetType',沒有'X:Key')在''或'',它告訴WPF用您的視圖繪製您的ViewModel。 'View'層意味着反映'ViewModel'層,而不是相反。 – Rachel

2

你缺少的部分是DataTemplates告訴WPF如何渲染你的ViewModels

<Window.Resources> 
    <DataTemplate TargetType="{x:Type local:TestViewModel1}"> 
     <local:TestView1 /> 
    </DataTemplate> 

    <DataTemplate TargetType="{x:Type local:TestViewModel2}"> 
     <local:TestView2 /> 
    </DataTemplate> 
</Window.Resources> 

當您在視覺樹插入的對象,如放置一個ViewModel對象ContentControl.Content,它會被繪製通過使用默認綁定到對象的.ToString()一個TextBlock,這就是爲什麼你只看到ViewModelnamespace.classnameContentControl

通過定義一個隱含DataTemplate在你的Resources地方(這是一個DataTemplate只有一個TargetType定義 - 沒有x:Key),你告訴WPF使用指定DataTemplate隨時隨地它試圖繪製對象繪製指定的對象,而不是使用綁定到.ToString()默認TextBlock的對象。

應當指出的是,隱DataTemplates是不是在早期版本的Silverlight的支持,但他們在5.0+支持。對於較早版本的Silverlight,我通常使用DataTemplateSelector來代替。