Laden...

Wie stelle ich Daten aus der DB als TreeView dar?

Erstellt von Mattes80 vor 3 Jahren Letzter Beitrag vor 3 Jahren 596 Views
M
Mattes80 Themenstarter:in
23 Beiträge seit 2020
vor 3 Jahren
Wie stelle ich Daten aus der DB als TreeView dar?

Hallo

Ich habe mit Dataset eine Tabelle erstellt "Kategorien"

In der Tabelle sind folgende Spalten drin

  • ID Key Schlüssel
  • UnterID Falls es ein Unterknoten sein soll
  • Bezeichnung Name des Knoten

Die UnterID ist so gedacht das hier die ID des Hauptitems steht und da ein Unteritems angelegt wird.

z.b.

("1", "", "Test") das ist ein Hauptitems
("2", "1" "Unter Test") das ist ein Unteritems die zu ID 1 zugeordnet wird
("3", "2" "Unter Unter Test") das ist wieder ein Unteritems die zu ID 2 zugeordnet wird.
("4", "", "Test2") Wieder ein Hauptitems

Diese Sachen sind in Dataset eingetragen und müssen nur noch ausgelesen werden.

Nun zu mein Hauptproblem wie erstellt man zu meinen Beispiel jetzt ein Baumstruktur die in TreeView dann so angezeigt wird?

Es soll ja nicht nur die Bezeichnung übertragen werden sondern auch die ID des Items. Da es vorkommen kann das die Bezeichnung 2 mal gibt.

WPF Code


        <TreeView x:Name="tv" ItemsSource="{Binding Kategorien}" Margin="0,0,499,194">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding UnterID}">
                    <TextBlock Text="{Binding Bezeichnung}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
            <TreeView.DataContext>
                <Datenbank:DataSet1/>
            </TreeView.DataContext>
        </TreeView>

Ich bin mir nicht sicher ob der XAML code richtig ist.

Wie rufe ich diese jetzt in Code Behind ab das es mir richtig angezeigt wird.

Kann mir bitte jemand ein kleines Code Beispiel geben?

Gruß

Mattes

P
441 Beiträge seit 2014
vor 3 Jahren

Wenn du das in der Form binden willst muss die Property "UnterID" ein Objekt zurückgeben, dass dem SubItem entspricht.

Die Schicht, die du beschreibst ist die Datenhaltung (Schlüssel & Fremdschlüssel in einer SQL zum Beispiel). Das, was du aber für die UI brauchst ist eine aufgebaute Datenstruktur. Du musst die Abhängigkeiten auflösen.

Siehe auch: [Artikel] Drei-Schichten-Architektur

M
Mattes80 Themenstarter:in
23 Beiträge seit 2020
vor 3 Jahren

Hallo danke für dein Antwort durch dein Beitrag sind mir Suchbegriffe für google eingefallen und habe dann diese gefunden, das genau so ist wie ich brauche.

https://www.codeproject.com/Articles/5165491/Filling-the-WPF-TreeView-with-Multilevel-Hierarchy

Hab es mir den Code Heruntergeladen und mit VS geöffnet und gestartet. Funktioniert. Aber....

Wenn ich jetzt den Code Kopiere in mein UserControll dann funktioniert diese nicht mehr.

public partial class UserControl1 : UserControl, INotifyPropertyChanged

das INotifyPropertyChanged kann in UserControl nicht erstellt werden.

 <HierarchicalDataTemplate  DataType= "{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}"   >

das {x:Type local:NodeViewModel} NodeViewModel kann nicht gefunden werden obwohl es vorhanden ist.

Was mach ich da Falsch?

M
Mattes80 Themenstarter:in
23 Beiträge seit 2020
vor 3 Jahren

Anbei noch mein Code

c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Test_TreeView
{
    /// <summary>
    /// Interaktionslogik für UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl, INotifyPropertyChanged
    {

        public void NodesFactory(DataTable InptDT, DataTable subDT, long level)
        {


            level = level + 1;


            var querryLevel =
            from itemsInputDT in InptDT.AsEnumerable()
            join itemSub in subDT.AsEnumerable() on itemsInputDT.Field<long>("GparentId") equals itemSub.Field<long>("Gid")
            where itemSub.Field<long>("level") == level - 1

            select new { Gid = itemsInputDT.Field<long>("Gid"), Gname = itemsInputDT.Field<string>("Gname"), GparentId = itemsInputDT.Field<long>("GparentId"), level = level };


            foreach (var x in querryLevel)
            {

                DataRow rowSub = subDT.NewRow();
                rowSub["Gid"] = x.Gid;
                rowSub["Gname"] = x.Gname;
                rowSub["GparentId"] = x.GparentId;
                rowSub["level"] = x.level;
                subDT.Rows.Add(rowSub);

                nodesList.Add(new NodeViewModel { Id = x.Gid, Name = x.Gname, Expand = true, Children = new ObservableCollection<NodeViewModel>() });

                nodesList.Find(gNode => gNode.Id == x.GparentId).Children.Add(nodesList.Last());

            }

            if (querryLevel.Count() > 0)
            { NodesFactory(InptDT, subDT, level); }


        }


        public event PropertyChangedEventHandler PropertyChanged;
        List<NodeViewModel> nodesList = new List<NodeViewModel>();
        TreeViewModel MyTreeModel = new TreeViewModel();



        public UserControl1()
        {
            //generic list comprising  hierarchical data- source to fill TreeViewModel
            List<GIER_Hierarchy> GIER_Hierarchy_List = new List<GIER_Hierarchy>();

            GIER_Hierarchy_List.Add(new GIER_Hierarchy(1, "root", 0));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(2, "Production B", 7));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(12, "Document Control", 17));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(17, "Engineering", 7));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(16, "Executive", 1));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(14, "Facilities and Maintenance", 7));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(10, "Finance", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(9, "Human Resources", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(11, "Information Services", 4));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(4, "Marketing", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(7, "Production", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(8, "Production Control", 7));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(5, "Purchasing", 18));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(13, "Quality Assurance", 7));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(6, "Research and Development", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(3, "Sales", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(15, "Shipping and Receiving", 18));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(19, "Tool Design", 2));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(18, "Logistic", 16));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(20, "Logistic A", 18));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(21, "Logistic A1", 20));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(22, "Logistic A1", 21));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(23, "Logistic A1", 22));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(24, "Logistic A1", 23));
            GIER_Hierarchy_List.Add(new GIER_Hierarchy(25, "Logistic A1", 24));


            if (GIER_Hierarchy_List.Count > 0)
            {

                //datatable to load data from GIER_Hierarchy_List
                DataTable InputDT = new DataTable();
                InputDT.Columns.Add("Gid", typeof(long));
                InputDT.Columns.Add("Gname", typeof(string));
                InputDT.Columns.Add("GparentId", typeof(long));

                //loading the data from  to datable
                foreach (var x in GIER_Hierarchy_List)
                {
                    DataRow rowInput = InputDT.NewRow();
                    rowInput["Gid"] = x.Gid;
                    rowInput["Gname"] = x.Gname;
                    rowInput["GparentId"] = x.GparentId;
                    InputDT.Rows.Add(rowInput);
                }

                //querring the datable to find the row with root as first level of hierachy
                var queryRoot =
                     from itemsInputDT in InputDT.AsEnumerable()
                     where itemsInputDT.Field<long>("GparentId") == 0
                     select new { Gid = itemsInputDT.Field<long>("Gid"), Gname = itemsInputDT.Field<string>("Gname"), GparentId = itemsInputDT.Field<long>("GparentId"), level = 1 };

                //creating auxiliary datatable for iterationaly querying in the subsequent levels of hierarchy
                DataTable sub = new DataTable();
                sub.Columns.Add("Gid", typeof(long));
                sub.Columns.Add("Gname", typeof(string));
                sub.Columns.Add("GparentId", typeof(long));
                sub.Columns.Add("level", typeof(long));

                //looping through the result of the querry to load the result of the query to auxiliary datable and adding nodes to list of nodes 

                foreach (var x in queryRoot)
                {
                    DataRow rowSub = sub.NewRow();
                    rowSub["Gid"] = x.Gid;
                    rowSub["Gname"] = x.Gname;
                    rowSub["GparentId"] = x.GparentId;
                    rowSub["level"] = 0;
                    sub.Rows.Add(rowSub);

                    //creating NodeViewModel and adding to the list of NodeViewModel object list

                    nodesList.Add(new NodeViewModel
                    {
                        Id = x.Gid,
                        Name = x.Gname,
                        Expand = true,
                        Children =

                            new ObservableCollection<NodeViewModel>()
                    });

                }

                //adding Collection of NodeViewModel object with the root to TreeModel

                MyTreeModel.Items = new ObservableCollection<NodeViewModel> { nodesList.Last() };

                long level = 0;


                NodesFactory(InputDT, sub, level);


            }
            else { MessageBox.Show("List of Direcitory is empty"); }


            
            
            InitializeComponent();

            // binding TreeView component with TreeModel
            GIER_catalogHierarchy.ItemsSource = MyTreeModel.Items;
        }
    }

    public class GIER_Hierarchy
    {
        public long Gid { get; set; }
        public string Gname { get; set; }
        public long GparentId { get; set; }


        public GIER_Hierarchy(long xGid, string xGname, long xGparentId)
        {
            this.Gid = xGid;
            this.Gname = xGname;
            this.GparentId = xGparentId;
        }

    }



    public class TreeViewModel
    {
        public ObservableCollection<NodeViewModel> Items { get; set; }

    }

    public class NodeViewModel : INotifyPropertyChanged
    {


        public long Id { get; set; }
        public string _Name;
        public bool _Expand;
        public string Name
        {

            get { return _Name; }

            set
            {

                if (_Name != value)
                {
                    _Name = value;
                    NotifyPropertyChanged("Name");
                }

            }
        }


        public bool Expand
        {
            get { return _Expand; }
            set
            {
                if (_Expand != value)
                {
                    _Expand = value;
                    NotifyPropertyChanged("Expand");
                }
            }
        }


        public ObservableCollection<NodeViewModel> Children { get; set; }


        #region INotifyPropertyChanged Members

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }

}

WPF

<UserControl x:Class="Test_TreeView.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Test_TreeView"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TreeView x:Name="GIER_catalogHierarchy"  BorderThickness="1" 
                  MinWidth="300" MinHeight="440"  Width="Auto"      ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" 
                  Margin="1,1,1,0"  Height="Auto">
            <TreeView.Resources>

                <HierarchicalDataTemplate  DataType= "{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}"   >

                    <Grid >

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition  x:Name="Line" Width="20" />
                            <ColumnDefinition  x:Name="Rectangle" />
                            <ColumnDefinition  x:Name="Empty1" Width="10" />
                            <ColumnDefinition  x:Name="Department" />
                        </Grid.ColumnDefinitions>

                        <!--drawing Connecting Lines -->
                        <!-- Horizontal Lines -->

                        <Border Grid.Column="0"  x:Name="HorLn" Margin="9,0,0,2" HorizontalAlignment="Stretch" Height="1" BorderThickness="0,0,0,1" VerticalAlignment="Bottom">
                            <Border.BorderBrush>
                                <LinearGradientBrush StartPoint="0,0" EndPoint="2,0" SpreadMethod="Repeat" MappingMode="Absolute">
                                    <GradientStop Color="Transparent" Offset="0" />
                                    <GradientStop Color="Transparent" Offset="0.499" />
                                    <GradientStop Color="#999" Offset="0.5" />
                                </LinearGradientBrush>
                            </Border.BorderBrush>
                        </Border>

                        <!-- Vertical Lines -->
                        <Border Grid.Column="0"  x:Name="VerLn" Margin="0,0,1,2" Grid.RowSpan="2" VerticalAlignment="Stretch" Width="1" BorderThickness="0,0,1,0" >
                            <Border.BorderBrush>
                                <LinearGradientBrush StartPoint="0,0" EndPoint="0,2" SpreadMethod="Repeat" MappingMode="Absolute">
                                    <GradientStop Color="Transparent" Offset="0" />
                                    <GradientStop Color="Transparent" Offset="0.499" />
                                    <GradientStop Color="#999" Offset="0.5" />
                                </LinearGradientBrush>
                            </Border.BorderBrush>
                        </Border>

                        <!--drawing catalog shapes-->
                        <Rectangle  Grid.Column="1"    Width="14" Height="10" Stroke="Gold"  SnapsToDevicePixels="true" VerticalAlignment="Center"    >
                            <Rectangle.Fill>
                                <LinearGradientBrush EndPoint="0.5,2" StartPoint="0.5,0">
                                    <GradientStop Color="White" Offset="0"/>
                                    <GradientStop Color="Gold" Offset="0.5"/>
                                    <GradientStop Color="Honeydew" Offset="1"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                        <Rectangle  Grid.Column="1"    Width="7" Height="4" Stroke="Gold"  SnapsToDevicePixels="true" VerticalAlignment="Top" HorizontalAlignment="Left"  Fill="White"  />
                        <!--textblock to display the names of catalogs-->
                        <TextBlock x:Name="textBlockHeader"    Grid.Column="3" Grid.Row="1" Text="{Binding Name}"     FontSize="9"   />
                    </Grid>

                </HierarchicalDataTemplate>
                <!--trriger to expand nodes-->
                <Style TargetType="{x:Type TreeViewItem}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Expand}"  Value="True">
                            <Setter Property="IsExpanded" Value="True"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TreeView.Resources>


        </TreeView>

    </Grid>
</UserControl>

P
441 Beiträge seit 2014
vor 3 Jahren

Entschuldige, wenn ich deinen Code nicht komplett anschaue.

Erstelle ein Minimalbeispiel, an dessen du dir selber klar machst wie das funktioniert.

-> Du hast eine Datenhaltungsklasse (die aus deinem ersten Post)
-> Daraus erstellst du eine Objektstruktur, die anstatt einer UnterID das UnterObjekt hält (im View Model)
-> In der View erstellt du ein HierarchicalTemplate, dass die Root Node/Array deiner Objektstruktur per Datenbindung erhält und deren Kind Objekte an die Kindknoten weitergibt

5.657 Beiträge seit 2006
vor 3 Jahren

Es ist schon sehr merkwürdig, daß dein Control die INotifyPropertyChanged-Schnittstelle implementiert. Wozu meinst du das zu benötigen?

Ansonsten ist es nicht hilfreich, einfach hier den gesamten Code zu posten, und zu hoffen, daß jemand das Problem für dich löst. Besser wäre, wenn du mal beschreibst, wo du Probleme hast, und wo du nicht weiter kommst. Siehe dazu [Hinweis] Wie poste ich richtig?

Es ist nicht so schwierig, ein hierarchisches Datenmodell an einen TreeView zu binden. Dazu sollte man aber die Grundzüge von MVVM verstanden haben. Siehe dazu [Artikel] MVVM und DataBinding

Ein eigenes UserControl ist dafür auch nicht erforderlich, lediglich ein HierarchicalDataTemplate.

Eine Schritt-für-Schritt-Anleitung gibt es hier: Populating Hierarchical Data In TreeView In WPF Using MVVM

Weeks of programming can save you hours of planning