Reputation: 401
Base on this excellent presentation from Laurent Bugnion at Xamarin Evolve 2014, I'm trying to create my first UWP/MVVM Light application.
I created a very simple Article : ObservableObject class with 2 string properties : Référence and Désignation.
In the view model associated to the article list view, I have an action to create a new article :
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));
}
here is the XAML for my Article detail view :
<!-- 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>
My problem here is that I have to define the DataContext in the code behind of my page :
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;
}
}
Is there a way to keep the design time DataContext as defined in the d:DataContext part of the Xaml's Page, and at runtime, get the DataContext from the Navigation parameter ?
My goal here is to have the less amount possible of code in the code behind. So I would like to define the runtime DataContext in the XAML also.
Upvotes: 3
Views: 2192
Reputation: 3970
For this, you need to use your own implementation of NavigationService
. The concept is to navigate to your page and call your ViewModel at the same time to handle parameters and set the DataContext.
Here are two samples of this pattern:
Upvotes: 0
Reputation: 5967
You can make use of dependency injection to create design or runtime service instances for your viewmodel. Using a view model locator you can do something like this:
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>();
}
And in your App.xaml you register the locator
<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>
And then you can reference it in your xaml like this:
<Page
...
DataContext="{Binding ArticleViewModel, Source={StaticResource Locator}}">
You could also take a look at the sample code here https://mvvmlight.codeplex.com/SourceControl/latest#Samples/Flowers/Flowers.Data/ViewModel/ViewModelLocator.cs
Upvotes: 1