MVVM, Confused about ViewModelLocator and DataTemp

2020-08-01 04:34发布

问题:

I use MVVMLight and it comes with a ViewModelLocator.

My initial project posed the following problem. I have a MainView that is rendered upon stating up the app. Depending on buttons clicked it renders either View1 or View2 (each are user controls) via ContentControl inside my MainView.

I locate the correct view model in my MainViewModel. But I found that I also need a DataTemplate so that the usercontrols within View1 and View2 will be correctly rendered in MainView, else it would only show the text based name of the classes.

I am confused about the following:

a) Do I need both, a view model locator and a DataTemplate to accomplish the above? I just jumped into WPF but thought I read that one or the other is required not both. Or more specific: Why do I have DataContext="{Binding LiveDataViewModel, Source={StaticResource Locator}}"> in my View (which resolves the binding to its own view model) but still need a DataTemplate?

b) Is this a view model first approach or a view first approach?

c) I tried a code behind solution and it literally took me 4 lines of code to accomplish the exact same thing that took me many classes, detours, eventToCommand & converters [because the control that triggers the choice of view only raises events not commands], data templates, view model locators, different view models...this looks like a huge cost to pay for no advantage whatsoever. Putting this into code behind seems to me perfectly fine because it is pure UI content (choose view and bind to content control, done). Am I missing something here? What would I give up via code behind?

I am new to WPF and MVVM and right now I am just extremely frustrated because it feels like I am running circles around a seemingly trivial issue.

回答1:

I'm sorry if this answer sounds basic, but it sounds like you may still be learning WPF and misunderstanding a few key things.

First off, there are two layers to a WPF application:

  • a UI layer consisting of the objects you see rendered on the screen
  • and the data layer that sits behind the UI, called the DataContext

When you do a binding, you are pulling data from the data layer and placing it in the UI layer.

The ViewModelLocator affects the data layer. It is used to find an appropriate data object to place behind a UI object.

Now in cases where the data object is inserted directly into the UI layer, such as anything with a .Content or .ItemsSource property bound directly to it's data layer, the default way WPF will render the data object is to use a TextBlock displaying the .ToString() of the object.

You can override this and tell WPF how to draw any type of object using a DataTemplate though. You can either tell a control to render using a specific template, or you can tell WPF to automatically render any object in the UI layer of type X using a specific DataTemplate.

So to answer your questions

a) Do I need both, a view model locator and a DataTemplate to accomplish the above? Or more specific: Why do I have DataContext="{Binding LiveDataViewModel, Source={StaticResource Locator}}"> in my View but still need a DataTemplate?

These are two separate items. The ViewModelLocator locates the data item behind the UI object, and the DataTemplate tells WPF how to draw that item.

Your binding is saying "bind the data layer (DataContext) to Locator.LiveDataViewModel", and my best guess is something in your XAML binds either ItemsSource or Content directly to the data layer, using XAML like Content="{Binding }"

b) Is this a view model first approach or a view first approach?

I think anytime you use a ViewModelLocator it is a view-first approach because the View is responsible for obtaining it's data item from the Locator. The data does not exist until after the View calls it.

Personally I never use a ViewModelLocator since I don't like the restrictions it has, and prefer a model-first approach, but that doesn't mean you can't use one if you want.

c) I tried a code behind solution and it literally took me 4 lines of code to accomplish the exact same thing that took me many classes, detours, eventToCommand & converters [because the control that triggers the choice of view only raises events not commands], data templates, view model locators, different view models...this looks like a huge cost to pay for no advantage whatsoever. Putting this into code behind seems to me perfectly fine because it is pure UI content (choose view and bind to content control, done). Am I missing something here? What would I give up via code behind?

I have no idea what your code looks like, however that sounds like there is a lot of unnecessary code in it. The idea behind the MVVM pattern is to have all your application logic reside in your classes, and all your user-interface logic reside in the UI controls. WPF is well suited to this design because of its binding system.

This makes it easy to hook up alternate user-interfaces to your application, with the most common one being test scripts. It also has the advantage of keeping the UI completely separate from business logic, which is a huge help when working with a dedicated UI team.

Personally I use MVVM for every WPF application, even really simple ones. I might blur the rules a bit in simple applications, but I could never go back to the old WinForms style of building applications when the MVVM option exists.

If you're interested, I've written a few blog articles for WPF beginners that you may find useful if you're first starting out :

  • Understanding the change in mindset when switching from WinForms to WPF
  • What is this "DataContext" you speak of?
  • A Simple MVVM Example

Hope this helps, and good luck :)