簡體   English   中英

如何將Linq Group By和Distinct用於Treeview

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM