Search code examples
avaloniauiavalonia

Where and how do the ViewLocator-generated Views get their DataContexts assigned (in Avalonia's Todo tutorial application)?


In the completed Avalonia tutorial Todo application --- where and how do TodoListView and AddItemView acquire their DataContexts to be equal to TodoListViewModel and AddItemViewModel respectively ???
I mean their parent control MainWindow's DataContext is a MainWindowViewModel instance (as assigned in App.xaml.cs file) --- while MainWindow's Content attribute is bound to MainWindowViewModel's Content property (which does get assigned instances of the viewmodels during execution). I just cannot trace the source wherefrom TodoListView and AddItemView acquire their DataContexts. Do they get it while:

  1. Being created by the ViewLocator at runtime ? -- but that's not possible as the DataContext property of the newly instantiated View is still NULL just before the ViewLocator returns the View instance -- as shown by the output of following code in the completed application (the code in the if block is modified by me to produce required output):
public IControl Build(object data)
        {
            var name = data.GetType().FullName.Replace("ViewModel", "View");
            var type = Type.GetType(name);

            if (type != null)
            {
                var viewInstance = (Control)Activator.CreateInstance(type);
                
                // the following always evaluates to true --- i.e. DataContext is always NULL before viewInstance is returned.
                if(viewInstance.DataContext == null)   
Console.WriteLine($"DataContext property of the newly created View instance of {name} in ViewLocator is NULL just before returning! ");


                 
                return  viewInstance ;
            }
            else
            {
                return new TextBlock { Text = "Not Found: " + name };
            }
        }
  1. OR they get their DataContext assigned by the parent Window ? --- but the parent window's own DataContext is MainWindowViewModel ----- how do we get to TodoListViewModel or AddItemViewModel from MainWindowViewModel ???

In short , I am unclear about where the Views generated at runtime via ViewLocator are getting their DataContext properties assigned.


Summarizing what I understood from the answer and some search and play:


If a ContentControl's (in this case Window's) Content property is a Control then the Control simply inherits the DataContext from the parent ContentControl. But if the ContentControl's Content property is a non-Control then the ContentPresenter of the ContentControl first finds a data template for the non-Control so that a child View can be generated and then sets its own DataContext to the non-Control. This newly assigned DataContext then gets inherited by the newly generated child View. Phewwwwww!


Solution

  • DataContext is inherited from ContentPresenter which is asking IDataTemplate.Build for a new view instance. When Content isn't a control, ContentPresenter sets its own DataContext to the value of Content which gets inherited by the child view.

    ContentPresenter is used internally by the Window to display its Content property.

    Same happens with ListBox items.