Ensure each child UserControl creates its own ViewModel instance
我正在为一个客户从事一个项目,并决定在数据绑定和UI设计的声明方法方面利用WPF的好处。但是我在理解我的Views和ViewModels之间的关系时遇到了一个大问题。
我有一个UserControl(ParentUserControl)和一个子UserControl(ChildUserControl)。在此ParentUserControl中,我有一个ContentPresenter,可以容纳ChildUserControl的多个实例。 ChildUserControl具有多个组合框和文本框,这些组合框和文本框显示来自我的模型的信息。通过单击"添加"按钮,用户可以根据需要在ParentUserControl中打开任意数量的ChildUserControl。在我的ParentViewModel中,我存储着用用户创建的每个ChildViewModel的实例,这些实例将新的ChildUserControl添加到ParentUserControl。用户可以通过"查看下一个"和"查看上一个"按钮浏览ChildUserControls。
所有这些都很好用,除非用户进行选择或更改任何ChildUserControl中任何控件的文本,更改会传播到用户创建的所有ChildUserControl中/为所有视图共享一个ViewModel。在使用和不使用MVVM Light工具包的情况下,我都尝试了所有可以想到的一切(这似乎在将来可以节省大量时间)。
我的问题是,我如何才能绝对肯定地确保每次实例化一个新View时,它都会获得自己的ViewModel实例?我已经坚持了好几天!!!谢谢!
'注意:此代码不是实际产品。这只是为了演示我在实际应用程序中遇到的问题。无论如何,不??要害怕用C#回答,这是我的首选语言。哦,我正在考虑使用Pure MVVM完成该项目。谢谢!!!
代码:
ParentUserControl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <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> |
父视图模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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 |
我看到了几个问题:
您在XAML中设置了
您如何在子视图之间导航?我没有看到相关的代码。