从视图模型中的按钮单击调用第二个视图
Invoking second view from button click in view model
尝试使用 WPF 和 MVVM 设计模式来完成 Castle Windsor。我的解决方案中有三个项目,即 MainView、ViewModel 和 IoCInstaller 项目。
MainView 依赖于 IoCInstaller 和 ViewModel。
IoCInstaller 依赖于 ViewModel。
现在我想从 ViewModel 中的按钮单击操作调用 SecondView,但基于依赖关系,我发现这很难。我知道我的 castle windsor 实现并不理想,但我没有找到关于它的理想实现方式的任何好的答案。任何建议都会很有帮助。
阅读文档并通过网络搜索后,我完成了基本的城堡实现工作,但是当涉及到 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
}
您当前使用的方式 Castle.Windsor
更像是一个 ServiceLocator 而不是 IOC 容器。
我建议您使用 typed factories to resolve your classes. With factories you don't need a public static WindsorContainer
because you only call Resolve
once (also see the Three-Calls-Pattern).
首先使用 Bootstrapper
-Class 调用 IWindsorInstaller
并注册 TypedFactoryFacility
:
public class Bootstrapper
{
public IWindsorContainer BootstrapContainer()
{
IWindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
return container.Install(new IocInstaller());
}
}
您可以通过 MainView
或 App.xaml.cs
调用 BootstrapContainer()
。
现在为您的 ViewModel
创建一个工厂:
public interface IViewModelFactory
{
IViewModel Create();
void Release(IViewModel viewModel);
}
您不需要实现这个工厂,Windsor 会为您完成。
您唯一需要做的就是更改您的 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
,您可以在调用 Bootstrapper
的位置调用 Resolve
并获得 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
打开另一个 window,你可以很容易地做到这一点。
首先为你的第二个视图模型创建一个工厂:
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
并显示一个新的 window,其中 SecondViewModel
作为您的 DataContext
:
public void MyActionForBttnClicked()
{
//invoke second view
ISecondViewModel secondViewModel = _secondViewModelFactory.Create();
SecondWindow secondWindow = new SecondWindow();
secondWindow.DataContext = secondViewModel;
secondWindow.ShowDialog();
}
尝试使用 WPF 和 MVVM 设计模式来完成 Castle Windsor。我的解决方案中有三个项目,即 MainView、ViewModel 和 IoCInstaller 项目。
MainView 依赖于 IoCInstaller 和 ViewModel。 IoCInstaller 依赖于 ViewModel。
现在我想从 ViewModel 中的按钮单击操作调用 SecondView,但基于依赖关系,我发现这很难。我知道我的 castle windsor 实现并不理想,但我没有找到关于它的理想实现方式的任何好的答案。任何建议都会很有帮助。
阅读文档并通过网络搜索后,我完成了基本的城堡实现工作,但是当涉及到 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
}
您当前使用的方式 Castle.Windsor
更像是一个 ServiceLocator 而不是 IOC 容器。
我建议您使用 typed factories to resolve your classes. With factories you don't need a public static WindsorContainer
because you only call Resolve
once (also see the Three-Calls-Pattern).
首先使用 Bootstrapper
-Class 调用 IWindsorInstaller
并注册 TypedFactoryFacility
:
public class Bootstrapper
{
public IWindsorContainer BootstrapContainer()
{
IWindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
return container.Install(new IocInstaller());
}
}
您可以通过 MainView
或 App.xaml.cs
调用 BootstrapContainer()
。
现在为您的 ViewModel
创建一个工厂:
public interface IViewModelFactory
{
IViewModel Create();
void Release(IViewModel viewModel);
}
您不需要实现这个工厂,Windsor 会为您完成。
您唯一需要做的就是更改您的 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
,您可以在调用 Bootstrapper
的位置调用 Resolve
并获得 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
打开另一个 window,你可以很容易地做到这一点。
首先为你的第二个视图模型创建一个工厂:
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
并显示一个新的 window,其中 SecondViewModel
作为您的 DataContext
:
public void MyActionForBttnClicked()
{
//invoke second view
ISecondViewModel secondViewModel = _secondViewModelFactory.Create();
SecondWindow secondWindow = new SecondWindow();
secondWindow.DataContext = secondViewModel;
secondWindow.ShowDialog();
}