尝试使用WPF和MVVM设计模式遍历温莎城堡。我的解决方案中有三个项目,即MainView,ViewModel和IoCInstaller项目。
MainView依赖于IoCInstaller和ViewModel。 IoCInstaller依赖于ViewModel。
现在,我想从ViewModel中的按钮单击操作中调用SecondView,但是基于依赖关系,我发现这很困难。我知道我的城堡温莎城堡实施不是理想的,但是在理想的实施方式上我找不到任何好的答案。任何建议都会很有帮助。
阅读文档并通过网络搜索后,我完成了基本的城堡实现工作,但在WPF和MVVM方面,我感到很困惑。
ViewModel项目
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
var iocContainer = IoCInstaller.WindsorContainer;
iocContainer.Install(new IoCInstaller());
var mainWindowViewModel = iocContainer.Resolve<IMainWindowViewModel>();
mainWindowViewModel.Initialize(iocContainer);
DataContext = mainWindowViewModel;
}
}
IoCInstaller项目
public class IoCInstaller : IWindsorInstaller
{
private static WindsorContainer _windsorContainer;
public static WindsorContainer WindsorContainer
{
get
{
if (_windsorContainer == null)
{
_windsorContainer = new WindsorContainer();
return _windsorContainer;
}
else
{
return _windsorContainer;
}
}
}
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Castle.MicroKernel.Registration.Component.For<IViewModel>());
}
}
最后是 ViewModel项目
public class ViewModel : INotifyPropertyChanged, IViewModel
{
public ViewModel()
{
}
public void Initialize(WindsorContainer windsorContainer)
{
Logger.Debug("Initializing main view model ");
iocContainer = windsorContainer;
}
public void MyActionForBttnClicked()
{
//invoke second view
}
//Other stuff
}
答案 0 :(得分:2)
您当前使用Castle.Windsor
的方式更像是ServiceLocator,而不是IOC容器。
我建议您使用typed factories来解决您的课程。在工厂中,您不需要public static WindsorContainer
,因为您只需调用Resolve
一次(另请参阅Three-Calls-Pattern)。
首先使用Bootstrapper
类,在其中调用IWindsorInstaller
,并注册TypedFactoryFacility
的使用:
public class Bootstrapper
{
public IWindsorContainer BootstrapContainer()
{
IWindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
return container.Install(new IocInstaller());
}
}
您可以从BootstrapContainer()
或MainView
致电App.xaml.cs
。
现在为您的ViewModel
创建工厂:
public interface IViewModelFactory
{
IViewModel Create();
void Release(IViewModel viewModel);
}
您不需要实现这个工厂,温莎会为您实现。
您唯一需要做的就是更改IocInstaller
并注册IViewModelFactory
:
public class IocInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IViewModel>().ImplementedBy<MainWindowViewModel>().LifestyleTransient());
container.Register(Component.For<IViewModelFactory>().AsFactory());
}
}
确保您熟悉可用的Lifestyles
。当您可能想使用LifestyleSingleton()
时,默认值为LifestyleTransient()
。有关更多信息,请参见this link。
要创建您的ViewModel
,您可以在致电Resolve
的位置致电Bootstrapper
并获得IViewModelFactory
:
public MainView()
{
//other stuff
Bootstrapper bootstrapper = new Bootstrapper();
IWindsorContainer container = bootstrapper.BootstrapContainer();
IViewModelFactory viewModelFactory = container.Resolve<IViewModelFactory>();
IViewModel viewModel = viewModelFactory.Create();
DataContext = viewModel;
}
如果您现在想从ViewModel
打开另一个窗口,则可以轻松完成。
首先为您的第二个视图模型创建一个工厂:
public interface ISecondViewModelFactory
{
ISecondViewModel Create();
void Release(ISecondViewModel secondViewModel);
}
然后在您的IocInstaller
中注册新类:
public class IocInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//registration for ViewModel
container.Register(Component.For<ISecondViewModel>().ImplementedBy<SecondViewModel>().LifestyleTransient());
container.Register(Component.For<ISecondViewModelFactory>().AsFactory());
}
}
现在可以将新的ISecondViewModelFactory
设置为ViewModel
的构造函数的参数:
public class ViewModel : INotifyPropertyChanged, IViewModel
{
private readonly ISecondViewModelFactory _secondViewModelFactory;
public ViewModel(ISecondViewModelFactory secondViewModelFactory)
{
_secondViewModelFactory = secondViewModelFactory;
}
}
ISecondViewModelFactory
已由温莎为您解决,因此您不必担心。
然后,您可以轻松创建新的SecondViewModel
并显示一个以SecondViewModel
作为DataContext
的新窗口:
public void MyActionForBttnClicked()
{
//invoke second view
ISecondViewModel secondViewModel = _secondViewModelFactory.Create();
SecondWindow secondWindow = new SecondWindow();
secondWindow.DataContext = secondViewModel;
secondWindow.ShowDialog();
}