0

I'm learning WPF and MVVM, and am working through this example here: https://www.tutorialspoint.com/mvvm/mvvm_wpf_data_templates.htm. So far it seems that the layers are joined together by a kind of magic glue, the aim being to make each layer to be a declaratory as possible, as agnostic as possible, not knowing about the other layers and letting the glue do the bonding.

It's just introduced the concept of ViewModelLocators, which makes sense. However, there are a few bits that I'm confused by.

In the View we have this

<UserControl x:Class="MVVMDemo.Views.StudentView"
             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" 
             xmlns:local="clr-namespace:MVVMDemo.Views"
             xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModels"
             xmlns:vml = "clr-namespace:MVVMDemo.VML" 
             vml:ViewModelLocator.AutoHookedUpViewModel = "True" 
             mc:Ignorable="d" 
             d:DesignHeight = "300" d:DesignWidth = "300">
    
    <Grid>
        <StackPanel HorizontalAlignment = "Left">
            <ItemsControl ItemsSource = "{Binding Path = Students}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation = "Horizontal">
                            <TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}" Width = "100" Margin = "3 5 3 5"/>
                            <TextBox Text = "{Binding Path = LastName, Mode = TwoWay}" Width = "100" Margin = "0 5 3 5"/>
                            <TextBlock Text = "{Binding Path = FullName, Mode = OneWay}" Margin = "0 5 3 5"/>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Grid>
</UserControl>

The VML is declared thus:

namespace MVVMDemo.VML
{
    public static class ViewModelLocator
    {
        public static bool GetAutoHookedUpViewModel(DependencyObject obj)
        {
            return (bool)obj.GetValue(AutoHookedUpViewModelProperty);
        }

        public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value)
        {
            obj.SetValue(AutoHookedUpViewModelProperty, value);
        }

        // Using a DependencyProperty as the backing store for AutoHookedUpViewModel. 
        //This enables animation, styling, binding, etc...

        public static readonly DependencyProperty AutoHookedUpViewModelProperty = DependencyProperty.RegisterAttached("AutoHookedUpViewModel", typeof(bool), typeof(ViewModelLocator), new PropertyMetadata(false, AutoHookedUpViewModelChanged));

        private static void AutoHookedUpViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (DesignerProperties.GetIsInDesignMode(d)) return;

            // this basically does string substitution to derive the ViewModel for the specified View. It replaces ".Views." with ".ViewModels" and tacks "Model" on the end, then sets that to be the DataContext of d (the DependencyObject)
            var viewType = d.GetType();
            string str = viewType.FullName;                             // e.g. "MVVMDemo.Views.StudentView"
            str = str.Replace(".Views.", ".ViewModels.");               // e.g. "MVVMDemo.ViewModels.StudentView"

            var viewTypeName = str;
            var viewModelTypeName = viewTypeName + "Model";             // e.g. "MVVMDemo.ViewModels.StudentViewModel"
            var viewModelType = Type.GetType(viewModelTypeName);
            var viewModel = Activator.CreateInstance(viewModelType);
            ((FrameworkElement)d).DataContext = viewModel;
        }

    }
}

My question is, what is this line:

vml:ViewModelLocator.AutoHookedUpViewModel = "True" 

actually doing. Does it get executed? ViewModelLocator has no method or property AutoHookedUpViewModel. It has methods GetAutoHookedUpViewModel and SetAutoHookedUpViewModel. Putting breakpoints on these two methods show that they are not called. What is the magic glue doing here and how does it work? What code actually gets called and when?

Secondary bonus questions:

In the XML properties of the UserControl tag, we have this:

             xmlns:vml = "clr-namespace:MVVMDemo.VML" 
             vml:ViewModelLocator.AutoHookedUpViewModel = "True" 

Why can't I just put this:

             clr-namespace:MVVMDemo.VML.ViewModelLocator.AutoHookedUpViewModel = "True" 

or just:

             MVVMDemo.VML.ViewModelLocator.AutoHookedUpViewModel = "True" 

Why do I have to make an XML namespace that points to an assembly namespace and not just specify the full assembly namespace directly?

Any help gratefully received. I feel a little swamped by magic glue.

Mark Roworth
  • 409
  • 2
  • 15
  • It is an [attached property](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/attached-properties-overview?view=netdesktop-6.0) that is set to `true`. Your breakpoint is not hit because the framework directly calls `DependencyObject.SetValue` when the property is set in XAML. – Clemens Oct 14 '22 at 11:04
  • The AutoHookedUpViewModelChanged callback should however be called. – Clemens Oct 14 '22 at 11:10
  • @Clemens - do the methods that fulfill the property always have to be of the form Get and Set. If not, how does it know? – Mark Roworth Oct 14 '22 at 11:20
  • For attached properties, yes. Please read the documentation linked in my first comment. – Clemens Oct 14 '22 at 11:22
  • @Clemens - working on it. Thank you. – Mark Roworth Oct 14 '22 at 11:36

0 Answers0