English 中文(简体)
如何从结构结构中建立目标等级? (以千方百计计)
原标题:How to build object hierarchy from SQL query? (for WPF TreeView)

由于抽出时间阅读这一员额。

I m having trouble trying to build a hierarchial object when getting data from my SQL database. Please note that I am a little bit of a newbie programmer.

你们如何建造一个等级不明的物体? 当我说不为人知的等级时,每个节点都可能有不同的儿童节点,而这反过来又可能有不同的儿童节点,等等。

想法是,我需要利用我的数据KQ制造一个等级的物体,以控制WPF的树木。

Below I have included the code I have so far. The first bit of code is my Class made up of Properties. Note that the "Products" class has an ObservableCollection referencing itself. I think this is how you construct the nested nodes. i.e. a list inside a list.

第二部法典是我的方法,从数据库下载数据。 在这方面,我需要说明如何将下载的数据分为等级。

www.un.org/spanish/ecosoc 产品类别(生产)

public class Products : INotifyPropertyChanged, IDataErrorInfo
{
    private Int64 m_ID;
    private SqlHierarchyId m_Hierarchy;
    private string m_Name;
    private ObservableCollection<Products> m_ChildProducts;

    // Default Constructor
    public Products()
    {
        ChildProducts = new ObservableCollection<Products>();
    }

    //Properties

    public Int64 ID
    {
        get
        {
            return m_ID;
        }
        set
        {
            m_ID = value;
            OnPropertyChanged(new PropertyChangedEventArgs("ID"));
        }
    }

    public SqlHierarchyId Hierarchy
    {
        get
        {
            return m_Hierarchy;
        }
        set
        {
            m_Hierarchy = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Hierarchy"));
        }
    }

    public String Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            m_Name = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Name"));
        }
    }

    public Int16 Level
    {
        get
        {
            return m_Level;
        }
        set
        {
            m_Level = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Level"));
        }
    }

    public Int64 ParentID
    {
        get
        {
            return m_ParentID;
        }
        set
        {
            m_ParentID = value;
            OnPropertyChanged(new PropertyChangedEventArgs("ParentID"));
        }
    }

    public ObservableCollection<Products> ChildProducts
    {
        get
        {
            return m_ChildProducts;
        }
        set
        {
            m_ChildProducts = value;
            OnPropertyChanged(new PropertyChangedEventArgs("ChildProducts"));
        }
    }

    //INotifyPropertyChanged Event
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }
}

www.un.org/spanish/ecosoc 采用多种方法,从商品行获取数据:

public static ObservableCollection<Products> GetProductsHierarchy()
    {

        ObservableCollection<Products> productsHierarchy = new ObservableCollection<Products>();

        SqlConnection connection = new SqlConnection(DBConnection.GetConnection().ConnectionString);

        string selectStatement = "SELECT ID, Hierarchy, Name, Hierarchy.GetLevel() AS Level, Hierarchy.GetAncestor(1) AS ParentHierarchy, " +
                                                 "(SELECT ID " +
                                                 "FROM SpecProducts " +
                                                 "WHERE (Hierarchy = SpecProducts_1.Hierarchy.GetAncestor(1))) AS ParentID " +
                                 "FROM  SpecProducts AS SpecProducts_1 " +
                                 "WHERE (EnableDisable IS NULL) " +
                                 "ORDER BY Hierarchy";

        SqlCommand selectCommand = new SqlCommand(selectStatement, connection);

        try
        {
            connection.Open();
            SqlDataReader reader = selectCommand.ExecuteReader();

            while (reader.Read())
            {

                Products product = new Products();
                product.ID = (Int64)reader["ID"];
                product.Name = reader["Name"].ToString();
                product.Hierarchy = (SqlHierarchyId)reader["Hierarchy"];
                product.Level = (Int16)reader["Level"];
                if (reader["ParentID"] != DBNull.Value)
                {
                    product.ParentID = (Int64)reader["ParentID"];
                }
                else
                {
                    product.ParentID = 0;
                }

                productsHierarchy.Add(product);

                // *** HOW TO BUILD HIERARCHY OBJECT WITH UNKNOWN & VARYING LEVELS?
                // *** ADD PRODUCT TO CHILDPRODUCT
            }

            return productsHierarchy;
        }
        catch (SqlException ex)
        {
            throw ex;
        }
        finally
        {
            connection.Close();
        }
    }

Below I have attached an image showing the structure of my SQL Query Data. Please note that the hierarchy level may go deeper when more products are added in the future. The Hierarchy object I need to create should be flexible enough to expand no matter what the number of node levels are.

非常感谢您的时间,我们非常赞赏一切帮助。

“SQL

********* EDIT 26/04/2012 14:37 *******************

Please find below a link to download my project code (this only contains treeview code). Can someone please take a look at it to see why I cannot create nodes beyond 2 levels?

该守则由用户HB MAAM发给我。 感谢你“HB MAAM”迄今提供的帮助。

Click this link to download code

最佳回答

I will create an example for you,
1- first i will create a class that holds the data that comes from the DB

public class SqlDataDto
{
    public int? Id { get; set; }
    public int? ParentId { get; set; }

    public String Name { get; set; }
    public String OtherDataRelatedToTheNode { get; set; }
}

2-数据将转换成等级数据,我们将利用这一类别保存:

public class LocalData : INotifyPropertyChanged
{
    private int? _id;
    public int? Id
    {
        get { return _id; }
        set { _id = value; OnPropertyChanged("Id"); }
    }

    private int? _parentId;
    public int? ParentId
    {
        get { return _parentId; }
        set { _parentId = value; OnPropertyChanged("ParentId"); }
    }

    private string _name;
    public String Name
    {
        get { return _name; }
        set { _name = value; OnPropertyChanged("Name"); }
    }

    private string _otherDataRelatedToTheNode;
    public String OtherDataRelatedToTheNode
    {
        get { return _otherDataRelatedToTheNode; }
        set { _otherDataRelatedToTheNode = value; OnPropertyChanged("OtherDataRelatedToTheNode"); }
    }

    private LocalData _parent;
    public LocalData Parent
    {
        get { return _parent; }
        set { _parent = value; OnPropertyChanged("Parent"); }
    }

    private ObservableCollection<LocalData> _children;
    public ObservableCollection<LocalData> Children
    {
        get { return _children; }
        set { _children = value; OnPropertyChanged("Children"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
        }
    }
}     

3- finally we need to change the sql data to hierarchical one:

public List<LocalData> GetHerachy(List<SqlDataDto> sqlData)
{
    var sqlParents = sqlData.Where(q => q.ParentId == null).ToList();
    var parents = sqlParents.Select(q => new LocalData {Id = q.Id, Name = q.Name}).ToList();
    foreach (var parent in parents)
    {
        var childs = sqlData.Where(q => q.ParentId == parent.Id).Select(q => new LocalData { Id = q.Id, Name = q.Name , Parent = parent});
        parent.Children = new ObservableCollection<LocalData>(childs);
    }
    return parents;
}

4- 之后,你可以生成my数据并转换成树,并在树中显示:

var sqlData = new List<SqlDataDto>
                  {
                      new SqlDataDto {Id = 1, ParentId = null, Name = "F1"}
                      , new SqlDataDto {Id = 2, ParentId = null, Name = "F2"}
                      , new SqlDataDto {Id = 3, ParentId = 1, Name = "S1"}
                      , new SqlDataDto {Id = 4, ParentId = 2, Name = "S21"}
                      , new SqlDataDto {Id = 5, ParentId = 2, Name = "S22"}
                  };
treeView.ItemsSource = GetHerachy(sqlData);

5- the tree should be like:

<TreeView Name="treeView">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>
问题回答

You need to use recursion to fill the Child-List of every object. This is necessary for the WPF HierarchicalDataTemplate to work. Otherwise you only get the first level. There is an alternative using the Linq method ForEach() and passing an Action Argument. The following solution is very straight forward and easy to understand:

public List<Product> Products { get; set; }

public MainViewModel()
{
    Products = new List<Product>();

    Products.Add(new Product() { Id = 1, Name = "Main Product 1", ParentId = 0 });
    Products.Add(new Product() { Id = 3, Name = "Sub Product 1", ParentId = 1 });
    Products.Add(new Product() { Id = 4, Name = "Sub Product 2", ParentId = 1 });
    Products.Add(new Product() { Id = 5, Name = "Sub Product 3", ParentId = 1 });
    Products.Add(new Product() { Id = 6, Name = "Sub Product 3.1", ParentId = 5 });


    this.ProcessRootNodes();
}

private void ProcessRootNodes()
{
    var rootNodes = Products.Where(x => x.ParentId == 0).ToList();

    for (int i = 0; i < rootNodes.Count; i++)
    {
rootNodes[i].Children = this.AddChildren(rootNodes[i]);
    }
}

private List<Product> AddChildren(Product entry)
{
    var children = Products.Where(x => x.ParentId == entry.Id).ToList();

    for(int i=0;i<children.Count;i++)
    {
children[i].Children = this.AddChildren(children[i]);
    }

    return children;
}

www.un.org/spanish/ga/president *** 与UNKNOWN &有关联的问答;

Instead of
ObservableCollection<Products> productsHierarchy = new ObservableCollection<Products>();
use Dictionary<Int64, Products> IdToProduct = new ...

作为贵产品; 采用<代码>IdToproduct[product.ID] = 产品;

然后,查阅填写的<代码>IdToproduct的收集和填写;

if(product.ParentID != 0)
{
    IdToProduct[product.ParentID].ChildProducts.Add(product);
}

现在,你的产品——和;儿童教育关系。

Optionally, add properties to the Products class:
public bool IsCategory { get { return (ChildProducts.Count >= 1); } } // e.g. Oven
public bool IsProduct { get { return !(IsCategory); } } // e.g. Electric (Oven)

现在,你们的看法大多是模式。

article是使用WPF树苗的实际起点。

Hint: a first point for You HierarchicalDataTemplate

<TreeView.ItemTemplate>
    <HierarchicalDataTemplate DataType="{x:Type local:Products}" 
                              ItemsSource="{Binding ChildProducts}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>

You should create a MainViewModel class which has:
public Products RootProduct { get; set; } (notify property changed property)

after you do your SQL parsing and what not; do:
RootProduct = IdToProduct.FirstOrDefault(product => (product.Level == 0));

<TreeView itemsSource="{具有约束力的根基Product.ChildProducts}”>





相关问题
SQL SubQuery getting particular column

I noticed that there were some threads with similar questions, and I did look through them but did not really get a convincing answer. Here s my question: The subquery below returns a Table with 3 ...

难以执行 REGEXP_SUBSTR

I m 查询Oracle 10g。 我有两张表格(样本数据见下文)。 i m 试图提取一些领域

SQL Query Shortcuts

What are some cool SQL shorthands that you know of? For example, something I learned today is you can specify to group by an index: SELECT col1, col2 FROM table GROUP BY 2 This will group by col2

PHP array callback functions for cleaning output

I have an array of output from a database. I am wondering what the cleanest way to filter the values is example array Array ( [0] => Array ( [title] => title 1 ...

OracleParameter and DBNull.Value

we have a table in an Oracle Database which contains a column with the type Char(3 Byte). Now we use a parameterized sql to select some rows with a DBNull.Value and it doesn t work: OracleCommand ...

Running numbers in SQL

I have a SQL-statement like this: SELECT name FROM users WHERE deleted = 0; How can i create a result set with a running number in the first row? So the result would look like this: 1 Name_1 2 ...

How to get SQL queries for each user where env is production

I’m developing an application dedicated to generate statistical reports, I would like that user after saving their stat report they save sql queries too. To do that I wrote the following module: ...

热门标签