0

I assign a datacontext to a CustomControl using this XAML:

 <Setter Property="DataContext" Value="{Binding TimeUnitGridViewModel, Mode=OneWay, Source={StaticResource Locator}}" />

This works as expected. The 'Locator' is an MVVMlight ViewModelLocator declared in the resources for the file.

How would I rewrite this XAML to allow for passing a parameter into the constructor of the ViewModel? I should be able to use property injection but I've no idea on the syntax.

EDIT:

This is the code I use in the ViewModelLocator:

        public TimeUnitGridViewModel TimeUnitGridViewModel

    {
        get
        {
            return ServiceLocator.Current.GetInstance<TimeUnitGridViewModel>(Guid.NewGuid().ToString());
        }
    }
jidl
  • 195
  • 1
  • 2
  • 19
  • 1
    I'm not sure about this approach. My (surely soon to be corrected) understanding is that your binding has to be done against a pre-existing object. You can't call things (i.e. a ViewModel) into being with a binding. Might it be a better idea to use an eventtrigger on a Loaded event on your View somewhere? The trigger fires a ViewModel method which instantiates TimeUnitGridViewModel with your parameter. – goobering Apr 02 '15 at 10:18
  • Hmmm. You've got me wondering why it _does_ work now. I use this in the viewmodel locator: ' public TimeUnitGridViewModel TimeUnitGridViewModel { get { return ServiceLocator.Current.GetInstance(Guid.NewGuid().ToString()); } }' – jidl Apr 02 '15 at 13:34
  • The first binding will work just fine because the ViewModelLocator has already created an instance of TimeUnitGridViewModel. Subsequent bindings to that ViewModel will reference *the same instance*. It is possible to create multiple instances of that ViewModel, but it complicates matters a little (see LBugnion's answer: http://stackoverflow.com/questions/2830517/how-to-have-multiple-pairs-view-viewmodel/2848084#2848084). What's the parameter you're trying to pass in, and what does it do? – goobering Apr 02 '15 at 14:06
  • I have the need to use the same view / viewmodel in two places at once - one representing a plan and one representing the actual. I want to avoid coding the same object twice so I thought I'd pass an enum in designating *plan* or *actual* so that when I register messages the _other_ instance doesn't act on them. – jidl Apr 02 '15 at 14:12
  • Looks like the referenced question in my previous comment is the answer then. You can implement a Dictionary of TimeUnitGridViewModels in your ViewModelLocator and reference each instance using a key. That approach will mean that each instance is created by the ViewModelLocator and should be available for binding. – goobering Apr 02 '15 at 14:21
  • 1
    @goobering, just a side note: "You can't call things into being with a binding." -> Yes, you can, using an ObjectDataProvider. It even has a ConstructorParameters property. But that is beside the point. Here, I am a little scared by the idea of an enum flag for the two different view models. How about two subclasses of a base view model? – Robin Apr 02 '15 at 18:54
  • Every day's a school day/I stand corrected! It's highly dependent on the requirements for your two views, but there is also the possibility of just shifting everything into one ViewModel bound to two Views and replace single instances with ObservableCollections. – goobering Apr 02 '15 at 19:48
  • @Robin, I had seen the ObjectDataProvider approach but couldn't work out how the syntax would work with a ControlTemplate / CustomControl. Do you have any ideas? – jidl Apr 02 '15 at 20:06

1 Answers1

-1

The ObjectDataProvider can be defined as a windows resource, maybe like this:

<Window.Resources>
  <ObjectDataProvider x:Key="myProvider" ObjectType="{x: Type TimeUnitGridViewModel}" MethodName="GetMyself">
  <ObjectDataProvider.ConstructorParameters>
    <system:String>some parameter, or your enum instead...</system:String>
  </ObjectDataProvider.ConstructorParameters>
</Window.Resources>

The method GetMyself just contains return this; Then, your binding would be:

<Setter Property="DataContext" Value="{Binding Source={StaticResource myProvider}}" />

But once again, this "view model" of yours then is not really a view model as in MVVM. Also, you can only do one-way binding like this, you cannot update the view model from the view through an ObjectDataProvider!

Therefore, I would recommend again to have a base view model class and derive PlanTimeUnitGridViewModel and ActualTimeUnitGridViewModel from it. Like this, you have no redundancy in the code, and you can use the two view models as they should be in the MVVM pattern.

Robin
  • 518
  • 3
  • 13