4
votes

Is it possible to use the MVVMLight ViewModelLocator on a UserControl. I have added it to my user control in the same way as is done on the MainWindow, but i get an error/popup in VS2010 stating "Cannot find resource named 'Locator'. Resource names are case sensitive."

Has anyone tried this?

Code i have thus far is pretty much a standard MVVMLight WPF starter application...

UserControl

<UserControl x:Class="NavTest3.PersonControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         Height="116" MinWidth="250" Width="300"
         DataContext="{Binding Person, Source={StaticResource Locator}}"
         >

<!---->
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Skins/MainSkin.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

App.xaml contains..

<Application.Resources>
    <!--Global View Model Locator-->
    <vm:ViewModelLocator x:Key="Locator"
                         d:IsDataSource="True" />
</Application.Resources>

so the issue is with setting "DataContext="{Binding Person, Source={StaticResource Locator}}" on the userControl."

As mentioned, doing this will mean every instance of this user control will share the same ViewModel, but I want to start with understanding this issue before moving on..

3
Posting your code would be helpful.Mike Post
can you post your locator code that pertains to this particular section?ecathell

3 Answers

4
votes

Yes you can, you need to create a static resource in your user control

<UserControl x:Class="MvvmLight1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"

             xmlns:vm="clr-namespace:MvvmLight1.ViewModel"
             >

    <UserControl.Resources>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </UserControl.Resources>
    <Grid>

    </Grid>
</UserControl>

but IMO it's not a good idea to use MVVM Light ViewModelLocator for UserControles because it is a static property and when you are going to instantiate multiple instances of your user control there are going to have the same common ViewModel so they all act same and this is not what we want for a UserControl in case you decide to use it once in your entire project.

to get around this problem you need to modify the ViewModelLocator by making all the properties Non static for instance :

 public class ViewModelLocator
    {
        //         v--- You got to comment this out
        private /*static*/ MainViewModel _main;

        public ViewModelLocator()
        {            
            CreateMain();
        }

        public /*static*/ MainViewModel MainStatic
        {
            get
            {
                if (_main == null)
                {
                    CreateMain();
                }

                return _main;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public MainViewModel Main
        {
            get
            {
                return MainStatic;
            }
        }

        public /*static*/ void ClearMain()
        {
            _main.Cleanup();
            _main = null;
        }

        public /*static*/ void CreateMain()
        {
            if (_main == null)
            {
                _main = new MainViewModel();
            }
        }

        public /*static*/ void Cleanup()
        {
            ClearMain();
        }
    }
2
votes

It may be a problem with the order in which the resources are loaded ... try assigning the DataContext of an element lower in the hierarchy, e.g. a grid underneath the user control.

<UserControl x:Class="NavTest3.PersonControl" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d" Height="116" MinWidth="250" Width="300">

    <UserControl.Resources> 
        <ResourceDictionary> 
            <ResourceDictionary.MergedDictionaries> 
                <ResourceDictionary Source="Skins/MainSkin.xaml" /> 
            </ResourceDictionary.MergedDictionaries> 
        </ResourceDictionary> 
    </UserControl.Resources>

    <Grid DataContext="{Binding Person, Source={StaticResource Locator}}">
        <!-- content -->
    </Grid>
</UserControl>

Edit:

Try using the data binding in the property section of Visual Studio to set the binding and confirm that you see the Locator. Select the element where your DataContext should go, find the DataContext property, and then click into the property value area. Now a dialog should open where you can select the locator. Possibly this solves the problem, or helps you find a soultion. Also rebuild your project prior to binding.

0
votes

Verify that you dont have an exception thrown in one of your ViewModels. Usually when I get that error the Locator can't be instantiated because there is an exception being thrown by one of the upstream Viewmodel builds. Can you post your Locator constructor?

if you want to trouble shoot this yourself, put a break point on your first CreateVM statement in the VMLocator and see which VM is throwing the exception.