Может, кто-нибудь возражает помочь мне с проблемой понимания WPF MVVM? Я создал проект MVVM с caliburn.micro в качестве основы 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>
Я реализовал SimpleContainer в соответствии с документацией caliburn.micro в моем загрузчике:
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
Если конструктор вызывается несколько раз, DI-объект Singleton внутри контейнера должен возвращать существующий экземпляр, не так ли? Кстати: StartupUri был удален из app.xaml. Заранее спасибо!