SimpleIoc MVVM解析视图(UserControl)

时间:2016-05-03 13:09:05

标签: wpf inversion-of-control

希望有人可以使用服务定位器来启发我最好的mvvm练习。 基本原则很明确。我有相应视图模型的视图,一切都可以正常工作。

让我们举一个简单的例子。我有一个主窗口和2个用户控件UCA和UCB。他们每个人都有在定位器类中注册的视图模型。

使用此IoC模式,如何使用一个内容控件和主窗口视图模型绑定在主窗口中显示UCA和UCB?确切地说,我想同时只显示一个控件。我无法绑定UCA或UCB视图模型,因为这是视图第一种方法,视图不会自动解析。

这方面的正确方法是什么?

由于

3 个答案:

答案 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>