Bundling ViewModel and View.cs with the View xaml

Jul 21, 2012 at 7:17 PM

I'm studying Karl Shifflett's article Prism 4 Region Navigation with Silverlight Frame Navigation and Unity, and found that he somehow bundles the view with the viewmodel along with the view.cs:

How does he do that?

The project is in SL4 Prism 4, but I'd like to have it also in SL5.

Developer
Jul 23, 2012 at 2:01 PM

Hi,

Based on my understanding, in the case you mentioned the view model is set in the view's code behind by using Unity property injection, by defining the [Dependency] attribute to its view model property, like this:

[Dependency]
public InventoryViewModel ViewModel {
get { return this.DataContext as InventoryViewModel; }
set { this.DataContext = value; }

On the other hand, the view uses the DesignInstance to Bind to Data in the Silverlight Designer, in order to provide a good design-time experience in XAML, this is mainly because the view is unaware of its DataContext's which will be assigned at run time.

You could find more information about this, in the following resources:

I hope you find this handy,

Agustin Adami
http://blogs.southworks.net/aadami

Jul 23, 2012 at 4:26 PM
Edited Jul 23, 2012 at 4:27 PM

Hi Agustin. There must be something else, because I did it and didn't get the ViewModel bundled in the explorer as in Karl's project.

Using my version of the UI Composition QuickStart, I did this with the EmployeeSummaryView:

<Grid x:Name="LayoutRoot" d:DataContext="{d:DesignInstance ViewModels:EmployeeSummaryViewModel}">

And in the corresponding .cs file:

public partial class EmployeeSummaryView : UserControl {
    public EmployeeSummaryView() {
        this.InitializeComponent();
    }

    [Dependency]
    public EmployeeSummaryViewModel ViewModel {
        get {
            return this.DataContext as EmployeeSummaryViewModel;
        }
        set {
            this.DataContext = value;
        }
    }
}

But the explorer shows this:

As you can see the ViewModel is not bundled to the View. I built the solution, even quit VS and entered again with no success.

But I run the project and it works properly.

What could I be missing here?

Developer
Jul 23, 2012 at 6:18 PM

Hi,

I believe, I have misunderstood your question. As far as I know, if what you want to do is group files in the Solution explorer, so far I'm not aware on how to achieve this directly from the Visual Studio IDE. However, based on my understanding this could be achieved by manually editing the corresponding .csproj file of the corresponding  Visual Studio project, for example with Notepad.

As an example, you could edit the ThePhoneCompany.Inventory.csproj and check how this is defined in the aforementioned solution:

<ItemGroup>
(...)
<Compile Include="Views\InventoryView.xaml.cs">
      <DependentUpon>InventoryView.xaml</DependentUpon>
    </Compile>
    <Compile Include="Views\InventoryViewModel.cs">
      <DependentUpon>InventoryView.xaml</DependentUpon>
</Compile>
(...)
Hence, you should be able to achieve this scenario by adding the following line to the files you desire to group:

<DependentUpon>YourViewFile.xaml</DependentUpon>
Note, that as this is not strictly related to Prism, perhaps you could find better guidance regarding this topic for example in the Visual Studio forums.

Regards,

Agustin Adami
http://blogs.southworks.net/aadami

Jul 23, 2012 at 7:41 PM
Edited Jul 23, 2012 at 7:47 PM

Thank you Agustin. You're answer have been very helpful.

Nevertheless, Having the Views depend on the ViewModel using the [Dependency] attribute, seems to me more elegant than placing the ViewModel as a parameter to the view.

Is there some disadvantage to this approach or they are equivalent?

Developer
Jul 23, 2012 at 9:14 PM

Hi,

I'm glad you find it useful.

Regarding your last concern, based on my understanding the main benefit of using property injection instead of constructor injection when resolving your dependencies from the container, is that this will allow you to have a parameter-less constructor which is necessary to allow the view to work with design-time tools, such as Visual Studio and Expression Blend, like shown above, in order to promote a designer friendly scenario.

On the other hand, note that when using this approach you cannot access the injected values of each property in the constructor of the class. This is because, at this time the property hasn't been instantiated.

Regards,

Agustin Adami
http://blogs.southworks.net/aadami

Jul 24, 2012 at 6:04 AM
Edited Jul 24, 2012 at 6:05 AM

Hi Agustin.

Could you give an example of the injected values I could be interested in accessing?

Developer
Jul 24, 2012 at 1:54 PM

Hi Rafael,

The value could be any dependency that you want to inject trough the container. For example the EventAggregator, RegionManager, etc...

Also, in the Advanced Construction and Wire-Up section of the Prism documentation shows how to achieve this using the constructor injection approach, and explains that you will have to maintain two constructors, as any additional constructors that you define should ensure that the default constructor is called so that the view can be properly initialized via the InitializeComponent method.

Regards,

Agustin Adami
http://blogs.southworks.net/aadami

Jul 24, 2012 at 5:58 PM

Thank you Agustin.