多次实例化 MVVM ViewModel 构造函数
MVVM ViewModel constructor instantiated several times
有人介意帮我解决 WPF MVVM 理解问题吗?
我用 caliburn.micro 作为 MVVM 框架构建了一个 MVVM 项目。请耐心等待,因为这是我第一次创建此类项目。网格应该显示一种主屏幕 (HomeViewModel)。
因此,它的绑定已添加到内容控件中。
有人可以协助并告诉我为什么我的 HomeViewModel 的构造函数被实例化了 3 次吗?
另一方面,如果有人可以解释如何为 ViewModels 实现方法,我会很好吗?所有这些,包括日志记录都执行了三次。
<Window [...]>
<Window.DataContext>
<viewModels:ShellViewModel />
</Window.DataContext>
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type viewModels:HomeViewModel}">
<local:HomeView DataContext="{Binding}" />
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="1">
<ContentControl.Content>
<Binding FallbackValue="{x:Null}"
Mode="OneWay"
Path="viewModels:HomeViewItem"
RelativeSource="{RelativeSource Self}" />
</ContentControl.Content>
</ContentControl>
</Grid>
我在我的引导程序中根据 caliburn.micro 文档实现了一个 SimpleContainer:
public class Bootstrapper : BootstrapperBase
{
private SimpleContainer _container;
public Bootstrapper()
{
Initialize();
}
protected override void Configure()
{
_container = new SimpleContainer();
_container.Singleton<IWindowManager, WindowManager>();
// Registering ViewModels
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.Where(type => !(String.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("ViewModels"))
.ToList()
.ForEach(viewModelType => _container.RegisterSingleton(
viewModelType, viewModelType.ToString(), viewModelType));
// Registering Views
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("View"))
.Where(type => !(String.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("Views"))
.ToList()
.ForEach(viewModelType => _container.RegisterSingleton(
viewModelType, viewModelType.ToString(), viewModelType));
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
return _container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
我的 HomeViewModel 是这样实现的:
public class HomeViewModel : Conductor<IScreen>
{
public HomeViewModel()
{
Debug.WriteLine("Hello from HomeVM");
}
}
我的 ShellViewModel 是这样的:
public class ShellViewModel : Screen
{
private IScreen _homeViewItem;
public ShellViewModel()
{
CreateSourceItem();
}
public IScreen HomeViewItem
{
get => _homeViewItem;
set
{
if (Equals(value, _homeViewItem))
return;
_homeViewItem = value;
NotifyOfPropertyChange(() => HomeViewItem);
}
}
private void CreateSourceItem()
{
HomeViewItem = new HomeViewModel();
}
}
应用程序启动时,调试输出中有 3 个 HomeViewModel 实现条目:
Hello from HomeVM
Hello from HomeVM
Hello from HomeVM
如果多次调用构造函数,容器内的Singleton DI应该return现有实例,不是吗?
顺便说一句:StartupUri 已从 app.xaml 中删除。
提前致谢!
此标记调用 ShellViewModel 的构造函数
<Window.DataContext>
<viewModels:ShellViewModel />
</Window.DataContext>
通过
调用HomeViewModel的构造函数
public ShellViewModel()
{
CreateSourceItem();
}
private void CreateSourceItem()
{
HomeViewItem = new HomeViewModel();
}
这里还有 2 个电话
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.Where(type => !(String.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("ViewModels"))
.ToList() // <= !!! look here in debugger, what ToList() returns.
// Here foreach loop calls constructor ShellViewModel()
// which calls HomeViewModel() via CreateSourceItem() again
// then the loop calls constructor of HomeViewModel() separately.
.ForEach(viewModelType => _container.RegisterSingleton(
viewModelType, viewModelType.ToString(), viewModelType));
总计: 3 次。全部正确。
单例很危险。
有人介意帮我解决 WPF MVVM 理解问题吗? 我用 caliburn.micro 作为 MVVM 框架构建了一个 MVVM 项目。请耐心等待,因为这是我第一次创建此类项目。网格应该显示一种主屏幕 (HomeViewModel)。 因此,它的绑定已添加到内容控件中。 有人可以协助并告诉我为什么我的 HomeViewModel 的构造函数被实例化了 3 次吗? 另一方面,如果有人可以解释如何为 ViewModels 实现方法,我会很好吗?所有这些,包括日志记录都执行了三次。
<Window [...]>
<Window.DataContext>
<viewModels:ShellViewModel />
</Window.DataContext>
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type viewModels:HomeViewModel}">
<local:HomeView DataContext="{Binding}" />
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="1">
<ContentControl.Content>
<Binding FallbackValue="{x:Null}"
Mode="OneWay"
Path="viewModels:HomeViewItem"
RelativeSource="{RelativeSource Self}" />
</ContentControl.Content>
</ContentControl>
</Grid>
我在我的引导程序中根据 caliburn.micro 文档实现了一个 SimpleContainer:
public class Bootstrapper : BootstrapperBase
{
private SimpleContainer _container;
public Bootstrapper()
{
Initialize();
}
protected override void Configure()
{
_container = new SimpleContainer();
_container.Singleton<IWindowManager, WindowManager>();
// Registering ViewModels
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.Where(type => !(String.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("ViewModels"))
.ToList()
.ForEach(viewModelType => _container.RegisterSingleton(
viewModelType, viewModelType.ToString(), viewModelType));
// Registering Views
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("View"))
.Where(type => !(String.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("Views"))
.ToList()
.ForEach(viewModelType => _container.RegisterSingleton(
viewModelType, viewModelType.ToString(), viewModelType));
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
return _container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
我的 HomeViewModel 是这样实现的:
public class HomeViewModel : Conductor<IScreen>
{
public HomeViewModel()
{
Debug.WriteLine("Hello from HomeVM");
}
}
我的 ShellViewModel 是这样的:
public class ShellViewModel : Screen
{
private IScreen _homeViewItem;
public ShellViewModel()
{
CreateSourceItem();
}
public IScreen HomeViewItem
{
get => _homeViewItem;
set
{
if (Equals(value, _homeViewItem))
return;
_homeViewItem = value;
NotifyOfPropertyChange(() => HomeViewItem);
}
}
private void CreateSourceItem()
{
HomeViewItem = new HomeViewModel();
}
}
应用程序启动时,调试输出中有 3 个 HomeViewModel 实现条目:
Hello from HomeVM
Hello from HomeVM
Hello from HomeVM
如果多次调用构造函数,容器内的Singleton DI应该return现有实例,不是吗? 顺便说一句:StartupUri 已从 app.xaml 中删除。 提前致谢!
此标记调用 ShellViewModel 的构造函数
<Window.DataContext>
<viewModels:ShellViewModel />
</Window.DataContext>
通过
调用HomeViewModel的构造函数public ShellViewModel()
{
CreateSourceItem();
}
private void CreateSourceItem()
{
HomeViewItem = new HomeViewModel();
}
这里还有 2 个电话
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.Where(type => !(String.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("ViewModels"))
.ToList() // <= !!! look here in debugger, what ToList() returns.
// Here foreach loop calls constructor ShellViewModel()
// which calls HomeViewModel() via CreateSourceItem() again
// then the loop calls constructor of HomeViewModel() separately.
.ForEach(viewModelType => _container.RegisterSingleton(
viewModelType, viewModelType.ToString(), viewModelType));
总计: 3 次。全部正确。
单例很危险。