我有一个从WinRT.XamlToolKit导入的TreeView,我试图在通用应用程序中使用。重要的是要注意,我知道有类似的问题,但有些问题不是因为它们早于Universal Apps,或者它们不适应MVVM的使用。按照教程了解如何填充树,我遇到了这种递归方法:
private ObservableCollection<TreeViewItemModel> BuildTree(int depth, int branches)
{
var tree = new ObservableCollection<TreeViewItemModel>();
if (depth <= 0) return tree;
var depthIndices = Enumerable.Range(0, branches).Shuffle();
for (var i = 0; i < branches; i++)
{
var d = depthIndices[i] % depth;
var b = _rand.Next(branches / 2, branches);
tree.Add(
new TreeViewItemModel
{
Branch = b,
Depth = d,
Text = "Item " + _itemId++,
Children = BuildTree(d, b)
});
}
return tree;
}
它被称为TreeItems = BuildTree(5,5);
然后我将TreeView ItemSource绑定到TreeItems并附加到TreeViewItemModel的Text属性。
这适用于预先确定的集合,然后如方法中所示,使用随机数来计算树将如何显示。 (在什么深度,有多少分支等)
我不确定如何实现类似的递归函数,以使用具有未确定数量的子项的不同ItemModel填充树。在我的设置中,我有一个空间,可以有儿童空间,设备和/或传感器。空间可以没有设备,也没有传感器,但是一个或多个子空间,或者它可能没有子空间,但它可能有设备和/或传感器。在我的Sensor类中,它具有与其所绑定的空间的Id以及它向其报告的设备相关的父ID。
因此,简而言之,我需要从空格列表中递归填充ObservableCollection<TreeViewSpaceModel>
。
TreeViewSpaceModel类:
public class TreeViewSpaceModel : NotifyObject
{
private string _name;
private Guid _iD;
private string _parentName;
private ObservableCollection<TreeViewSpaceModel> _children = new ObservableCollection<TreeViewSpaceModel>();
private ObservableCollection<TreeViewDeviceModel> _devices = new ObservableCollection<TreeViewDeviceModel>();
private ObservableCollection<TreeViewSensorModel> _sensors = new ObservableCollection<TreeViewSensorModel>();
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
public string ParentName
{
get { return _parentName; }
set { SetProperty(ref _parentName, value); }
}
public Guid Id
{
get { return _iD; }
set { SetProperty(ref _iD, value); }
}
public ObservableCollection<TreeViewSpaceModel> Children
{
get { return _children; }
set { SetProperty(ref _children, value); }
}
public ObservableCollection<TreeViewDeviceModel> Devices
{
get { return _devices; }
set { SetProperty(ref _devices, value); }
}
public ObservableCollection<TreeViewSensorModel> Sensors
{
get { return _sensors; }
set { SetProperty(ref _sensors, value); }
}
}
DeviceModel没有子级,但它有传感器,而SensorModel没有子级或设备或传感器,因为它是层次结构的末尾。 太空课:
public class Space
{
public Guid Id { get; set; }
public string Name { get; set; }
public int SpaceTypeId { get; set; }
public virtual Space Parent { get; set; }
public virtual ICollection<Sensor> Sensors { get; set; }
public virtual ICollection<Device> Devices { get; set; }
public virtual ICollection<Space> Children { get; set; }
}
最终结果理想情况如下:
Space1
---- ChildSpace1
--------Device1
-------------Sensor1
-------------Sensor2 (Sensors report for Spaces, but are bound to Devices)
--------SubChildSpace1
-------------Sensor1
-------------Sensor2
--------SubChildSpace2
-------------Sensor1
------------Sensor2
--------Device2
---- ChildSpace2
Space2
如果有更简单的方法来做这个而不是递归方法,我很乐意接受它。在研究用于通用应用程序的TreeViews时,我确实遇到过其他人说用户应该能够执行类似items.Node(0).Add(stuffhere)
的操作;但是,我无法弄清楚如何实现这一点,因为ObservableCollection没有提供.Node扩展名。
答案 0 :(得分:1)
由于控件不支持虚拟化 - 它假设项目数量有限(最适合远低于1000项),因此递归应该没问题。 TreeViewSpaceModel
的一个小问题是它有多个子模型列表。要让它与TreeView
一起使用,您需要一个子列表,但它们可以是不同类型的。如果您想以不同方式显示它们 - 您需要使用模板选择器。至于生成列表,没有编译检查,它可能是这样的:
static ObservableCollection<TreeViewItemModel> GetSpaceTree(
IEnumerable<Space> spaces)
{
return new ObservableCollection<TreeViewItemModel>(
spaces
.Where(space => space.Parent == null)
.Select(space => new TreeViewSpaceModel(space))
);
}
然后在TreeViewSpaceModel
中你会得到像这样的构造函数
TreeViewSpaceModel(Space space)
{
// TODO: Set name, ID etc.
this.Children = new ObservableCollection<TreeViewItemModel>(
space.Children.Select(childSpace => new TreeViewSpaceModel(childSpace))
.Union(space.Devices.Select(device => new TreeViewDeviceModel(device)))
.Union(space.Sensors.Select(sensor => new TreeViewSensorModel(sensor)))
);
}
答案 1 :(得分:0)
我不太清楚为什么我不能得到Filip Skakun提供给工作的答案,但他仍然值得一些赞誉,因为他的例子确实帮助我思考如何解决问题。我只使用了一个班级模型 - &gt; TreeViewItemModel并像这样构造它来构建我的Observable Collection。
TreeViewItemModel类:
public class TreeViewItemModel : NotifyObject
{
private string _name;
private Guid _iD;
private string _parentName;
private Guid _parentId;
private string _parentDeviceName;
private ObservableCollection<TreeViewItemModel> _children = new ObservableCollection<TreeViewItemModel>();
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
public Guid ParentId
{
get { return _parentId; }
set { SetProperty(ref _parentId, value); }
}
public string ParentDeviceName
{
get { return _parentDeviceName; }
set { SetProperty(ref _parentDeviceName, value); }
}
public string ParentName
{
get { return _parentName; }
set { SetProperty(ref _parentName, value); }
}
public Guid Id
{
get { return _iD; }
set { SetProperty(ref _iD, value); }
}
public ObservableCollection<TreeViewItemModel> Children
{
get { return _children; }
set { SetProperty(ref _children, value); }
}
public TreeViewItemModel(object thing)
{
//GetDevices();
if (thing.GetType() == typeof (Space))
{
var space = (Space)thing;
var parentName = string.Empty;
if (space.Parent != null)
{
parentName = space.Parent.Name;
}
Name = space.Name;
ParentName = parentName;
Id = space.Id;
Children = new ObservableCollection<TreeViewItemModel>(space.Children.Select(s => new TreeViewItemModel(s)).Union(space.Devices.Select(d => new TreeViewItemModel(d)).Union(space.Sensors.Select(sensor => new TreeViewItemModel(sensor)))));
}
else if (thing.GetType() == typeof (Device))
{
var device = (Device) thing;
var parentName = device.Space.Name;
Name = device.Name;
ParentName = parentName;
Id = device.Id;
Children = new ObservableCollection<TreeViewItemModel>(device.Sensors.Select(s => new TreeViewItemModel(s)));
}
else if (thing.GetType() == typeof(Sensor))
{
var sensor = (Sensor) thing;
var space = sensor.Space.Name ?? string.Empty;
//var device = Devices.First(d => d.Id == sensor.DeviceId);
var device = sensor.Device;
ParentName = device == null ? "No Matching Device" : device.Name;
Name = sensor.Id.ToString();
Id = sensor.Id;
ParentName = space;
Children = null;
}
}
我称之为:TreeSpaces = BuildSpaceTree(AllSpaces);
BuildSpaceTree方法如下:
private ObservableCollection<TreeViewItemModel> BuildSpaceTree(IEnumerable<Space> spaces)
{
return new ObservableCollection<TreeViewItemModel>(spaces.Where(space => space.Parent == null).Select(space => new TreeViewItemModel(space)));
}
我对Filip的回答最大的问题是,它不喜欢我尝试联合多个不同类型的列表。