views:

89

answers:

1

I'm trying to write a ParentAdapter implementation; I'm interested in providing design-time support for some WPF controls I'm writing and this is how you manage custom logic for reparenting items to different container controls. I started small, with the notion of creating a StackPanel-derived class that would only allow Button elements to be parented at design-time (yes, I'm aware the panel itself needs code to support this as well.) I started with what I figured would be the simplest the ParentAdapter could be:

using System;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Windows.Design.Interaction;
using Microsoft.Windows.Design.Model;

namespace ControlLibrary.Design
{
    internal class SimplePanelParentAdapter : ParentAdapter
    {
        public override bool CanParent(ModelItem parent, Type childType)
        {
            return (childType == typeof(Button));
        }

        // moves the child item into the target panel; in this case a SimplePanel
        public override void Parent(ModelItem newParent, ModelItem child)
        {
            using (ModelEditingScope undoContext = newParent.BeginEdit())
            {
                // is this correct?
                //child.Content.SetValue("I'm in a custom panel!");
                SimplePanel pnl = newParent.GetCurrentValue() as SimplePanel;
                pnl.Children.Add(child.GetCurrentValue() as UIElement);                
                undoContext.Complete();
            }

        }

        public override void RemoveParent(ModelItem currentParent, ModelItem newParent, ModelItem child)
        {
            // No special things need to be done, right?
            child.Content.SetValue("I was in a custom panel.");
        }
    }
}

When I work with this at design-time, as soon as I drag a button over my custom panel, a NullReferenceException is thrown from deep within the VS code. My code is not throwing the exception, because I can step all the way through my method; the call stack indicates that code in Microsoft.Windows.Design.Developer.dll is throwing the exception.

Obviously I'm doing something incorrectly, but the documentation provides no examples and my search-fu seems to indicate that either no one is trying this or anyone who is trying it isn't talking about it. Does anyone have suggestions?

A: 

I found the answer to my question myself. The problem is caused by editing the model instead of the ModelItem wrapper. What I should have done (and does work) is something like this:

using System;
using System.Windows.Controls;
using Microsoft.Windows.Design.Interaction;
using Microsoft.Windows.Design.Model;

namespace ControlLibrary.Design
{
    internal class SimplePanelParentAdapter : ParentAdapter
    {
        public override bool CanParent(ModelItem parent, Type childType)
        {
            return (childType == typeof(Button));
        }

        // moves the child item into the target panel; in this case a SimplePanel
        public override void Parent(ModelItem newParent, ModelItem child)
        {
            using (ModelEditingScope undoContext = newParent.BeginEdit())
            {
                ModelProperty prop = newParent.Properties["Children"];
                ModelItemCollection items = (ModelItemCollection)prop.Value;
                items.Add(child);

                undoContext.Complete();
            }

        }

        public override void RemoveParent(ModelItem currentParent, ModelItem newParent, ModelItem child)
        {
            using (ModelEditingScope scope = child.BeginEdit())
            {
                ModelProperty prop = currentParent.Properties["Children"];
                ((ModelItemCollection)prop.Value).Remove(child);

                scope.Complete();
            }
        }
    }
}

I was confused when I wrote the first code and unsure how I was supposed to call Add() on the Children property; it looks like ModelProperty.Value wraps collections with ModelItemCollection, so unless you go out of your way to make your class use an obtuse interface this should work.

OwenP