2016-03-18 135 views
2

我有這樣的用戶控件:指定的元素已經是另一個元素的邏輯子元素。先斷開它。在用戶控制

[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和錯誤第一個按鈕「指定的元素已經是另一個元素的邏輯子元素,請先斷開它。」感謝您的幫助,對不起我的糟糕英語。

回答

2

不知道設計師正在做什麼,但這會「修復」它。

更改行:

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]); 
0

運用JH代碼,我將移動它到你的函數的頂部,讓您的網格時的狀態你清除它,被「清除」,並且所有的孩子已經從視覺樹中斷開。

private void ClearAndBuildGrid() 
{ 
    foreach (var item in Items) 
    { 
     var parent = System.Windows.Media.VisualTreeHelper.GetParent(item) as Grid; 
     if (parent != null) 
      parent.Children.Remove(item); 
    } 
    MainGrid.Children.Clear(); 

這將是一個風格/意圖/喜好的事情,並且要清楚,答案J.H.給出是完全有效的。

考慮使用foreach而不是for而不必處理數組下標。

相關問題