2014-02-17 94 views
3

對於WPF和MVVM模式,我很新,所以請隨身攜帶。我爲客戶開發一個項目,並決定利用WPF在數據綁定和聲明式UI設計方面的優勢。但我有一個很大的問題,理解我的Views和ViewModels之間的關係。確保每個子UserControl創建自己的ViewModel實例

我有一個UserControl(ParentUserControl)和一個子UserControl(ChildUserControl)。在這個ParentUserControl中,我有一個ContentPresenter可以容納多個ChildUserControl實例。 ChildUserControl有多個組合框和文本框,顯示來自我的模型的信息。用戶可以通過單擊「添加新的」按鈕,在ParentUserControl中打開任意多個ChildUserControls。在我的ParentViewModel中,我存儲用戶創建的每個ChildViewModel的實例將新的ChildUserControl添加到ParentUserControl。用戶可以通過'查看下一個'和'查看以前的'按鈕來瀏覽ChildUserControls。

所有這些工作都很好,除非用戶在任何ChildUserControl中進行選擇或更改任何控件的文本,否則該更改會傳播到用戶爲所有視圖創建/共享一個ViewModel的所有ChildUserControl。我嘗試了所有我能想到的,無論是否使用MVVM Light工具包(這似乎將在未來爲我節省大量時間)。

我的問題是我怎麼能絕對肯定每次一個新的View被實例化,它獲得它自己的ViewModel的實例?我已經堅持了幾天!謝謝!

'注意:此代碼不是實際產品。這只是爲了展示我與真正的應用程序有關的問題。無論如何,如果需要的話,不要害怕在C#中回答我的首選語言。哦,我試圖用Pure MVVM來完成這個項目。謝謝!!!

代碼:

ParentUserControl:

<UserControl x:Class="ParentUserControl" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:MVVM_Light_Test_Application" 
    Height="350" Width="525"> 
    <UserControl.Resources> 
     <DataTemplate DataType="{x:Type local:ChildUserControlViewModel}"> 
      <local:ChildUserControl/> 
     </DataTemplate> 
    </UserControl.Resources> 

    <UserControl.DataContext> 
     <local:MainViewModel/> 
    </UserControl.DataContext> 
    <Grid> 
     <StackPanel Width="auto" Height="200"> 
      <ContentPresenter Content="{Binding CurrentView}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > 
      </ContentPresenter>    
     </StackPanel> 
     <StackPanel> 
      <Button Command="{Binding ChangeUserControlCommand}" Content="Click To Change View"/> 
     </StackPanel> 
    </Grid> 
</UserControl> 

ChildUserControl:

<UserControl x:Class="ChildUserControl" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:MVVM_Light_Test_Application" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300" Background="{Binding BGColor, UpdateSourceTrigger=PropertyChanged}"> 
    <UserControl.DataContext> 
     <local:ChildUserControlViewModel/> 
    </UserControl.DataContext> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="149*"/> 
      <ColumnDefinition Width="151*"/> 
     </Grid.ColumnDefinitions> 

     <StackPanel Height="200" Width="auto"> 
      <StackPanel> 
       <ComboBox x:Name="cboExampleObjects" Margin="5" ItemsSource="{Binding Customers}" DisplayMemberPath="Details" SelectedItem="{Binding SelectedCustomer}"/> 
      </StackPanel> 
      <StackPanel Grid.Column="1"> 
       <TextBox x:Name="txtObjectPropertyValue" Text="{Binding SelectedCustomer.Name}" Margin="5"/> 
      </StackPanel> 
     </StackPanel> 
    </Grid> 
</UserControl> 

父視圖模型:

Public Class MainViewModel 
    Inherits ViewModelBase 

    Public Sub New() 
     _currentView = New ChildUserControlViewModel 
     ChangeUserControlCommand = New RelayCommand(AddressOf ChangeUserControl) 
    End Sub 

    Private _currentView As ViewModelBase 
    Public Property CurrentView As ViewModelBase 
     Get 
      Return _currentView 
     End Get 
     Set(value As ViewModelBase) 
      _currentView = value 
      RaisePropertyChanged("CurrentView") 
     End Set 
    End Property 

    Public Property ChangeUserControlCommand As RelayCommand 


    Public Sub ChangeUserControl() 
     CurrentView = New ChildUserControlViewModel 
     CType(CurrentView, ChildUserControlViewModel).BGColor = Nothing 
    End Sub 
End Class 

子視圖模式:

進口System.Collections.ObjectModel

Public Class ChildUserControlViewModel 
    Inherits ViewModelBase 

    Public Sub New() 
     _customes = New ObservableCollection(Of Customer)(New List(Of Customer)({New Customer With {.Name = "TestName1", .CustomerNumber = 1}, New Customer With {.Name = "TestName2", .CustomerNumber = 2}})) 
    End Sub 

    Private _customers As ObservableCollection(Of Customer) 
    Public Property Customers As ObservableCollection(Of Customer) 
     Get 
      Return _customers 
     End Get 
     Set(value As ObservableCollection(Of Customer)) 
      _customers = value 
      RaisePropertyChanged("Customers") 
     End Set 
    End Property 

    Private _selectedCustomer As Customer 
    Public Property SelectedCustomer As Customer 
     Get 
      Return _selectedCustomer 
     End Get 
     Set(value As Customer) 
      If _selectedCustomer Is Nothing OrElse String.Compare(value.Name, _selectedCustomer.Name) <> 0 Then 
       _selectedCustomer = value 
       RaisePropertyChanged("SelectedCustomer") 
      End If 
     End Set 
    End Property 

    Private _bgColor As SolidColorBrush 
    Public Property BGColor As SolidColorBrush 
     Get 
      Dim random As New Random 
      Return New SolidColorBrush(Color.FromArgb(50, Random.Next(0, 255), Random.Next(0, 255), Random.Next(0, 255))) 
     End Get 
     Set(value As SolidColorBrush) 
      Dim random As New Random 
      _bgColor = New SolidColorBrush(Color.FromArgb(50, random.Next(0, 255), random.Next(0, 255), random.Next(0, 255))) 
      RaisePropertyChanged("BGColor") 
     End Set 
    End Property 
End Class 

回答

2

我看到幾個問題:

  1. 在XAML中設置ChildUserControl.DataContext,但ChildUserControl實例已經從ContentPresenter結合獲取數據的上下文。你可以安全地刪除它。

  2. ContentPresenter只能包含一個子控件。當您創建一個新的視圖模型並將其設置爲CurrentView時,舊的視圖模型將被遺忘,舊的ChildUserControl將被刪除,然後將創建一個代表新視圖模型的新的ChildUserControl

如何在子視圖間導航?我沒有看到相關的代碼。

+0

刪除XAML中的'ChildUserControl.DataContext'確實有竅門!你是上帝!我沒有意識到,綁定到「ContentPresenter」時,子視圖的數據上下文已設置。我真的不能夠感謝你! –

+0

如果一個控件包含另一個控件,則子控件將(幾乎)始終從父控件繼承數據上下文,無論它如何添加(演示者,模板,顯式等)。如果父控件是一個列表('ItemsControl'),則子控件將綁定到來自'ItemsSource'的單個項目。 – Athari

+0

這實際上使事情變得更容易。另外,我在我的子用戶控件的DataContext上收到了設計時錯誤。你剛剛救了我一次與我的客戶談話,我害怕哈哈。再次感謝! –

相關問題