如何使用Linq Group By和Distinct进行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);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章