0

我是 C# 和 WPF 的初学者。我正在为一个名为 vvvv 的基于节点的软件编写插件。我已经实现了滑块、按钮和其他简单的 ui 元素。以下代码显示了滑块节点在 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 输入其中。据我了解,我只能在一个 tabitem 中添加一个东西。所以我在考虑每次需要时创建一个网格,并用所有传入的 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);
        }
    }

我进行了很多搜索,但找不到任何解决该错误的方法。显然将元素添加到网格会抛出“指定元素已经是另一个元素的逻辑子元素”;

4

1 回答 1

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

您已将代码(来自正确的代码部分)粘贴到 if which 条件是_elementInputs[i] == null || !(_elementInputs[i] is UIElement)这意味着将所有 UIElements 过滤到范围之外。由于我不熟悉 vvvv 概念,我不知道您在 _elementInputs 数组中有什么,但如果您有 UIElements ,您需要通过我在 if with condition 之前给您的代码_elementInputs[i] == null || !(_elementInputs[i] is UIElement)

请使用以下说明更新您的问题: 1. _elementInputs[i] 里面是什么?2. _elementInputs[i].IOObject 里面是什么?3. 您要添加到网格中的 UIElement 是什么?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 });
}

如果您遇到代码问题,我将很乐意提供帮助。问候。

于 2016-01-31T12:05:56.997 回答