我将TreeView组织为:
Level1
level 1.1
level 1.1.1
level 1.1.2
level 1.1.3
level 1.1.3.1
level 1.1.3.2
level 1.2
level 1.3
level2
level 2.1
.............
每个级别都是一个继承自TreeViewModelBase的ViewModel。
给定一个类似于1.1.3.2的视图模型,此代码将从TreeView中删除它:
var y = SelectedItem as TreeViewModelBase;
var z = y.Parent;
z.Children.Remove(y);
if (z.Children.Count == 0)
{
var g = z.Parent;
g.Children.Remove(z);
}
从所选项目开始并从父项中删除它的单个循环是什么。如果父项不再有子项,则从父项中删除父项,同样处理树结构。
执行此操作的最佳循环结构是什么?
感谢您的帮助。
答案 0 :(得分:1)
以下是我提出的建议:
(修剪项目1.4.1.1)
之前:
后:
Item
:您的商品
Parent
属性Prune
方法,将其从父级中移除,爬上并重复直到不可能代码:
internal class Item
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ItemCollection _children;
public Item()
{
Children = new ItemCollection();
}
public Item Parent { get; private set; }
public ItemCollection Children
{
get { return _children; }
set
{
if (_children != null)
{
_children.CollectionChanged -= Children_CollectionChanged;
}
if (value != null)
{
value.CollectionChanged += Children_CollectionChanged;
// Notify about previously (never notified) added items
if (value.Count > 0)
{
value.RaiseCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value));
}
}
_children = value;
}
}
public string Name { get; set; }
private void Children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e != null)
{
if (e.NewItems != null)
{
IEnumerable<Item> newItems = e.NewItems.OfType<Item>();
foreach (Item item in newItems)
{
item.Parent = this;
}
}
if (e.OldItems != null)
{
IEnumerable<Item> oldItems = e.OldItems.OfType<Item>();
foreach (Item item in oldItems)
{
item.Parent = null;
}
}
}
}
public override string ToString()
{
return string.Format("{0}", Name);
}
public void Prune()
{
Item parent = Parent;
if (parent != null)
{
parent.Children.Remove(this);
while (parent.Children.Count <= 0)
{
Item grandParent = parent.Parent;
if (grandParent != null)
{
grandParent.Children.Remove(parent);
parent = grandParent;
}
}
}
}
}
ItemCollection
:
使用ObservableCollection
的项目集合,非常有助于减少指定父级的需要,您将在下面的示例中看到。
internal class ItemCollection : ObservableCollection<Item>
{
public ItemCollection()
{
}
public ItemCollection(IEnumerable<Item> items)
{
foreach (Item item in items)
{
Add(item);
}
}
internal void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
{
OnCollectionChanged(e);
}
}
演示代码
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var root = new Item
{
Name = "root",
Children = new ItemCollection(new[]
{
new Item
{
Name = "item1.1",
Children = new ItemCollection(new[]
{
new Item {Name = "item1.1.1"},
new Item {Name = "item1.1.2"}
})
},
new Item
{
Name = "item1.2",
Children = new ItemCollection(new[]
{
new Item {Name = "item1.2.1"}
})
},
new Item {Name = "item1.3"}
})
};
var item1411 = new Item
{
Name = "item1.4.1.1"
};
var item141 = new Item
{
Name = "item1.4.1",
Children = new ItemCollection(new[]
{
item1411
})
};
var item14 = new Item
{
Name = "item1.4",
Children = new ItemCollection(new[]
{
item141
})
};
root.Children.Add(item14);
Console.WriteLine("-----------------");
Console.WriteLine("before pruning");
Console.WriteLine("-----------------");
PrintHierarchy(root);
Console.WriteLine("-----------------");
Console.WriteLine("after pruning");
Console.WriteLine("-----------------");
item1411.Prune();
PrintHierarchy(root);
DataContext = root;
}
private void PrintHierarchy(Item root, int level = 0)
{
Console.WriteLine("{0}{1}", string.Concat(Enumerable.Repeat(" ", level)), root);
if (root.Children.Count > 0)
{
foreach (Item child in root.Children)
{
PrintHierarchy(child, level + 1);
}
}
}
}
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow"
Width="525"
Height="350">
<Grid>
<Grid.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
</Style>
</Grid.Resources>
<TreeView ItemsSource="{Binding (wpfApplication3:Item.Children)}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="wpfApplication3:Item" ItemsSource="{Binding Children}">
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
修改强>
系统显然会反映树中的变化,例如:
private void Button_Click(object sender, RoutedEventArgs e)
{
_item1411.Prune();
}
TreeView
将无缝更新。
答案 1 :(得分:1)
我赞同艾贝的回答。在我的特定情况下,所有ViewModel都保存在ObservableCollections中,并且所有ViewModel都来自相同的TreeViewModelBase,下面的代码似乎更简单。 TreeView将自动更新。
var z = SelectedItem as TreeViewModelBase;
TreeViewModelBase y;
do
{
y = z;
if (y.Parent == null) break;
z = y.Parent;
z.Children.Remove(y);
} while(z.Children.Count==0);