DataContext in Views and UserControls; not working as expected

Topics: Questions
Mar 11, 2013 at 3:00 PM
I have just started with Catel and am confused on how DataContext gets set etc.
I am trying to create a common UserControl and use it in several windows. That control has a ViewModel as recommended. When the control is created (from the XAML in the containing window), the DataContext is null.

I turned on Catel logging and I see a log entry that indicates that the DataContext for the user control view is set to the ViewModel of the containing page, yet when the data of a bound property is retrieved, it is retrieved from the ViewModel of the user control.

What is worse, is that UserControl.DataContext is null.

Please guide me though this as it is obvious, I have missed some very basic part.

Thanks
Coordinator
Mar 11, 2013 at 3:02 PM
Please upload a repro. There can be many things wrong, such as:

1) Does the VM has an empty constructor?
2) Can the VM be resolved?
Mar 11, 2013 at 3:12 PM
Geert,
Thanks for the quick reply. Yes, the UserControl's VM has a parmeterless constructor. There is current a line of code in it to set a property, but I had the same result without it. Yes, the VM is resolved. The debug traces show it being created.

My repro is probably too big. We are stuck with Telerik, so I created my own version of DataWindow that derives from RadWindow. and implimented IDataWindow. I also I have created my own ViewModel base class that derives from yours.

I know you are busy, but I was hoping for a discussion on how the DataContext is set/managed with Catel. I have read every article I can find with the words Catel and DataContext in them and nothing gives me a roadmap as to how it works.

If you believe the repro is the best path, I will try to recreate without my base classes etc. Please advise.

Thanks
Coordinator
Mar 11, 2013 at 5:08 PM
Mar 11, 2013 at 5:12 PM
Yes
First link 6 times.
Second link 1 time.
Third link 3 times.
Coordinator
Mar 11, 2013 at 5:16 PM
Then I will be needing an example. Sorry for the overhead, but I need a good way to reproduce this if the behavior is not as expected.
Mar 11, 2013 at 7:05 PM
I have uploaded a repro named CatelRepro to my SkyDrive at https://skydrive.live.com/#cid=F308DB222B13E73F&id=F308DB222B13E73F%21107

This repro proves that I am confused. It works in that the UserControl pulls data from its ViewModel, yet I see to following things that confuse me.
1) - The DataContext on both views (MainPage and UserControl1View) remain null.
2) - The Debug trace says, "LOG: 02:53:32:536 => [DEBUG] [Catel.Windows.Controls.MVVMProviders.Logic.LogicBase] DataContext of TargetControl 'UserControl1View' has changed to 'MainPageViewModel'", yet databind works and pulls the data from the UserControl1ViewModel.

Please help me understand what is happening.
Also, I will have UserControls that I will need their DataContext pointing to the same DataContext as the parent window. I will need to know how to make that work too.

Thanks
Coordinator
Mar 11, 2013 at 8:42 PM
The DataContext is set, just override the OnViewModelChanged in any view and you will see that it is set to the right value (but you have to let catel do its work).

I had to fix the follwing:

1) ok command in the MainPageViewModel
2) NewWindow must derive from a window (changed it to catel:DataWindow)

Then it all works like a charm.
Mar 12, 2013 at 11:19 AM
Geert,
The OK command was a left over from the bigger project.

Yes, it works, but the question is how/why? Yes, I did the override as suggested in UserControl1View and see that the ViewModel changes. However, if I look a the DataContext property for that view before and after calling the base.OnViewModelChanged, the DataContext is still pointint to the MainPageViewModel as indicated in the diagnostic trace.

How does data binding end up with values from UserContro1ViewModel when that ViewModel is NOT the target of the DataContext?

Note. All of this discussion is relative to the UserControl1View in the MainPage not the one in the NewWindow.

Thank you for you continued assistance?
Coordinator
Mar 12, 2013 at 4:32 PM
So your question is actually: how does it work under the hood? Or are there actually problems?

We are actively updating our documentation, but remember this is all for free (we don't get money for writing docs), so please be patient while we write it. I will create a special sections about the inner workings.
Mar 12, 2013 at 4:46 PM
Yes, my question is how. As I said, the results are there but they go against everything that I know about databinding.

The reason that I care is as follows. (Maybe you can tell me how to do what I want.)

I want to create some common controls such as a OKCancelPanel (which has an OK button and a Cancel button). The content of the buttons could be changed by binding and the CanExecute/Execute would eventually execute against the ViewModel of the containing View. In otherwords, common code and common layout. So instead of the control needing its on ViewModel, it really needs to share the ViewModel of the containing control or window. I have other controls like this that I want also, so it is not as simple as using your DataWindow with the built in OK/Cancel buttons.

I sincerely appreaciate that this execelent framework is free. I reviewed 5 or 6 MVVM frameworks before choosing yours. I believe that yours is the most complex under the hood and the most complete (with the exeception of Microsoft Prism/MEF etc.). I just need to learn how to use it to its fullest.

To paraphrase, I am trying to learn how to fish instead of simply eating the fish you give me.

Thanks
Coordinator
Mar 12, 2013 at 4:53 PM
In that case, just make the "OkCancelPanel" a normal control. This way, it can do something like this:

[ PAGE ]
== Real page DataContext
-- InnerGrid with DataContext as ViewModel
So, the inner grid (which is created under the hood) contains the actual VM as datacontext. This is how the translation is done from the parent DataContext => ViewModel per control.

If you have a page with a VM, and you want it to respond to the Page OK / Cancel stuff, just create a "regular" UserControl. Then it will inherit the DataContext from the parent (which is the VM of the Page) and then you can use it like you intended.

I hope this clears some things up.
Mar 14, 2013 at 1:39 PM
Got distracted yesterday. Back on this today.

Ok, 'regular' UserControl makes sense to me. I thought that might be the correct answer. Thanks.
Question.
For any bindable properties in my 'regular' control. Should I use normal property registration or Catel property registration?
Coordinator
Mar 14, 2013 at 1:57 PM
If you want them updatable, they should support INotifyPropertyChanged. The Catel properties do this for you. Note that this is only required if you want to reflect changes from the VM to the View. I always recommend to use Catel properties because otherwise you might forget it on some and then you have a mixed mess.
Coordinator
Mar 23, 2013 at 12:04 PM
FYI, I have documented a bit about how Catel handles the DataContext and view models under the hood.

See https://catelproject.atlassian.net/wiki/display/CTL/UserControl+-+under+the+hood
Mar 25, 2013 at 11:22 AM
Thank you for taking time to add this documentation. It helps.