确保每个子UserControl都创建自己的ViewModel实例

时间:2014-02-17 04:13:21

标签: .net wpf vb.net mvvm viewmodel

我为客户开发项目,并决定在数据绑定和UI设计的声明方法方面利用WPF的优势。但是我在理解View和ViewModel之间的关系时遇到了很大的问题。

我有一个UserControl(ParentUserControl)和一个子UserControl(ChildUserControl)。在这个ParentUserControl中,我有一个ContentPresenter,可以容纳ChildUserControl的多个实例。 ChildUserControl有多个组合框和文本框,显示我的模型中的信息。用户可以通过单击“添加新”按钮,在ParentUserControl中打开尽可能多的ChildUserControl。在我的ParentViewModel中,我存储了用户创建的每个ChildViewModel的实例,并将新的ChildUserControl添加到ParentUserControl。用户可以通过“查看下一个”和“查看上一个”按钮来浏览ChildUserControl。

所有这些都很有效,除非用户进行选择或更改任何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

1 个答案:

答案 0 :(得分:2)

我看到几个问题:

  1. 您在XAML中设置了ChildUserControl.DataContext,但ChildUserControl的实例已经从ContentPresenter中的绑定中获取了数据上下文。您可以安全地将其删除。

  2. ContentPresenter只能包含一个子控件。当您创建新的视图模型并将其设置为CurrentView时,会忘记旧的视图模型,删除旧的ChildUserControl,然后创建一个代表新视图模型的新ChildUserControl

  3. 如何在子视图之间导航?我没有看到相关的代码。