Проверьте, является ли указанный элемент уже логическим дочерним элементом другого элемента
Я новичок в 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;
Обновления
- Сетка может содержать большое количество элементов, но последний из них будет виден пользователю.
- Ошибка исходит от элемента, который вы хотите добавить сам, что элемент принадлежит другому элементу управления (некоторый другой элемент имеет элемент как дочерний элемент).
- Найдите родительский элемент элемента, который вы хотите добавить, удалите элемент из дочерней коллекции текущего родителя и добавьте этот элемент в качестве нового дочернего элемента вашей сетки.
- Попробуйте использовать snoop, чтобы выяснить, кто является родителем вашего элемента (содержится в _elementInputs).
- Вот несколько полезных ссылок ( первая, вторая).
Обновление 2
- Как я понимаю, у вас есть сторонняя инфраструктура в вашем проекте, потому что я не могу разрешить тип коллекций _elementInputs и UIElementOut.
- Поскольку _elementInputs - это поле, я до сих пор не могу понять, откуда взялись _elementInputs (не вижу этого в коде).
- Код для добавления совершенно нового элемента неверен:
Правильный код (на мой взгляд)
//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 });
}
Я буду рад помочь, если у вас возникнут проблемы с кодом. С уважением.