DependencyProperty getter/setter not being called

I would suggest not to use ObservableCollection as the type of an Items dependency property.

The reason for having an ObservableCollection here (I guess) is to enable the UserControl to attach a CollectionChanged handler when the property value is assigned. But ObservableCollection is too specific.

The approach in WPF (e.g. in ItemsControl.ItemsSource) is to define a very basic interface type (like IEnumerable) and when the property is assigned a value, find out if the value collection implements certain more specific interfaces. This would at least be INotifyCollectionChanged here, but the collection might also implement ICollectionView and INotifyPropertyChanged. All these interfaces wouldn't be mandatory and that would enable your dependency property to bind to all sorts of collections, starting with a plain array up to a complex ItemCollection.

Your OnItemsChanged property change callback would then look like this:

private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    MyGrid grid = obj as MyGrid;

    if (grid != null)
    {
        var oldCollectionChanged = e.OldValue as INotifyCollectionChanged;
        var newCollectionChanged = e.NewValue as INotifyCollectionChanged;

        if (oldCollectionChanged != null)
        {
            oldCollectionChanged.CollectionChanged -= grid.OnItemsCollectionChanged;
        }

        if (newCollectionChanged != null)
        {
            newCollectionChanged.CollectionChanged += grid.OnItemsCollectionChanged;

            // in addition to adding a CollectionChanged handler
            // any already existing collection elements should be processed here
        }
    }
}

private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // handle collection changes here
}

The WPF binding mechanism may bypass your standard CLR property and go directly to the dependency property accessors (GetValue and SetValue).

That is why logic should not be placed inside of the CLR property, but instead inside a changed handler.

Also the ObservableCollection<string> will never be set because when you use collection properties from XAML, like the following:

<local:MyGrid>
    <local:MyGrid.Items>
        <sys:String>First Item</sys:String>
        <sys:String>Second Item</sys:String>
    </local:MyGrid.Items>
</local:MyGrid>

It is actually calling a get on Items and then calling Add for each of the elements.