How to set DataContext in a SL4 app that uses MEF

Oct 25, 2010 at 3:10 PM

I am currently working on an app that uses MEF to make sure the app can be extended with plugins. The app WCF RIA servies with Silverlight 4.


The strucuture is as follows:

I have a view TimeDetailView to show the data of the currently selected TimeObject. The view imports its ViewModel in the code-behind file:

 [ExportViewType(ViewModuleType = ModuleTypeEnum.TimeTFT, ViewType = ViewTypeEnum.Detail, Name = "TimeDetail")]
 public partial class TimeTFTDetailView : UserControl
 {

  public TimeTFTDetailView()
  {
   InitializeComponent();
  }

  [Import(typeof(TimeTFTViewDetailViewModel))]
  public TimeTFTViewDetailViewModel TimeTFTDetailVM { get; set; }
 }


The ViewModel itself exposes some properties and commands that can be used by the view. Shown here is the CurrentTime property that returns the currently selected TimeObject

 [Export(typeof(TimeTFTViewDetailViewModel))]
 public class TimeTFTViewDetailViewModel : MEViewModelBase
 {
  private ITimeModel _timeModel;
  private IProjectModel _projectModel;

  private TimeObject _currentTime;
  public TimeObject CurrentTime
  {
   get { return _currentTime; }
   private set
   {
    if (value != _currentTime)
    {
     _currentTime = value;
     this.RaisePropertyChanged("CurrentTime");
    }
   }
  }
  [ImportingConstructor]
  public TimeTFTViewDetailViewModel(ITimeModel timeModel)
  {
   _timeModel = timeModel;
  }


In the views xaml code I set the binding:

<UserControl
    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:converters="clr-namespace:TabLive.Client.Libs.Helper;assembly=TabLive.Client.Libs.Helper"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Name="userControl"

x:Class="TabLive.Client.Modules.TimeTFT.Views.TimeTFTDetailView"
    mc:Ignorable="d" d:DesignWidth="440" d:DesignHeight="384">


    <Grid x:Name="LayoutRoot" Background="White">
  <TextBox x:Name="TimeBeginTextBox" HorizontalAlignment="Left" Height="24" Margin="104,48,0,0"

TextWrapping="Wrap" VerticalAlignment="Top" Width="104" 
   Text="{Binding TimeTFTDetailVM.CurrentTime.TimeBegin, ElementName=userControl,

Mode=TwoWay}"/>

     </Grid>
</UserControl>



Now my question:

As the viewModel is only provided as a property in the codebehind file of the view, I am (so far) not able to use the viewModel as datacontext for the view. If I set it in xaml I get the error "viewmodel is not usable as an object element because it does not define a parameterless public constructor." Which is of course true as I need to import the timeModel in the constructor.

Because of this I have to set each binding with the element property (Binding TimeTFTDetailVM.CurrentTime.TimeBegin, ElementName=userControl) and not via the DataContext.

Is this 'normal' if you use MEF - or am I doing something wrong? Should I e.g. create a second constructor in the viewmodel so that I am able to set the viewmodel as data context (but then I would loose the ImportingConstructor  for the TimeModel).

I don't know if this is really a problem, it is more the feeling that I perhaps have a problem in my app strcuture which could become terrible, if I had to change it later in the project.

Any feedback from your side would be very helpful.

Thanks
Dirk

Oct 26, 2010 at 7:33 PM

Change the import in your view to as follows:

[Import(typeof(TimeTFTViewDetailViewModel))]
  public TimeTFTViewDetailViewModel TimeTFTDetailVM

get{ this.DataContext as TimeTFTViewDetailViewModel;

set{ this.DataContext = value;

}

If you don't want to do that, then consider using an Import property instead of a constructor in TimeTFTViewDetailViewModel

Oct 26, 2010 at 7:34 PM

Err, I left out the closing }'s above but you should get the jist.