Mvvm Light,UWP和代码后台

3

基于 Laurent Bugnion 在 Xamarin Evolve 2014 上的这个优秀的演示文稿,我正在尝试创建我的第一个 UWP/MVVM Light 应用程序。

我创建了一个非常简单的Article : ObservableObject类,其中包含两个字符串属性:RéférenceDésignation

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

    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;
    }
}

有没有一种方法可以保持设计时的DataContext,就像在Xaml的页面中定义的d:DataContext部分一样,在运行时从导航参数中获取DataContext?
我的目标是尽可能少地在代码后台中编写代码。因此,我也想在XAML中定义运行时DataContext。

2
来自另一个法国人的建议:在类成员/方法中,永远不要使用带重音的字符。只需使用ACSII字符以避免任何错误。 - Arnaud Develay
Arnaud,我们可以为此辩论数小时 :) 为了证明我的观点,我在C#中使用重音符号已经超过10年了。我要求我的开发人员(好吧,我强迫他们)这样做,因为1/我从来没有因为这个而出现任何错误,Visual Studio完美地管理Unicode文件2/它使代码更易读3/我有一种感觉,你的想法来自于旧时代的语言(在.Net时代之前,我使用Delphi多年)。 - Julien Ferraro
1
@JulienFerraro,你应该避免在任何可能被非法语使用者阅读的代码中使用法语。这里你至少破坏了两个命名约定。保持代码整洁。 - aloisdg
2个回答

1
您可以利用依赖注入为视图模型创建设计或运行时服务实例。使用视图模型定位器,您可以像这样做:
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

Hosney,感谢您的及时回答。不过,我的问题并不完全是这样的。我在我的解决方案中几乎有与您展示的代码完全相同的代码。请查看示例中的Flowers.Wp/DetailsPage.xaml。DataContext已定义为设计时间。运行时数据上下文在代码后台中定义。我的问题是:为什么我们应该在代码后台中定义运行时数据上下文。 - Julien Ferraro
@JulienFerraro 没有必要这样。我在上面的代码中只在xaml中指定了DataContext,没有后台代码。定位器根据应用程序是运行还是设计模式来决定返回哪个服务实例。 - H77
请查看示例中的Flowers.Wp/MainPage.xaml。它使用了相同的概念。 - H77
Hosney,我的主页面与Flowers.Wp/MainPage.xaml具有完全相同的绑定。 我所说的页面是一个详细视图,类似于Flowers.Wp/DetailsPage.xaml。 为什么Flowers.Wp/MainPage.xaml和Flowers.Wp/DetailsPage.xaml中的绑定不同呢? - Julien Ferraro
@JulienFerraro 我不确定为什么示例是这样做的,但它并不一定非得那样。你可以像在主页面中那样直接绑定到数据上下文,在详细信息页面上进行操作。 - H77
显示剩余3条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接