Do views inserted into regions have their own view model?

Jul 31, 2012 at 8:41 PM
Edited Jul 31, 2012 at 8:44 PM

I am trying out a screen where I have a couple of regions. When I load a view into the region, should it be creating an instance of its view model, or does the view rely on the view model of the regions' parent page?

I don't seem to get a view model for the view in the region, so I'm not sure if I am misunderstanding the way regions work or I haven't wired up the relationships properly.

 

Aug 1, 2012 at 3:24 AM

You could do it either way but normally a view which is loaded into a region would have its own view model.  How are you wiring up the view and view model?  A simple view's code behind would be something like

using System.ComponentModel.Composition;
using Jounce.Core.View;
using Jounce.Core.ViewModel;
using Jounce.Regions.Core;

[ExportAsView(Constants.PartyControlView, DeactivateOnUnload=true)]
[ExportViewToRegion(Constants.PartyControlView, Constants.MainControlRegion)]
public partial class PartyControl
{
    public PartyControl()
    {
        InitializeComponent();
    }

[Export]
public ViewModelRoute Binding { get { return ViewModelRoute.Create(typeof(PartyControlViewModel).FullName, Constants.PartyControlView); } }
}

You can also create the binding using the fluent interface.  The corresponding view model would be

using Jounce.Core.ViewModel;

[ExportAsViewModel(typeof(PartyControlViewModel))]
public class PartyControlViewModel : BaseViewModel
{
}
Aug 1, 2012 at 11:25 AM

Thanks for looking at this Paul, I have all this wiring in place, but I must be missing something else.

I have a property on my model

public string ScreenInfo
        {
            get
            {
                if (InDesigner)
                    return "xxxxx";
                return DateTime.Now.ToString();
            }
        }

 

which I have wired into my view via a textbox with

Text="{Binding ScreenInfo}" 

I see the xxxxx value in the design view, but when I run the app, I see the view in the region, but not the date in the text box.

In the debug window I get an error, which suggests it's looking for my property on the host page. So I'm a bit confused as to why it resolves at design time but not at runtime.

System.Windows.Data Error: BindingExpression path error: 'ScreenInfo' property not found on 'ViewModel: MainViewModel' 'Eks2.ViewModels.MainViewModel' (HashCode=24981566). BindingExpression: Path='ScreenInfo' DataItem='ViewModel: MainViewModel' (HashCode=24981566); target element is 'System.Windows.Controls.TextBox' (Name='textBox1'); target property is 'Text' (type 'System.String')..

 

Aug 1, 2012 at 12:37 PM

Design time wiring is different from runtime, so it is not a surprise to get one right and not the other.  I had this problem a couple of days ago and it took me sometime to discover that I had done a bad job with copy and paste of my Binding.  Can you post your binding statement?

Aug 1, 2012 at 4:42 PM

My screen is dead simple:

 

<UserControl x:Class="Eks2.Views.Screen1"
  
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"
  
mc:Ignorable="d"
  
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
            
xmlns:ViewModels="clr-namespace:Eks2.ViewModels">
  
  
<Grid x:Name="LayoutRoot" Background="White" d:DataContext="{d:DesignInstance ViewModels:Screen1ViewModel, IsDesignTimeCreatable=True}">
      
<sdk:Label Height="40" HorizontalAlignment="Left" Margin="68,40,0,0" Name="label1" VerticalAlignment="Top" Width="297" Content="Screen1" />
      
<TextBox Height="23" HorizontalAlignment="Left" Margin="74,124,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding ScreenInfo}" />
  
</Grid>
</UserControl>

Aug 1, 2012 at 9:51 PM

The view you posted shows that you have bound a design-time viewmodel (d:DataContext="{d:DesignInstance ...}") but have you done it for runtime?  See my previous example of the code behind exporting a ViewModelRoute.  You can also do it with the fluent router.

Aug 1, 2012 at 9:58 PM

Yes, I have set up Binding on the view....

	[Export]
        public ViewModelRoute Binding
        {
            get { return ViewModelRoute.Create<Screen1ViewModelScreen1>(); }
        }

 

Aug 1, 2012 at 10:03 PM
Edited Aug 1, 2012 at 10:03 PM

Ah, I have just used the version of ViewModelRoute.Create that you posted above, rather then the generic typed version I was using and voila, I'm getting wired up! Thanks for your help on this.

Aug 1, 2012 at 10:10 PM

That's good, but a little strange.  I didn't realise that I had posted the non-generic version of Create, I just copy/pasted some of my own code without checking (my bad).  Normally I use the version that you posted

[Export]
public ViewModelRoute Binding
{
  get { return ViewModelRoute.Create<DayEventViewModel,DayEventView>();}
}

I only use the non-genric version when the view needs to be invoked from outside the xap. 


Aug 1, 2012 at 10:31 PM

Umm, the non-generic way you do it does seem to be the way Jeremy does it in the sample apps. I can't see what I might have been missing.