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:
So, now my ItemsSource should be bound to an IList<Unit>. My treeview is defined like this:
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
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