Can Drag and Drop be enabled on tree hierarchy when self-referencing?

2 posts, 0 answers
  1. Rodd
    Rodd avatar
    7 posts
    Member since:
    Jul 2010

    Posted 09 Aug 2011 Link to this post

    I followed the guidelines for binding a treeview to self-referencing data
    I noticed in the Drag and Drop documentation for treeview, that dropping into a node is only available if the ItemsSource is IList.

    So, I changed the UnitCollection class (from the self-referencing document) to look like this:
        public class UnitCollection : IList<Unit>, INotifyPropertyChanged, INotifyCollectionChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            public event NotifyCollectionChangedEventHandler CollectionChanged;
            private List<Unit> _internalList;
     
            private void OnPropertyChanged(string propertyName)
            {
                this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
            }
            private void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, e);
            }
     
            private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
            {
                if (CollectionChanged != null)
                    CollectionChanged(this, e);
            }
            private void OnCollectionChanged(NotifyCollectionChangedAction action, Unit item, int index)
            {
                this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
            }
     
            public UnitCollection(IEnumerable<Unit> list)
            {
                _internalList = new List<Unit>();
                foreach (var item in list)
                {
                    this.Add(item);
                }
            }
            public UnitCollection()
            {
                _internalList = new List<Unit>();
            }
     
            private void AdoptItem(Unit item)
            {
                item.SetOwner(this);
                OnPropertyChanged("Item[]");
            }
            private void DiscardItem(Unit item)
            {
                item.SetOwner(null);
                OnPropertyChanged("Item[]");
            }
             
            public int IndexOf(Unit item)
            {
                return _internalList.IndexOf(item);
            }
     
            public void Insert(int index, Unit item)
            {
                this.AdoptItem(item);
                _internalList.Insert(index, item);
                OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
            }
     
            public void RemoveAt(int index)
            {
                var item = _internalList[index];
                this.DiscardItem(item);
                _internalList.RemoveAt(index);
                OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
            }
     
            public Unit this[int index]
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }
     
            public void Add(Unit item)
            {
                this.AdoptItem(item);
                _internalList.Add(item);
                OnCollectionChanged(NotifyCollectionChangedAction.Add, item, 0);
            }
     
            public void Clear()
            {
                foreach (var item in _internalList)
                {
                    this.DiscardItem(item);
                }
                _internalList.Clear();
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
     
            public bool Contains(Unit item)
            {
                return _internalList.Contains(item);
            }
     
            public void CopyTo(Unit[] array, int arrayIndex)
            {
                _internalList.CopyTo(array, arrayIndex);
            }
     
            public int Count
            {
                get { return _internalList.Count; }
            }
     
            public bool IsReadOnly
            {
                get { throw new NotImplementedException(); }
            }
     
            public bool Remove(Unit item)
            {
                var index = _internalList.IndexOf(item);
                this.DiscardItem(item);
                var result = _internalList.Remove(item);
                OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
                return result;
            }
     
            public IEnumerator<Unit> GetEnumerator()
            {
                return _internalList.GetEnumerator();
            }
     
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return ((System.Collections.IEnumerable)_internalList).GetEnumerator();
            }
         
    }

    So, now my ItemsSource should be bound to an IList<Unit>.  My treeview is defined like this:
    <tel:RadTreeView x:Name="UnitTree"
                     ItemsSource="{Binding Units, Converter={StaticResource UnitHierarchy}}"
                     SelectedItem="{Binding SelectedUnit, Mode=TwoWay}"
                     ScrollViewer.VerticalScrollBarVisibility="Auto"
                     IsDragDropEnabled="True"
                     BorderBrush="Black" BorderThickness="1"
                     Grid.Row="1" Grid.ColumnSpan="2"
                     IsEnabled="{Binding IsEditing}"
                     IsExpandOnSingleClickEnabled="True">
        <tel:RadTreeView.ItemTemplate >
            <tel:HierarchicalDataTemplate ItemsSource="{Binding Converter={StaticResource UnitHierarchy}}" >
                <StackPanel Orientation="Vertical" Width="200" >
                    <StackPanel Orientation="Horizontal" >
                        <TextBlock x:Name="name" TextWrapping="Wrap" Text="{Binding Name}" FontWeight="Bold" />
                        <TextBlock Text="*" Margin="10,0,0,0" Visibility="{Binding HasChanges, Converter={StaticResource BooleanToVisibility}}"  />
                    </StackPanel>
                    <TextBlock x:Name="type" Text="{Binding UnitType}" FontStyle="Italic" FontSize="10" Foreground="Gray" FontWeight="Bold" />
                </StackPanel>
            </tel:HierarchicalDataTemplate>
        </tel:RadTreeView.ItemTemplate>
    </tel:RadTreeView>

    And my ViewModel has a public UnitCollection Units {get; set;} which you can see is bound to my ItemsSource.

    With all this in place, I can drag each item but it does not allow me to drop items either into another item nor does it allow me to drop before or after another item.

    What do I have to do to get drag and drop to work into items?

    Thanks.

    Rodd
  2. Rodd
    Rodd avatar
    7 posts
    Member since:
    Jul 2010

    Posted 09 Aug 2011 Link to this post

    Okay, so I figured it out.  The problem was the Converter.  My converter looked like this:
    public class UnitCollectionConverter : IValueConverter
    {
     
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var item = value as Unit;
            if (item != null)
            {
                var list = item.Owner.Where(i => i.ParentId == item.Id);
                return list;
            }
     
            var items = value as UnitCollection;
            if(items != null)
            {
                var list = items.Where(i => !items.Any(it => it.Id == i.ParentId));
                return list;
            }
     
            return null;
        }
     
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    I had to add .ToList() to the return values like so:
    var list = item.Owner.Where(i => i.ParentId == item.Id);
    return list.ToList();
  3. DevCraft banner
Back to Top