希望有人可以使用服务定位器来启发我最好的mvvm练习。 基本原则很明确。我有相应视图模型的视图,一切都可以正常工作。
让我们举一个简单的例子。我有一个主窗口和2个用户控件UCA和UCB。他们每个人都有在定位器类中注册的视图模型。
使用此IoC模式,如何使用一个内容控件和主窗口视图模型绑定在主窗口中显示UCA和UCB?确切地说,我想同时只显示一个控件。我无法绑定UCA或UCB视图模型,因为这是视图第一种方法,视图不会自动解析。
这方面的正确方法是什么?
由于
答案 0 :(得分:0)
您可以创建单独的服务以将视图作为对话框启动,以便可以在整个应用程序中以通用方式使用它。并将通过构造函数将此服务注入ViewModel
,该构造函数将启动任何对话框。
public interface IDialogService<T>
{
void Show();
void ShowDialog();
}
public class DialogService<T> : IDialogService<T> where T : Window
{
public void Show()
{
container.Resolve<T>().Show();
}
public void ShowDialog()
{
container.Resolve<T>().ShowDialog();
}
}
现在只需将此服务注入相应的viewmodel
。
public class YourViewModel
{
//commands
public ICommand someCommand { get; set; }
private IDialogService<BookingView> _dialogService;
public YourViewModel(IDialogService<YourView > dialogService)
{
_dialogService = dialogService
someCommand = new RelayCommand(someCommandDoJob, () => true);
}
public void someCommandDoJob(object obj)
{
//Since you want to launch this view as dialog you can set its datacontext in its own constructor.
_dialogService.ShowDialog();
}
}
答案 1 :(得分:0)
一种解决方案可能是使用ContentTemplate
属性和DataTrigger
来选择性地显示UCA或UCB(参见下面的示例)。 UCA也可以在样式设置器中设置为默认视图。在这种情况下,只需要一个DataTriggers
。
另一种解决方案可能是使用ContentTemplateSelector
属性并实现DataTemplateSelector
。
请参阅:ContentControl.ContentTemplateSelector (MSDN)
<!--content control in main window-->
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<!--suppose main window view model has a bool property UseUCA-->
<!--if UseUCA is true render UCA view-->
<DataTrigger Binding="{Binding UseUCA}" Value="True">
<DataTrigger.Setters>
<!--by setting ContentTemplate property you control what is rendered inside of the content control-->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<!--render UCA view-->
<local:UCA />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
<!--if UseUCA is false render UCB view-->
<DataTrigger Binding="{Binding UseUCA}" Value="False">
<DataTrigger.Setters>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<!--render UCB view-->
<local:UCB />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
答案 2 :(得分:0)
好的......这是一个想法...你可以跟踪&#34; currentview&#34;在您的MainViewModel中,让UI显示基于类型的正确控件。这是一个简单的例子。我正在使用Button切换视图......理想情况下,这可以通过符合您要求的任何逻辑来完成。
主窗口:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Content="Switch Views" Command="{Binding SwitchViewsCommand}" />
<ContentControl Grid.Row="1" Content="{Binding CurrentControl}">
</ContentControl>
</Grid>
</Window>
UCA和UCB只是用户控件,其中包含不同的文本:
<UserControl x:Class="WpfApplication4.UserControls.UCA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication4.UserControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="This is user control A" />
</Grid>
</UserControl>
UCAViewModel和UCBViewModel在我的示例中是从ViewModelBase继承的空视图模型
namespace WpfApplication4.ViewModel
{
public class UCAViewModel : ViewModelBase
{
}
}
MainViewModel根据其viewmodel
处理当前显示的视图using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Practices.ServiceLocation;
namespace WpfApplication4.ViewModel
{
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
RegisterCommands();
SwitchView();
}
private void SwitchView()
{
if(CurrentControl == null)
{
CurrentControl = ServiceLocator.Current.GetInstance<UCAViewModel>();
}
else
{
if(CurrentControl is UCAViewModel)
CurrentControl = ServiceLocator.Current.GetInstance<UCBViewModel>();
else
CurrentControl = ServiceLocator.Current.GetInstance<UCAViewModel>();
}
}
private ViewModelBase _currentControl;
public ViewModelBase CurrentControl
{
get { return _currentControl; }
set
{
if (_currentControl != value)
{
_currentControl = value;
RaisePropertyChanged("CurrentControl");
}
}
}
private void RegisterCommands()
{
SwitchViewsCommand = new RelayCommand(SwitchView);
}
public RelayCommand SwitchViewsCommand { get; private set; }
}
}
ViewModelLocator存储实例
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
namespace WpfApplication4.ViewModel
{
/// <summary>
/// This class contains static references to all the view models in the
/// application and provides an entry point for the bindings.
/// </summary>
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<UCAViewModel>();
SimpleIoc.Default.Register<UCBViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
}
}
}
最后,制作正确视图的胶水在app.xaml文件中完成:
<Application x:Class="WpfApplication4.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication4" StartupUri="MainWindow.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:localUC="clr-namespace:WpfApplication4.UserControls"
xmlns:vm="clr-namespace:WpfApplication4.ViewModel">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<DataTemplate DataType="{x:Type vm:UCAViewModel}">
<localUC:UCA />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:UCBViewModel}">
<localUC:UCB />
</DataTemplate>
</Application.Resources>
</Application>