c# - 指定的元素已经是另一个元素的逻辑子元素。先断开它。在用户控制中

标签 c# wpf xaml wpf-controls

我有这个用户控件:

[ContentProperty("Items")]
[DefaultProperty("Items")]
public partial class PanelControl : UserControl
{
    public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(PanelControl), new FrameworkPropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(OnOrientationChanged)));
    public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<UIElement>), typeof(PanelControl), new FrameworkPropertyMetadata(new ObservableCollection<UIElement>(), new PropertyChangedCallback(OnItemsChanged)));
    public static readonly DependencyProperty SizeProperty = DependencyProperty.RegisterAttached("Size", typeof(double), typeof(PanelControl), new FrameworkPropertyMetadata(1.0, new PropertyChangedCallback(OnSizeChanged)), new ValidateValueCallback(IsSizeValid));

    public Orientation Orientation
    {
        get
        {
            return (Orientation)GetValue(OrientationProperty);
        }
        set
        {
            SetValue(OrientationProperty, value);
        }
    }

    public ObservableCollection<UIElement> Items
    {
        get
        {
            return (ObservableCollection<UIElement>)GetValue(ItemsProperty);
        }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }

    public static void SetSize(UIElement element, double size)
    {
        element.SetValue(SizeProperty, size);
    }
    public static double GetSize(UIElement element)
    {
        return (double)element.GetValue(SizeProperty);
    }

    private static void OnOrientationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        /*MessageBox.Show("orientation");*/
        ((PanelControl)dependencyObject).ClearAndBuildGrid();
    }

    private static void OnItemsChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        /*MessageBox.Show("items");*/
        ((PanelControl)dependencyObject).ClearAndBuildGrid();
        if(args.OldValue != null)
            ((ObservableCollection<UIElement>)args.OldValue).CollectionChanged -= ((PanelControl)dependencyObject).OnItemsCollectionChanged;
        if (args.NewValue != null)
            ((ObservableCollection<UIElement>)args.NewValue).CollectionChanged += ((PanelControl)dependencyObject).OnItemsCollectionChanged;

    }

    private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
    {
        /*MessageBox.Show("collection");*/
        ClearAndBuildGrid();
    }

    private static void OnSizeChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        ((PanelControl)dependencyObject).ClearAndBuildGrid();
        /*MessageBox.Show("size");*/
    }
    private static bool IsSizeValid(object value)
    {
        return (double)value < 0 ? false : true;
    }

    private void ClearAndBuildGrid()
    {
        MainGrid.Children.Clear();
        MainGrid.RowDefinitions.Clear();
        MainGrid.ColumnDefinitions.Clear();
        /*MessageBox.Show(MainGrid.Children.Count.ToString());*/
        for (int i = 0; i < Items.Count; i++)
        {
            if (Orientation == Orientation.Horizontal)
            {
                MainGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = SizeToGridLength(GetSize(Items[i])) });
                Grid.SetColumn(Items[i], i * 2);
                if (i != Items.Count - 1)
                {
                    MainGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(5) });
                    GridSplitter splitter = new GridSplitter() { ResizeDirection = GridResizeDirection.Columns, HorizontalAlignment = HorizontalAlignment.Stretch };
                    Grid.SetColumn(splitter, i * 2 + 1);
                    MainGrid.Children.Add(splitter);
                }
            }
            else
            {
                MainGrid.RowDefinitions.Add(new RowDefinition() { Height = SizeToGridLength(GetSize(Items[i])) });
                Grid.SetRow(Items[i], i * 2);
                if (i != Items.Count - 1)
                {
                    MainGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(5) });
                    GridSplitter splitter = new GridSplitter() { ResizeDirection = GridResizeDirection.Rows, VerticalAlignment = VerticalAlignment.Stretch };
                    Grid.SetRow(splitter, i * 2 + 1);
                    MainGrid.Children.Add(splitter);
                }
            }
            MainGrid.Children.Add(Items[i]);
        }
    }

    private GridLength SizeToGridLength(double size)
    {
        return new GridLength(size, GridUnitType.Star);
    }

    public PanelControl()
    {
        InitializeComponent();
        Items.CollectionChanged += OnItemsCollectionChanged;
    }
}

我在这里使用它:

<p:PanelControl>
    <Button />
    <Button />
    <Button />
</p:PanelControl>

当我启动应用程序时,它运行良好,但在设计器中,我在 xaml 中的第一个按钮下划线,并出现错误“指定元素已经是另一个元素的逻辑子元素。首先断开它。”感谢您的帮助,抱歉我的英语不好。

最佳答案

不确定设计师发生了什么,但这会“修复”它。

更改行:

MainGrid.Children.Add(Items[i]);

致:

var parent = VisualTreeHelper.GetParent(Items[i]) as Grid;
if (parent != null)
    parent.Children.Remove(Items[i]);
MainGrid.Children.Add(Items[i]);

关于c# - 指定的元素已经是另一个元素的逻辑子元素。先断开它。在用户控制中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36092599/

相关文章:

c# - 程序兼容性助手认为我的应用程序是安装程序

c# - 如何将 Typescript Map 对象发布到 ASP.Net Core WebAPI?

c# - WPF字体大小不变

c# - WPF 模板中的平滑动画 ProgressBar

xaml - 应用内日历上的周 View (通用 Windows 平台/UWP)

c# - 相同的 url 不同的环境 - 一个成功另一个失败并出现 SSL 错误

c# - WPF WebBrowser - 检测重定向?

C# 在转换后访问类成员

c# - C#中的加法和除法

c# - 将 ActivSync 4.5 与 Visual Studio 2005 安装项目捆绑在一起