Caliburn.Micro 仅 GetAllInstances returns 一个视图模型(Caliburn.Micro MVVM)
Caliburn.Micro GetAllInstances only returns one viewModel(Caliburn.Micro MVVM)
我一直在尝试将 Caliburn.Micro MVVM 框架集成到 C# WPF 项目中,我正处于中间阶段。
我目前只有三个视图模型:
- ShellViewModel -(Window 带有 ContentControl 的视图)
- AboutViewModel -(用户控件视图)
- ChatViewModel -(另一个用户控件视图)
目前,我正在尝试在 AboutView 中使用一个按钮,该按钮绑定到 AboutViewModel 中的 'Chat()' 方法,应该将用户带到 ChatView,但我正在使用 AboutViewModel 对此进行测试。 (如处理程序中所示)
我需要的是所有 Screen/ViewModels 都是单例并且只有一个实例,当我尝试更改页面时,它 returns 到一个已经存在的页面。
这里的问题是,当我执行 IoC.GetAllInstances() 时,我只注册了一个实例,即 ShellViewModel,即使我在引导程序中尝试了多种配置,我也无法在一个实例中注册我的其他 ViewModel制作实例的方法 "reachable"
感谢您抽出宝贵时间,这是我认为与该问题相关的代码:
这是我的引导程序:
public class AppBootstrapper : BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public AppBootstrapper()
{
Initialize();
var config = new TypeMappingConfiguration
{
DefaultSubNamespaceForViewModels = "ViewModel",
DefaultSubNamespaceForViews = "View"
};
ViewLocator.ConfigureTypeMappings(config);
Caliburn.Micro.ViewModelLocator.ConfigureTypeMappings(config);
}
protected override void Configure()
{
_container.Singleton<ShellViewModel, ShellViewModel>();
_container.Singleton<IWindowManager, WindowManager>();
//tried registering AboutViewModel in multiple ways
_container.Singleton<AboutViewModel, AboutViewModel>();
_container.RegisterSingleton(typeof(AboutViewModel), null,typeof(AboutViewModel));
/
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
}
ShellViewModel.cs:
public class ShellViewModel : Conductor<object>, IHandle<NavigationMessage>
{
/// <summary>
/// Caliburn.Micro event aggregator. (Publish/Subscribe pattern)
/// </summary>
public IEventAggregator events = new EventAggregator();
public ShellViewModel()
{
//var aaa = IoC.Get<IEventAggregator>();
events.Subscribe(this);
ActivateItem(new AboutViewModel(events));
}
public void Handle(NavigationMessage message)
{
//var instance = IoC.GetInstance(message.ViewModelType,null);
var instances = IoC.GetAllInstances(null);
foreach(var i in instances)
{
MessageBox.Show(i.ToString());
}
ActivateItem(new AboutViewModel(events));
}
}
和 AboutViewModel.cs:
/// <summary>
/// ViewModel belonging to the AboutView.xaml.
/// </summary>
/// <seealso cref="AboutView.xaml"/>
public class AboutViewModel : Screen, IHandle<NavigationMessage>
{
private readonly IEventAggregator _eventAggregator;
/// <summary>
/// Private container for the 'Version' public property.
/// </summary>
/// <see cref="Version"/>
private string _version;
/// <summary>
/// Property containing a string of the application's current version (e.g.: 0.1.3.45)
/// </summary>
/// <see cref="_version"/>
[JsonIgnore]
public string Version
{
get
{
return _version;
}
set
{
_version = value;
NotifyOfPropertyChange(() => Version);
}
}
/// <summary>
/// Base constructor for the AboutViewModel class.
/// </summary>
public AboutViewModel(IEventAggregator eventAggregator)
{
Logging.Info("Initialize AboutViewModel", this.GetType());
Logging.Debug("Subscribing to the eventAggregator", this.GetType());
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
_version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
Logging.Debug("Version loaded (" + _version + ")", this.GetType());
}
/// <summary>
/// Boolean method connected to the ChatCommand activates or deactivates based on it's return
/// </summary>
/// <param name="obj">Object of type GotoPageMessage received from the messenger</param>
public bool CanChat(object obj)
{
return true;
}
/// <summary>
/// Method connected to the ChatCommand that sends the user to the 'Chat' view
/// </summary>
/// <param name="obj">Object of type GotoPageMessage received from the messenger</param>
public void Chat(object obj)
{
_eventAggregator.PublishOnUIThread(new NavigationMessage(typeof(AboutViewModel)));
}
public void Handle(NavigationMessage message)
{
//This handle is used only to know how many instances I have active
MessageBox.Show("about");
}
}
编辑 1:
P.S.: 我以前的 ShellViewModel 是 Conductor.Collection.OneActive。仍然没有用。也许 AllActive 可以工作?...
覆盖 Caliburn Micro 的 SelectAssemblies 方法以定位所有视图:
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
Assembly.GetExecutingAssembly(), typeof(MainViewModel).Assembly
};
}
有关引导程序的更多信息 here。
我现在确实找到了一个解决方案,没有弄乱程序集。
我注意到 ShellViewModel 的实例是可访问的,通过将实例保存到一个对象中并对其进行调试,我注意到我创建的所有 viewModel 实例都在 'Items'。
基本上这就是我在 ShellViewModel 内部的处理程序中所做的:
public void Handle(NavigationMessage message)
{
ShellViewModel Shell = (ShellViewModel)IoC.GetInstance(typeof(ShellViewModel), null);
object Instance = null;
foreach (var item in Shell.Items)
{
if (item.ToString().Contains(message.ViewModelType.ToString()))
Instance = item;
}
object AuxObject = new object();
if (Instance == null)
{
try
{
Instance = Activator.CreateInstance(message.ViewModelType, Shell.events);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
ActivateItem(Instance);
}
我一直在尝试将 Caliburn.Micro MVVM 框架集成到 C# WPF 项目中,我正处于中间阶段。
我目前只有三个视图模型:
- ShellViewModel -(Window 带有 ContentControl 的视图)
- AboutViewModel -(用户控件视图)
- ChatViewModel -(另一个用户控件视图)
目前,我正在尝试在 AboutView 中使用一个按钮,该按钮绑定到 AboutViewModel 中的 'Chat()' 方法,应该将用户带到 ChatView,但我正在使用 AboutViewModel 对此进行测试。 (如处理程序中所示)
我需要的是所有 Screen/ViewModels 都是单例并且只有一个实例,当我尝试更改页面时,它 returns 到一个已经存在的页面。
这里的问题是,当我执行 IoC.GetAllInstances() 时,我只注册了一个实例,即 ShellViewModel,即使我在引导程序中尝试了多种配置,我也无法在一个实例中注册我的其他 ViewModel制作实例的方法 "reachable"
感谢您抽出宝贵时间,这是我认为与该问题相关的代码:
这是我的引导程序:
public class AppBootstrapper : BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public AppBootstrapper()
{
Initialize();
var config = new TypeMappingConfiguration
{
DefaultSubNamespaceForViewModels = "ViewModel",
DefaultSubNamespaceForViews = "View"
};
ViewLocator.ConfigureTypeMappings(config);
Caliburn.Micro.ViewModelLocator.ConfigureTypeMappings(config);
}
protected override void Configure()
{
_container.Singleton<ShellViewModel, ShellViewModel>();
_container.Singleton<IWindowManager, WindowManager>();
//tried registering AboutViewModel in multiple ways
_container.Singleton<AboutViewModel, AboutViewModel>();
_container.RegisterSingleton(typeof(AboutViewModel), null,typeof(AboutViewModel));
/
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
}
ShellViewModel.cs:
public class ShellViewModel : Conductor<object>, IHandle<NavigationMessage>
{
/// <summary>
/// Caliburn.Micro event aggregator. (Publish/Subscribe pattern)
/// </summary>
public IEventAggregator events = new EventAggregator();
public ShellViewModel()
{
//var aaa = IoC.Get<IEventAggregator>();
events.Subscribe(this);
ActivateItem(new AboutViewModel(events));
}
public void Handle(NavigationMessage message)
{
//var instance = IoC.GetInstance(message.ViewModelType,null);
var instances = IoC.GetAllInstances(null);
foreach(var i in instances)
{
MessageBox.Show(i.ToString());
}
ActivateItem(new AboutViewModel(events));
}
}
和 AboutViewModel.cs:
/// <summary>
/// ViewModel belonging to the AboutView.xaml.
/// </summary>
/// <seealso cref="AboutView.xaml"/>
public class AboutViewModel : Screen, IHandle<NavigationMessage>
{
private readonly IEventAggregator _eventAggregator;
/// <summary>
/// Private container for the 'Version' public property.
/// </summary>
/// <see cref="Version"/>
private string _version;
/// <summary>
/// Property containing a string of the application's current version (e.g.: 0.1.3.45)
/// </summary>
/// <see cref="_version"/>
[JsonIgnore]
public string Version
{
get
{
return _version;
}
set
{
_version = value;
NotifyOfPropertyChange(() => Version);
}
}
/// <summary>
/// Base constructor for the AboutViewModel class.
/// </summary>
public AboutViewModel(IEventAggregator eventAggregator)
{
Logging.Info("Initialize AboutViewModel", this.GetType());
Logging.Debug("Subscribing to the eventAggregator", this.GetType());
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
_version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
Logging.Debug("Version loaded (" + _version + ")", this.GetType());
}
/// <summary>
/// Boolean method connected to the ChatCommand activates or deactivates based on it's return
/// </summary>
/// <param name="obj">Object of type GotoPageMessage received from the messenger</param>
public bool CanChat(object obj)
{
return true;
}
/// <summary>
/// Method connected to the ChatCommand that sends the user to the 'Chat' view
/// </summary>
/// <param name="obj">Object of type GotoPageMessage received from the messenger</param>
public void Chat(object obj)
{
_eventAggregator.PublishOnUIThread(new NavigationMessage(typeof(AboutViewModel)));
}
public void Handle(NavigationMessage message)
{
//This handle is used only to know how many instances I have active
MessageBox.Show("about");
}
}
编辑 1:
P.S.: 我以前的 ShellViewModel 是 Conductor.Collection.OneActive。仍然没有用。也许 AllActive 可以工作?...
覆盖 Caliburn Micro 的 SelectAssemblies 方法以定位所有视图:
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
Assembly.GetExecutingAssembly(), typeof(MainViewModel).Assembly
};
}
有关引导程序的更多信息 here。
我现在确实找到了一个解决方案,没有弄乱程序集。
我注意到 ShellViewModel 的实例是可访问的,通过将实例保存到一个对象中并对其进行调试,我注意到我创建的所有 viewModel 实例都在 'Items'。
基本上这就是我在 ShellViewModel 内部的处理程序中所做的:
public void Handle(NavigationMessage message)
{
ShellViewModel Shell = (ShellViewModel)IoC.GetInstance(typeof(ShellViewModel), null);
object Instance = null;
foreach (var item in Shell.Items)
{
if (item.ToString().Contains(message.ViewModelType.ToString()))
Instance = item;
}
object AuxObject = new object();
if (Instance == null)
{
try
{
Instance = Activator.CreateInstance(message.ViewModelType, Shell.events);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
ActivateItem(Instance);
}