我正在从XML文件中读取我的初始数据并将其返回为:
List<ReportItem> ReportMapItems = Database.ReadXMLReportMap();
然后将ReportMapItems读入ReportTree,作为树视图的基本集合:
ReportTree = new ObservableCollection<ReportViewModel>(
(from report in ReportMapItems
select new ReportViewModel(report, ReportMapItems))
.ToList());
XAML
<TreeView ItemsSource="{Binding ReportTree}" >
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type r:ReportViewModel}"
ItemsSource="{Binding Children}"
>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ReportName}" Width="150" />
<TextBlock Text="{Binding Comment}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
DataType="{x:Type r:NetworkViewModel}"
ItemsSource="{Binding Children}"
>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding NetworkIP}" Width="110" />
<TextBlock Text="{Binding NetworkName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type r:PrinterViewModel}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding IPAddress}" Width="100" />
<TextBlock Text="{Binding PrinterFullName}" Width="300" />
<TextBlock Text="{Binding Location}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
问题是树视图正在为ReportMapItems中的每个报表条目创建一个节点,因此多次显示相同的报表。
我需要的是为每个不同的ReportName生成一个报告节点,并且在此节点下为每个不同的NetWorkIP生成一个唯一的网络节点。最后,在其相应的NetWorkIP和ReportName下为每个PrinterFullName生成ONLY ONE打印机节点。
如何使用LINQ来规范化ReportMapItems或ReportTree,以便TreeView正确显示信息(以标准化方式)????
提前感谢您的帮助。
编辑:根据请求,以下是一些类的定义。 (这不是一个代码转储,但遗憾的是涉及到很多类。如果需要更多信息,我很乐意添加它。)
public class ReportViewModel : TreeViewModelBase
{
private string reportname;
readonly IList<ReportItem> reportitems;
private ReportItem report;
private IList<ReportItem> ReportMapItems;
private ReportItem reportitem;
// Each ReportViewModel is a level 1 node in the Tree. Each ReportViewModel should only have reportitems specific to the
// report being modeled.
public ReportViewModel(ReportItem reportitem, IList<ReportItem> reportitems)
: base(null, true)
{
this.reportitem = reportitem;
this.reportitems = reportitems;
}
public ReportViewModel(Report SelectedReport, UI.Network.PRINTERMAP SelectedPrinter)
: base(null, true)
{
ReportItem r = new ReportItem {
ReportName = SelectedReport.ReportName,
Comment = SelectedReport.Comment,
IPAddress = SelectedPrinter.IPAddress,
PrinterDescription = SelectedPrinter.Description,
PrinterFullName = SelectedPrinter.PrinterFullName,
Location = SelectedPrinter.Location,
NetworkIP = SelectedPrinter.NetworkIP,
NetworkName = SelectedPrinter.NetworkName
};
this.reportitem = r;
this.reportitems = new List<ReportItem>();
this.reportitems.Add(r);
}
public string ReportName
{
get { return reportitem.ReportName; }
}
public string Comment
{
get { return reportitem.Comment; }
}
public IList<ReportItem> ReportItems
{
get { return reportitems; }
}
// LoadChildren() is called only when the ReportViewModel is expanded by user clicking on '+'.
protected override void LoadChildren()
{
foreach (Network network in Database.GetNetwork(ReportName, ReportItems))
base.Children.Add(new NetworkViewModel(network, this));
}
}
public class NetworkViewModel : TreeViewModelBase
{
readonly Network _network;
readonly ReportViewModel _reportviewmodel;
public NetworkViewModel(Network network, ReportViewModel parentRegion)
: base(parentRegion, true)
{
_network = network;
_reportviewmodel = parentRegion;
}
public string NetworkIP
{
get { return _network.NetworkIP; }
}
public string NetworkName
{
get { return _network.NetworkName; }
}
public string ReportName
{
get { return _reportviewmodel.ReportName; }
}
public IList<ReportItem> ReportItems
{
get { return _reportviewmodel.ReportItems; }
}
// LoadChildren() is called only when the NetworkViewModel is expanded by user clicking on '+'.
protected override void LoadChildren()
{
foreach (Printer printer in Database.GetPrinters(ReportName, NetworkIP, ReportItems))
base.Children.Add(new PrinterViewModel(printer, this));
}
}
public List<ReportItem> ReportMapItems { get; set; }
public class ReportItem
{
public string ReportName { get; set; }
// Report description
public string Comment { get; set; }
// Printer IPAddress
public string IPAddress { get; set; }
// The PhysicalAddress of a device is its MAC.
public string PhysicalAddress { get; set; }
// Printer description
public string PrinterDescription { get; set; }
// Full Name of the printing queue
public string PrinterFullName { get; set; }
// Printer location
public string Location { get; set; }
// Network IP
public string NetworkIP { get; set; }
// Network Name
public string NetworkName { get; set; }
}
public class ReportTree
{
public ReportTree(string reportName)
{
this.ReportName = reportName;
}
public ReportTree()
{
// TODO: Complete member initialization
}
public string ReportName { get; set; }
readonly List<Network> _networks = new List<Network>();
public List<Network> Networks
{
get { return _networks; }
}
}
public struct NETWORK
{
public string NetworkName { get; set; }
public string NetworkIP { get; set; }
}
public struct PRINTERMAP
{
// the PrinterName is the name from the printer que
public string PrinterFullName { get; set; }
public string MAC { get; set; }
public string IPAddress { get; set; }
public string Comment { get; set; }
public string Description { get; set; }
// Location is from the Device table, (not the printer que).
public string Location { get; set; }
public int Type { get; set; }
public string Company { get; set; }
public string Model { get; set; }
// the DeviceName is the name from the NetBios.
public string DeviceName { get; set; }
public string Office { get; set; }
public string NetworkIP { get; set; }
public string NetworkName { get; set; }
}
答案 0 :(得分:1)
这是我认为System.Linq
球队错失的一种情况。但是,由于我们能够创建Extension methods,我们可以创建自己的DistinctBy<TSource, Tkey> IEnumerable
扩展方法:
public static IEnumerable<TSource> DistinctBy<TSource, TKey> (
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> keys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (keys.Add(keySelector(element))) yield return element;
}
}
这是一种非常简单的方法,只使用HashSet
来“过滤”重复值,只返回不同的属性值。您可以像这样使用它:
IEnumerable<YourDataType> distinctCollection = fullCollection.
DistinctBy<YourDataType, YourPropertyDataType>(d => d.PropertyToMakeDistinctBy);