As some background, I'm playing around with a Windows Store App and Windows Phone 8 application sharing a single ViewModel (PCL).
I'm using MVVMLight and NInject / Common Service Locator to instantiate view models and services. Which is great and gives me really nice loose coupling that is fantastic to test etc etc.
However, getting design time data support (by switching in a different NInject module etc) is a complete black-box, and although I now have it working I'm not very happy with it, and its been mainly through trial and error.
I'm using the standard practice of having a ViewModelLocator
(instantiated as an app resource) that pulls View Models from the Service Locator. This always gets executed.
Problem is, I can't tell how much of my code is actually being executed by the design-time editor. So, to ensure that NInject is initialised and the CSL hooked into NInject, I have to have a static constructor on the ViewModelLocator
that calls into my App
class to kick-off NInject.
This seems wrong to me. So really, I'd like to know what the best practice for this is, and if there is actually any documentation / guarantees on which parts of the application are "started" whilst it is being shown at design time, and if that differs between Windows Store Apps and Windows Phone 8 apps.
ViewModelLocator.cs (snippet)
public class ViewModelLocator
{
static ViewModelLocator()
{
System.Diagnostics.Debug.WriteLine("VML Start");
var servicelocator = new NinjectServiceLocator(App.Kernel);
ServiceLocator.SetLocatorProvider(() => servicelocator);
System.Diagnostics.Debug.WriteLine("VML End");
}
public AppViewModel AppViewModel
{
get { return ServiceLocator.Current.GetInstance<AppViewModel>(); }
}
public MainViewModel MainViewModel
{
get { return ServiceLocator.Current.GetInstance<MainViewModel>(); }
}
}
App.xaml.cs (snippet)
partial class App : Application
{
public static StandardKernel Kernel { private set; get; }
static App()
{
// Register dependencies & hook the service locator to use NInject under the hood
var servicemodule = ViewModelBase.IsInDesignModeStatic ? (NinjectModule)new DesignTimeModule() : new RunTimeModule();
var viewmodelmodule = new ViewModelModule();
App.Kernel = new StandardKernel(servicemodule, viewmodelmodule);
}
}
App.xaml (snippet)
<?xml version="1.0" encoding="utf-8"?>
<Application RequestedTheme="Dark"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="KieranBenton.LeaveNow.App.App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:app="using:KieranBenton.LeaveNow.App"
xmlns:dependencies="using:KieranBenton.LeaveNow.App.Dependencies"
mc:Ignorable="d">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
...
</ResourceDictionary.MergedDictionaries>
<dependencies:ViewModelLocator x:Key="ViewModelLocator"
d:IsDataSource="True" />
</ResourceDictionary>
</Application.Resources>
</Application>
Main.xaml
<tcdcontrols:LayoutAwarePage x:Name="pageRoot"
x:Class="KieranBenton.LeaveNow.App.Pages.Main"
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:tcdcontrols="using:TCD.Controls"
xmlns:vm="using:KieranBenton.LeaveNow.ViewModel"
mc:Ignorable="d"
DataContext="{Binding MainViewModel, Source={StaticResource ViewModelLocator}}">
<Page.Resources>
<!-- Collection of grouped items displayed by this page, bound to a subset of the complete item list because items in groups cannot be virtualized -->
<!-- NOTE: Ridiculous lengths to get this working - see http://www.ralbu.com/post/2012/11/18/Building-WinRT-Windows-8-Grouped-items-using-MVVMLight.aspx -->
<CollectionViewSource x:Name="groupedItemsViewSource"
Source="{Binding Journeys}"
d:Source="{Binding Journeys, Source={d:DesignInstance Type=vm:Main, IsDesignTimeCreatable=True}}"
IsSourceGrouped="true"
ItemsPath="Routes" />
</Page.Resources>
Blend for Visual Studio helps you design XAML-based Windows and Web applications. It provides the same basic XAML design experience as Visual Studio and adds visual designers for advanced tasks such as animations and behaviors.
To open the XAML Designer, right-click a XAML file in Solution Explorer and choose View Designer. to switch which window appears on top: either the artboard or the XAML editor.
XAML stands for Extensible Application Markup Language. It's a simple and declarative language based on XML. In XAML, it very easy to create, initialize, and set properties of an object with hierarchical relations. It is mainly used for designing GUIs.
To open this page, choose the Tools menu and then choose Options. To access the XAML Designer property page, choose the XAML Designer node. Settings for the XAML Designer are applied when you open the document. So, if you make changes to the settings, you need to close and then reopen Visual Studio to see the changes.
The design time editor should only instantiate the page you are editing and execute any code that gets called while doing this:
You didn't say how you wanted to instantiate your ViewModelLocator
and initialize Ninject before trying to get the designer working.Therefore it's difficult to give suggestion how to fix that.
As a general recommandation for design time data I'd recommend you stick with DesignInstance markup which works with both Windows Store Apps and Windows Phone 8. You just need to add design time DataContext
to your Page
markup:
<Page xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DataContext="{d:DesignInstance viewModels:PageViewModel, IsDesignTimeCreatable=True}">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With