[英]How to use Linq Group By and Distinct for Treeview
我正在從XML文件讀取初始數據,並將其返回為:
List<ReportItem> ReportMapItems = Database.ReadXMLReportMap();
然后,將ReportMapItems讀取到ReportTree中,該Tree作為Treeview的基本集合:
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的最后生成一個打印機節點。
一個人將如何使用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; }
}
我相信System.Linq
團隊會錯過這種情況。 但是,由於我們具有創建擴展方法的能力,我們僅可以創建自己的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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.