Проверьте, является ли указанный элемент уже логическим дочерним элементом другого элемента

Я новичок в C# и WPF. Я программирую плагин для основанного на узле программного обеспечения под названием vvvv. Я реализовал ползунки, кнопки и другие простые элементы интерфейса. Следующий код показывает, как выглядит узел ползунков в C#:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Xml;
using VVVV.PluginInterfaces.V2;

namespace VVVV.Packs.UI.Nodes.WPF
{
    [PluginInfo(Author = "lecloneur", Category = "WPF", Help = "WPF Slider", Name = "Slider", AutoEvaluate = false)]

    public class WPFSlider : GenericNode, IPluginEvaluate
    {
        [Input("SizeX", DefaultValue = 120, Order = 9, MinValue = 0)]
        public IDiffSpread<int> SizeX;

        [Input("SizeY", DefaultValue = 120, Order = 9, MinValue = 0)]
        public IDiffSpread<int> SizeY;

        [Input("Orientation", Order = 1, DefaultEnumEntry = "Horizontal")]
        public IDiffSpread<Orientation> OrientationIn;

        [Output("Value", Order = 2)]
        public ISpread<double> ValueOut;

        int elements_count = 0;

        public void Evaluate(int SpreadMax)
        {
            UIElementOut.SliceCount = SpreadMax;
            ValueOut.SliceCount = SpreadMax;
            for (int i = 0; i < SpreadMax; i++)
            {
                if (UIElementOut == null || !(UIElementOut[0] is Slider) || elements_count < SpreadMax || OrientationIn.IsChanged || SizeX.IsChanged || SizeY.IsChanged)
                {
                    CreateElement(i);
                }
                OutputData(i);
                Transformation(i, (Slider)UIElementOut[i]);
            }
            elements_count = SpreadMax;
        }

        private void CreateElement(int i)
        {
            UIElementOut[i] = new Slider();
            var uiElement = (Slider)UIElementOut[i];
            uiElement.Minimum = 0;
            uiElement.Maximum = 1;
            uiElement.Orientation = OrientationIn[i];
            uiElement.IsMoveToPointEnabled = true;
            uiElement.Width = SizeX[i]; ;
            uiElement.Height = SizeY[i];
            uiElement.VerticalAlignment = VerticalAlignment.Center;
            uiElement.HorizontalAlignment = HorizontalAlignment.Center;

            XmlReader XmlRead = XmlReader.Create("Styles/SliderStyle.xaml");
            ResourceDictionary myResourceDictionary = (ResourceDictionary)XamlReader.Load(XmlRead);
            XmlRead.Close();
            Style uiElementStyle = myResourceDictionary["SliderStyle"] as Style;
            uiElement.Style = uiElementStyle;
        }

        private void OutputData(int i)
        {
            var uiElement = (Slider)UIElementOut[i];
            ValueOut[i] = uiElement.Value;
        }
    } 
}

Сейчас я пытаюсь реализовать tabcontrol, где я мог бы динамически создавать tabitem и вводить в него UIElement. Насколько я понимаю, я могу добавить только одну вещь в табитем. Поэтому я думал о создании сетки каждый раз, когда мне нужно, и заполняю ее всем входящим элементом UIElement.

    public void Evaluate(int SpreadMax)
    {
        SpreadMax = 1;

        UIElementOut.SliceCount = 1;

        for (var i = 0; i < SpreadMax; i++)
        {
            if (UIElementOut == null || !(UIElementOut[i] is TabControl))
                UIElementOut[i] = new TabControl();
                var uiElement = (TabControl)UIElementOut[i];
                uiElement.Height = 200;
                uiElement.Width = 500;
        }



        Grid grid;

        int[] _elementCounts = new int[_elementInputs.SliceCount];

        for (var i = 0; i < _elementInputs.SliceCount; i++)
        {
            if (_elementInputs[i] == null || !(_elementInputs[i] is UIElement))
            {
                grid = new Grid();

                for (var j = 0; j < _elementInputs[i].IOObject.SliceCount; j++)
                {
                    if (_elementInputs[i].IOObject[j] != null)
                    {
                        UIElement test = new UIElement();
                        test = _elementInputs[i].IOObject[j];
                        grid.Children.Add(test);
                    }
                }
                _elementCounts[i] = _elementInputs[i].IOObject.SliceCount;
                ValueOut[i] = _elementCounts[i];


                if (((TabControl)UIElementOut[0]).Items.Count <= i)
                {
                    ((TabControl)UIElementOut[0]).Items.Add(new TabItem { Header = _nameInputs[i].IOObject[0], Content = grid });
                }

                if (_nameInputs[i].IOObject.IsChanged)
                {
                    ((TabItem)((TabControl)UIElementOut[0]).Items[i]).Header = _nameInputs[i].IOObject[0];
                }

                if (_elementInputs[i].IOObject.IsChanged)
                {
                    ((TabItem)((TabControl)UIElementOut[0]).Items[i]).Content = grid;
                }
            }
        }

        for (var i = ((TabControl)UIElementOut[0]).Items.Count - 1; ((TabControl)UIElementOut[0]).Items.Count > _elementInputs.SliceCount; i--)
        {
            ((TabControl)UIElementOut[0]).Items.RemoveAt(i);
        }
    }

Я много искал, но не могу найти идеи, как решить эту ошибку. Очевидно, добавление элементов в бросок сетки "указанный элемент уже является логическим дочерним элементом другого элемента";

1 ответ

Здравствуйте, попробуйте следующий метод на нескольких визуальных объектах (дочерних) и проверьте, является ли полученный объект той же ссылкой. Вот полезная ссылка с объяснениями и многое другое...

Код класса расширения:

public static class VisualTreeHelperExtensions
{
    public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
    {
        while (true)
        {
            //get parent item
            DependencyObject parentObject = VisualTreeHelper.GetParent(child);

            //we've reached the end of the tree
            if (parentObject == null) return null;

            //check if the parent matches the type we're looking for
            T parent = parentObject as T;
            if (parent != null)
                return parent;
            child = parentObject;
        }
    }
}

Пример:

var dataGrid1 = dependencyObject1.FindParent<DataGrid>();
var dataGrid2 = dependencyObject2.FindParent<DataGrid>();
var isSameObject = dataGrid1 == dataGrid2;

Обновления

  1. Сетка может содержать большое количество элементов, но последний из них будет виден пользователю.
  2. Ошибка исходит от элемента, который вы хотите добавить сам, что элемент принадлежит другому элементу управления (некоторый другой элемент имеет элемент как дочерний элемент).
  3. Найдите родительский элемент элемента, который вы хотите добавить, удалите элемент из дочерней коллекции текущего родителя и добавьте этот элемент в качестве нового дочернего элемента вашей сетки.
  4. Попробуйте использовать snoop, чтобы выяснить, кто является родителем вашего элемента (содержится в _elementInputs).
  5. Вот несколько полезных ссылок ( первая, вторая).

Обновление 2

  1. Как я понимаю, у вас есть сторонняя инфраструктура в вашем проекте, потому что я не могу разрешить тип коллекций _elementInputs и UIElementOut.
  2. Поскольку _elementInputs - это поле, я до сих пор не могу понять, откуда взялись _elementInputs (не вижу этого в коде).
  3. Код для добавления совершенно нового элемента неверен:

Правильный код (на мой взгляд)

                //here is in my opinion the correct algorithm in this case
                var elementFromInputs = _elementInputs[i] as UIElement;
                if (elementFromInputs == null) continue;
                //try to find parent of type Panel
                var parentPanel = elementFromInputs.FindParent<Panel>();
                //try to find parent of type ContentControl
                var parentContentControl = elementFromInputs.FindParent<ContentControl>();
                if (parentPanel == null && parentContentControl == null)
                {
                    //add if there is no any parents
                    grid.Children.Add(elementFromInputs);
                }
                if (parentPanel != null)
                {
                    //remove element from parent's collection
                    parentPanel.Children.Remove(elementFromInputs);
                }
                if(parentContentControl != null)
                {
                    //reset parent content to release element
                    parentContentControl.Content = null;
                }
                grid.Children.Add(elementFromInputs);

Обновление 3

Вы вставили код (из правильного раздела кода) внутрь, если какое условие является _elementInputs[i] == null || !(_elementInputs[i] is UIElement) это означает фильтрацию всех ваших UIElements из области видимости. Так как я не знаком с концепциями vvvv, я не знаю, что у вас внутри массива _elementInputs, но если у вас есть UIElements, вам нужно пройти код, который я дал вам перед условием if with _elementInputs[i] == null || !(_elementInputs[i] is UIElement),

Пожалуйста, обновите ваш вопрос следующими пояснениями: 1. Что находится внутри _elementInputs[i]? 2. Что находится внутри _elementInputs[i].IOObject? 3. Какие элементы UIE вы хотите добавить в сетку? 4. Пожалуйста, запустите следующий метод и напишите мне комментарий, что у вас есть в вашей сетке и элементах управления TabControl.

Тестовый код

public void Evaluate(int SpreadMax)
{
    SpreadMax = 1;

    UIElementOut.SliceCount = 1;

    for (var i = 0; i < SpreadMax; i++)
    {
        if (UIElementOut == null || !(UIElementOut[i] is TabControl))
            UIElementOut[i] = new TabControl();
            var uiElement = (TabControl)UIElementOut[i];
            uiElement.Height = 200;
            uiElement.Width = 500;
    }

    Grid grid = new Grid();
    var listOfElements = new List<UIElements>
    {
            new Button {Background = Brushes.Tomato, Content = "Click Me"},
            new Button {Background = Brushes.Yellow, Content = "Click Me"},
            new Button {Background = Brushes.Green, Content = "Click Me"},
            new Button {Background = Brushes.Blue, Content = "Click Me"}
    };
    listOfElements.ForEach(button => grid.Children.Add(button));
    ((TabControl)UIElementOut[0]).Items.Add(new TabItem { Header = "Objects", Content = grid });
}

Я буду рад помочь, если у вас возникнут проблемы с кодом. С уважением.

Другие вопросы по тегам