问题
I have my model classes that look like this:
class Base
{
public string Name { get; set; }
}
class Item : Base { ... }
class Group : Base
{
public List<Base> GroupItems { get; private set; }
}
Then, I have a view model with an Items
collection, that I fill up like shown in the FillUp()
method below:
class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Base> Items { get; set; }
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1);
this.Items.Add(item1);
this.Items.Add(item2);
this.Items.Add(group);
}
}
So, my Items
collection now contains 2 objects of type Item
and one object of type Group
, which has a "parent-child" reference to one of the Item
object.
What I want to achieve: I'd like to display this model in a TreeView
so that all the Item
s which belong to some Group
should be displayed as child elements of that Group
, despite of they are in the "root" collection.
It should then look like this:
- Item2
+ Group
- Item1
I could use a HierarchicalDataTemplate
to display parent-child elements, but this does not let me filtering out those items from the root collection that belong to some groups.
<TreeView>
<TreeView.Resources>
<HierarchicalDataTemplate DataType = "{x:Type loc:Group}" ItemsSource = "{Binding GroupItems}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type loc:Item}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TreeView.Resources>
<TreeViewItem ItemsSource="{Binding Items}"/>
</TreeView>
With this view, I'm getting the "Item1"
twice:
- Item1
- Item2
+ Group
- Item1
Is there any way to get the desired result via view (XAML) markup only? Otherwise, I should change my view model so that the Item
s will be only added into the Group
s, not in the "root" collection (but that is what I try to avoid at the moment).
回答1:
Assuming you have some indication of which Item belongs in a group , for this example iv'e added a Guid in Group and Item classes.
You can go about this in 2 ways :
1) Create a composite wrapper class . And create an ItemsSource of Wrapper class . Where there is a single item which does not belong to a group , Children would just remain null.
public class Wrapper<T> where T : Base
{
public List<T> Children { get; set; }
}
public class Base
{
public string Name { get; set; }
}
public class Item : Base
{
public Guid GroupId { get; set; }
}
public class Group : Base
{
public Guid ID { get; set; }
public List<Item> GroupItems { get; private set; }
}
your second option is to use a CollectionView , and filter out Items which belong to a group.
private ICollectionView _baseView;
public ICollectionView BaseView
{
get
{
if (_baseView == null)
{
_baseView = new ListCollectionView((IList) items);
_baseView.Filter = o => o is Group || o is Item && (o as Item).GroupId != Guid.Empty;
}
return _baseView;
}
}
回答2:
You can define two Collections in your ViewModel one for all items and one for the tree, it seems to be simple.
class ViewModel
{
public ObservableCollection<Base> AllItems { get; set; }
public ObservableCollection<Base> RootLevelItems { get; set; }
}
If you have only two levels (e.g. no nested groups) you can use ListView with GroupStyle.
回答3:
In response to your comment:
There are no duplicates in the collection by the way, as you can see in my code - it's just the view that displays the item twice.
You said that there are no duplicates in your code, but clearly there is:
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1); // Adding item1 into collection in Group
this.Items.Add(item1); // Adding item1 into collection again
this.Items.Add(item2);
this.Items.Add(group);
}
Therefore, as I said, this is the expected behaviour and the TreeView
is only showing you what you told it to. So to remove the duplicate item, simply don't add it to your collection:
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1); // Adding item1 into collection in Group
// this.Items.Add(item1); // Don't add item1 into collection again
this.Items.Add(item2);
this.Items.Add(group);
}
来源:https://stackoverflow.com/questions/28340249/is-it-possible-to-define-a-treeview-hierarchical-view-template-for-a-plain-col