【发布时间】:2020-07-18 20:57:48
【问题描述】:
有人介意帮助我解决 WPF MVVM 理解问题吗? 我用 caliburn.micro 作为 MVVM 框架构建了一个 MVVM 项目。请多多包涵,因为这是我第一次创建这种项目。网格应该显示一种主屏幕(HomeViewModel)。 因此,它的绑定已添加到内容控件中。 有人可以帮忙告诉我为什么我的 HomeViewModel 的构造函数被实例化了 3 次吗? 另一方面,如果有人可以解释如何实现 ViewModel 的方法,我会很好吗?所有这些,包括日志记录都执行了 3 次。
<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 应该返回现有实例,不是吗? 顺便说一句: StartupUri 已从 app.xaml 中删除。 提前致谢!
【问题讨论】:
-
当您在 XAML 中设置 DataContext 时,它将创建一个实例。 CreateSourceItem 方法创建一个实例和 DI 容器。 1+1+1=3 q.e.d.
标签: c# wpf mvvm constructor caliburn.micro