Ensure that each child of UserControl creates its own instance of ViewModel

I am new to WPF and the MVVM template, so please come with me. I am working on a project for a client and decided to take advantage of WPF in terms of data binding and a declarative approach to user interface design. But I had a huge problem in understanding the relationship between my views and ViewModels.

I have a UserControl (ParentUserControl) and a child UserControl (ChildUserControl). Inside this ParentUserControl, I have a ContentPresenter that can contain multiple instances of ChildUserControl. ChildUserControl has several combo boxes and text fields displaying information from my model. The user can open as many ChildUserControls in ParentUserControl as possible by clicking the "Add New" button. In my ParentViewModel I store instances of each ChildViewModel created with the user, adds a new ChildUserControl to the ParentUserControl. The user can navigate through ChildUserControls elements using the "View Next" and "View Previous" buttons.

All this works fine, unless the user makes a selection or changes the text of any control in any ChildUserControl, this change applies to all ChildUserControls children that the user created or used the same ViewModel for all views. I have tried everything I can think of, with and without using the MVVM Light toolkit (which seems to be going to save a ton of time in the future).

My question is, how can I be absolutely sure that every time a new View is created, it gets its own instance of ViewModel? I am stuck on this for several days !!! Thank!

'. . , . #, , . , 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
+3
1

:

  • ChildUserControl.DataContext XAML, ChildUserControl ContentPresenter. .

  • ContentPresenter . CurrentView, , ChildUserControl , ChildUserControl, .

? .

+2

All Articles