(WPF/MVVM) MainViewModel 中的单个实例
(WPF/MVVM) Single Instance In MainViewModel
我有一个项目有 3 View/ViewModels(当然到现在为止!)。所以我在 MainView 中有一个 ListView 来显示它们中的每一个,并且可以由用户选择。所以我使用了这样的东西:
class MainViewModel :INotifyPropertyChanged
{
public ObservableCollection<BaseViewModel> obv
{
get { return this._obv; }
}
public MainViewModel()
{
pvm = new PViewModel();
lvm = new LViewModel();
svm = new SViewModel();
cvm = new CViewModel();
ivm = InstanceViewModel.Instance;
obv.Add(pvm);
obv.Add(lvm);
obv.Add(svm);
}
.
.
.
}
这是主视图:
<Window x:Class="Banking_System.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Banking_System"
xmlns:view="clr-namespace:Banking_System.View"
xmlns:model="clr-namespace:Banking_System.Model"
xmlns:viewmodel="clr-namespace:Banking_System.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="1200" MinHeight="500" MinWidth="800">
<Window.DataContext>
<viewmodel:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="boo2vis"/>
<DataTemplate DataType="{x:Type viewmodel:PViewModel}">
<view:P/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:LViewModel}">
<view:L/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:SViewModel}">
<view:S/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:CViewModel}">
<view:C/>
</DataTemplate>
</Window.Resources>
<Grid FlowDirection="RightToLeft">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="ListBoxMenu" Margin="5" Grid.Column="0" ItemsSource="{Binding obv}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Margin="10" Padding="10"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border Grid.Column="1" Margin="5" BorderBrush="#FF7F9DB9" BorderThickness="1">
<ContentControl Margin="10" Content="{Binding SelectedItem, ElementName=ListBoxMenu}"/>
</Border>
</Grid>
然后将 ListView 绑定到 obv。但是在这样做之后,当 ListView 中的 SelectedItem 发生变化时,这个 MainViewModel 得到一个新实例并且因此所有其他 ViewModels在里面,会得到一个新的实例。(因为我在里面写了new *Viewmodel()
!)
(换句话说,所有应用程序都刷新,就像刚打开一样!)
Q:那么有没有办法防止这种行为呢?
注意: 虽然我可以在所有 ViewModel 中使用实例并编写如下内容:
/* In each ViewModel have something like this */
public static LViewModel Instance
{
get
{
if (_Instance == null)
_Instance = new LViewModel();
return _Instance;
}
}
/* Then change the MainViewModel to something like this */
class MainViewModel :INotifyPropertyChanged
{
public ObservableCollection<BaseViewModel> obv
{
get { return this._obv; }
}
public MainViewModel()
{
pvm = PViewModel.Instance;
lvm = LViewModel.Instance;
svm = SViewModel.Instance;
cvm = CViewModel.Instance;
ivm = InstanceViewModel.Instance;
obv.Add(pvm);
obv.Add(lvm);
obv.Add(svm);
}
.
.
.
}
但是我不知道对不对!
更新:我根本不知道定位器!因此,使用此代码添加另一个 class 名称 Locator:
class Locator
{
public LViewModel LInstance
{
get { return new LViewModel(); }
}
public PViewModel PInstance
{
get { return new PViewModel(); }
}
public SViewModel SInstance
{
get { return new SViewModel(); }
}
public MainViewModel MainInstance
{
get { return new MainViewModel(); }
}
}
但是我的MainViewModel还是和以前一样!我确实将 xaml 更改为:
<!--<Window.DataContext>
<viewmodel:MainViewModel/>
</Window.DataContext>-->
.
.
.
<!-- Just added the DataContext -->
<ListBox x:Name="ListBoxMenu" Margin="5" Grid.Column="0" ItemsSource="{Binding obv}" DataContext="{Binding MainInstance, Source={StaticResource LocatorVM}}">
.
.
.
但仍然像以前一样,MainViewModel 和其他 ViewModels 每次都会重新加载!
是的,您需要创建一个 "singleton" VM,或者您可以使用 Locator
,就像大多数 MVVM 框架提供的那样。
(实际上基本上是一样的...)。
看看我能不能link你...
好吧,我的……你知道什么。 have a look at this answer 了解有关定位器的更多信息
差不多。你想要这样的东西:
class Locator
{
private LViewModel _lInstance;
public LViewModel LInstance
{
get { return _lInstance ?? (_lInstance = new LInstance()); }
}
....
}
这样,您创建了一次实例,并且仅在请求时创建,并且它们应该在更改之间存活:)
我有一个项目有 3 View/ViewModels(当然到现在为止!)。所以我在 MainView 中有一个 ListView 来显示它们中的每一个,并且可以由用户选择。所以我使用了这样的东西:
class MainViewModel :INotifyPropertyChanged
{
public ObservableCollection<BaseViewModel> obv
{
get { return this._obv; }
}
public MainViewModel()
{
pvm = new PViewModel();
lvm = new LViewModel();
svm = new SViewModel();
cvm = new CViewModel();
ivm = InstanceViewModel.Instance;
obv.Add(pvm);
obv.Add(lvm);
obv.Add(svm);
}
.
.
.
}
这是主视图:
<Window x:Class="Banking_System.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Banking_System"
xmlns:view="clr-namespace:Banking_System.View"
xmlns:model="clr-namespace:Banking_System.Model"
xmlns:viewmodel="clr-namespace:Banking_System.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="1200" MinHeight="500" MinWidth="800">
<Window.DataContext>
<viewmodel:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="boo2vis"/>
<DataTemplate DataType="{x:Type viewmodel:PViewModel}">
<view:P/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:LViewModel}">
<view:L/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:SViewModel}">
<view:S/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:CViewModel}">
<view:C/>
</DataTemplate>
</Window.Resources>
<Grid FlowDirection="RightToLeft">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="ListBoxMenu" Margin="5" Grid.Column="0" ItemsSource="{Binding obv}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Margin="10" Padding="10"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border Grid.Column="1" Margin="5" BorderBrush="#FF7F9DB9" BorderThickness="1">
<ContentControl Margin="10" Content="{Binding SelectedItem, ElementName=ListBoxMenu}"/>
</Border>
</Grid>
然后将 ListView 绑定到 obv。但是在这样做之后,当 ListView 中的 SelectedItem 发生变化时,这个 MainViewModel 得到一个新实例并且因此所有其他 ViewModels在里面,会得到一个新的实例。(因为我在里面写了new *Viewmodel()
!)
(换句话说,所有应用程序都刷新,就像刚打开一样!)
Q:那么有没有办法防止这种行为呢?
注意: 虽然我可以在所有 ViewModel 中使用实例并编写如下内容:
/* In each ViewModel have something like this */
public static LViewModel Instance
{
get
{
if (_Instance == null)
_Instance = new LViewModel();
return _Instance;
}
}
/* Then change the MainViewModel to something like this */
class MainViewModel :INotifyPropertyChanged
{
public ObservableCollection<BaseViewModel> obv
{
get { return this._obv; }
}
public MainViewModel()
{
pvm = PViewModel.Instance;
lvm = LViewModel.Instance;
svm = SViewModel.Instance;
cvm = CViewModel.Instance;
ivm = InstanceViewModel.Instance;
obv.Add(pvm);
obv.Add(lvm);
obv.Add(svm);
}
.
.
.
}
但是我不知道对不对!
更新:我根本不知道定位器!因此,使用此代码添加另一个 class 名称 Locator:
class Locator
{
public LViewModel LInstance
{
get { return new LViewModel(); }
}
public PViewModel PInstance
{
get { return new PViewModel(); }
}
public SViewModel SInstance
{
get { return new SViewModel(); }
}
public MainViewModel MainInstance
{
get { return new MainViewModel(); }
}
}
但是我的MainViewModel还是和以前一样!我确实将 xaml 更改为:
<!--<Window.DataContext>
<viewmodel:MainViewModel/>
</Window.DataContext>-->
.
.
.
<!-- Just added the DataContext -->
<ListBox x:Name="ListBoxMenu" Margin="5" Grid.Column="0" ItemsSource="{Binding obv}" DataContext="{Binding MainInstance, Source={StaticResource LocatorVM}}">
.
.
.
但仍然像以前一样,MainViewModel 和其他 ViewModels 每次都会重新加载!
是的,您需要创建一个 "singleton" VM,或者您可以使用 Locator
,就像大多数 MVVM 框架提供的那样。
(实际上基本上是一样的...)。
看看我能不能link你...
好吧,我的……你知道什么。 have a look at this answer 了解有关定位器的更多信息
差不多。你想要这样的东西:
class Locator
{
private LViewModel _lInstance;
public LViewModel LInstance
{
get { return _lInstance ?? (_lInstance = new LInstance()); }
}
....
}
这样,您创建了一次实例,并且仅在请求时创建,并且它们应该在更改之间存活:)