Mvvm Light、UWP 和代码隐藏

Mvvm Light, UWP and code behind

基于 Xamarin Evolve 2014 上来自 Laurent Bugnion 的 this excellent presentation,我正在尝试创建我的第一个 UWP/MVVM Light 应用程序。

我创建了一个非常简单的 文章:ObservableObject class 具有 2 个字符串属性:Référence名称.

在与文章列表视图关联的视图模型中,我有一个创建新文章的操作:

    public ArticlesViewModel(IArticleService dataService, INavigationService navigationService)
    {
        ArticleService = dataService;
        NavigationService = navigationService;

        CréeArticleCommand = new RelayCommand(CréeArticle);
    }

    public RelayCommand CréeArticleCommand { get; private set; }

    private void CréeArticle()
    {
        if (!CréeArticleCommand.CanExecute(null))
            return;

        NavigationService.NavigateTo(ViewModelLocator.ArticleDetail_Key,
                                     new ArticleViewModel(new Article(),
                                                          ArticleService,
                                                          NavigationService));
    }

这是我的文章详细信息视图的 XAML:

<!-- language: xaml -->
<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UniversalTest1.UWP.Articles"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Editors="using:DevExpress.UI.Xaml.Editors"
    x:Class="UniversalTest1.UWP.Articles.Article_Detail"
    mc:Ignorable="d"
    xmlns:vm="clr-namespace:UniversalTest1.Data.ViewModels.Articles;assembly=UniversalTest1.Data"
    d:DataContext="{d:DesignInstance Type=vm:ArticleViewModel, IsDesignTimeCreatable=True}">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="Référence :"   HorizontalAlignment="Left" Margin="24,15,0,0" VerticalAlignment="Top"/>
        <TextBlock Text="Désignation :" HorizontalAlignment="Left" Margin="10,52,0,0" VerticalAlignment="Top"/>

        <Editors:TextEdit Text="{Binding Article.Référence, Mode=TwoWay}" HorizontalAlignment="Left" Margin="100,8,0,0" VerticalAlignment="Top" Width="300"/>
        <Editors:TextEdit Text="{Binding Article.Désignation, Mode=TwoWay}" HorizontalAlignment="Left" Margin="100,45,0,0" VerticalAlignment="Top" Width="500"/>

        <Button Content="Sauver" Command="{Binding SauverCommand}" HorizontalAlignment="Left" Margin="102,84,0,0" VerticalAlignment="Top"/>
    </Grid>
</Page>

我的问题是我必须在页面后面的代码中定义 DataContext :

public sealed partial class Article_Detail : Page
{
    public Article_Detail()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        DataContext = (ArticleViewModel)e.Parameter;
    }
}

有没有办法保持在 Xaml 页面的 d:DataContext 部分定义的设计时 DataContext,并在运行时从导航参数 ?

我的目标是尽可能减少后台代码中的代码量。所以我也想在 XAML 中定义运行时 DataContext。

您可以使用依赖注入为您的视图模型创建设计或运行时服务实例。使用视图模型定位器,您可以执行以下操作:

public class ViewModelLocator
{
    static ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            if (!SimpleIoc.Default.IsRegistered<IArticleService>())
            {
                SimpleIoc.Default.Register<IArticleService, DesignArticleService>();
            }
        }
        else
        {
            if (!SimpleIoc.Default.IsRegistered<IArticleService>())
            {
                SimpleIoc.Default.Register<IArticleService, ArticleService>();
            }
        }

        SimpleIoc.Default.Register<ArticleViewModel>();
    }

    public ArticleViewModel ArticleViewModel => ServiceLocator.Current.GetInstance<ArticleViewModel>();
}

然后在您的 App.xaml 中注册定位器

<Application
    x:Class="UniversalTest1.App" // your namespace
    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" 
    mc:Ignorable="d" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:viewModel="using:UniversalTest1.Data.ViewModels"> // your namespace

    <Application.Resources>

        <ResourceDictionary>
            <viewModel:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
        </ResourceDictionary>

    </Application.Resources>

</Application>

然后您可以在 xaml 中引用它,如下所示:

<Page
...
DataContext="{Binding ArticleViewModel, Source={StaticResource Locator}}">

您也可以在此处查看示例代码https://mvvmlight.codeplex.com/SourceControl/latest#Samples/Flowers/Flowers.Data/ViewModel/ViewModelLocator.cs

为此,您需要使用自己的 NavigationService 实现。这个概念是导航到您的页面并同时调用您的 ViewModel 来处理参数并设置 DataContext.

这是此模式的两个示例: