0

I am attempting to create a region control that does the following trick

<wgc:RegionContentControl Region="HotDog">
    <Label>Foo</Label>
    <Label>Bar</Label>
</wgc:RegionContentControl>

<wgc:RegionControl Region="HotDog">
</wgc:RegionControl>

At run time and design time the controls defined in RegionContentControl will get appended to RegionControl. I can use this to inject stuff into status bars for example.

Anyway at runtime it works fine and sometimes in the designer it work. However sometimes in the designer I get an error that

Element already has a logical parent. It must be detached from the
old parent before it is attached to the new one.

My code implementing the above pattern is below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace My.Controls
{
    public class RegionMessage {
        public enum RegionAction {
            Add,
            Remove,
        }
        public string Region { get; set; }
        public List<Control> Controls { get; set; }
        public RegionAction Action { get; set; }
    }

    public class RegionControl : ItemsControl
    {
        public RegionControl()
        {
            ReactiveUI
                .MessageBus.Current
                .Listen<RegionMessage>()
                .Subscribe(HandleRegionMessage);
        }



        public string Region
        {
            get { return (string)GetValue(RegionProperty); }
            set { SetValue(RegionProperty, value); }
        }

        public static readonly DependencyProperty RegionProperty =
            DependencyProperty.Register("Region", typeof(string), typeof(RegionControl), new PropertyMetadata(""));


        private void HandleRegionMessage(RegionMessage obj)
        {
            if (obj.Region!=Region)
            {
                return;
            }
            if (obj.Action==RegionMessage.RegionAction.Add)
            {
                foreach (var item in obj.Controls)
                {
                    this.Items.Add(item);
                }
            }
            else
            {
                foreach (var item in obj.Controls)
                {
                    this.Items.Remove(item);
                }

            }
        }
    }

    [ContentProperty("Children")]
    public class RegionContentControl : Control
    {
        static RegionContentControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(RegionContentControl), new FrameworkPropertyMetadata(typeof(RegionContentControl)));
        }

        public static readonly DependencyProperty ChildrenProperty =
       DependencyProperty.Register("Children", typeof(List<Control>), typeof(RegionContentControl), new PropertyMetadata(new List<Control>()));

        public List<Control> Children
        {
            get { return (List<Control>)GetValue(ChildrenProperty); }
            set { SetValue(ChildrenProperty, value); }
        }

        public string Region
        {
            get { return (string)GetValue(RegionProperty); }
            set { SetValue(RegionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Region.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RegionProperty =
            DependencyProperty.Register("Region", typeof(string), typeof(RegionContentControl), new PropertyMetadata(""));



        public RegionContentControl()
        {
            this.LoadedObserver().Subscribe(Loaded);
        }

        private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj)
        {
            ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage()
            {
                Action = RegionMessage.RegionAction.Add
                ,
                Controls = Children
                ,
                Region = Region
            });
        }
    }

}

I am sure that my problem involves that the controls still think they are attached to the RegionContentControl but I'm not sure how to detach them correctly. Any suggestions?

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217

1 Answers1

0

Removing the items from Children before broadcasting does the trick

    List<Control> _HiddenChildren;

    private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj)
    {
        if (_HiddenChildren==null)
        {
            _HiddenChildren = Children;
            this.Children = new List<Control>();
        }

        ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage()
            { Action = RegionMessage.RegionAction.Add
            , Controls = _HiddenChildren
            , Region = Region
            });
    }
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217