none
TreeView mit mehrere Daten RRS feed

  • Frage

  • Hallo

    Ich bin immer noch dabei den TreeView richtig zu lernen. Den Baumstruktur kann ich jetzt schon sehr gut.

    Ich habe meine Daten für TreeView so geteilt

    TreeView-Nummer

    TreeView-UnterNummer

    TreeView-Name

    Das mein TreeView mit die Daten richtig angezeigt wird funktioniert schon mal sehr gut.

    Nun möchte ich aber das wenn man mit der Linken Maustaste auf ein Konten Klickt. das ein MessageBox erscheint und er mir dann die TreeView_Nummer, TreeView_UnterNummer und den TreeView_Name ausgibt der ausgewählt ist.

    Weiß leider nicht wie ich das anstellen soll.

    Hier schon mal mein Code

    XAML:

    <Window x:Class="TreeView.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:TreeView"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <TreeView ItemsSource="{Binding RootItems}">
                <TreeView.ItemContainerStyle>
                    <Style TargetType="{x:Type TreeViewItem}">
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                        <Setter Property="FontWeight" Value="Normal" />
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
    
                                <Setter Property="FontWeight" Value="ExtraBold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding Row._TreeView_Name}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
    
        </Grid>
    </Window>
    

    CS-Code

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    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;
    
    namespace TreeView
    {
        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            DataSet1 DataSet_TreeView = new DataSet1();
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = this;
                DataSet_TreeView.Data_Treeview.Rows.Add("1", "10", "", "test0");
                DataSet_TreeView.Data_Treeview.Rows.Add("2", "11", "", "test1");
                DataSet_TreeView.Data_Treeview.Rows.Add("3", "12", "10", "test01");
                DataSet_TreeView.Data_Treeview.Rows.Add("1", "13", "12", "test02");
                
                
    
    
                ObservableCollection<Data_Treeview> col = new ObservableCollection<Data_Treeview>();
                foreach (DataRow row in DataSet_TreeView.Tables["Data_Treeview"].Rows) col.Add(new Data_Treeview((DataSet1.Data_TreeviewRow)row));
                cvs.Source = col.Where((d) => d.TreeViewUnterNummer == "");
    
    
    
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
        }
    
    
        public class Data_Treeview
        {
    
            public Data_Treeview(DataSet1.Data_TreeviewRow row) { this.Row = row; this.dt = (DataSet1.Data_TreeviewDataTable)row.Table; this.ds = (DataSet1)row.Table.DataSet; }
    
            DataSet1 ds;
            DataSet1.Data_TreeviewDataTable dt;
    
            public DataSet1.Data_TreeviewRow Row { get; set; }
            public string TreeViewNummer { get => Row._TreeView_Nummer; set { Row._TreeView_Nummer = value; } }
            public string TreeViewUnterNummer { get => Row._TreeView_UnterNummer; set { Row._TreeView_UnterNummer = value; } }
            public string TreeViewName { get => Row._TreeView_Name; set { Row._TreeView_Name = value; } }
            public object ChildrenItems => new ObservableCollection<Data_Treeview>(from d in dt where d._TreeView_UnterNummer == this.TreeViewNummer select new Data_Treeview(d));
    
    
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
    
    
    }
    

    Wäre super wenn mir einer ein kleines Beispiel geben könnte.

    Gruß

    Mezzo

    Dienstag, 10. August 2021 10:47

Antworten

  • Hallo Mezzo,

    man kann im TreeViewItem-Style EventSetter unterbringen. Im C# kannst du im Handler eine MessageBox anzeigen. Dabei kannst du den Tag des 'sender' auswerten:

    <Style TargetType="TreeViewItem">
    	<Setter Property="Tag" Value="{Binding}" />
    	<EventSetter Event="MouseLeftButtonUp" Handler="treeViewItem_MouseLeftButtonUp" />
    </Style>

    private void treeViewItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
            // Achtung!
            // Das Event wird für das Element, auf dem geklickt wurde,
            // und für all seine Parent-Elemente bis einschließlich des Root-Knotens aufgerufen.
            // Diese weiteren Aufrufe können unterbunden werden, indem 'e.Handled = true' gesetzt wird.
    e.Handled = true; Data_Treeview item = (sender as TreeViewItem)?.Tag as Data_Treeview; if (item == null) return; // MessageBox anzeigen... }
    Gruß
    Heiko
    • Bearbeitet Heiko65456465 Dienstag, 10. August 2021 15:37
    • Als Antwort markiert Mezzo80 Samstag, 14. August 2021 10:52
    Dienstag, 10. August 2021 15:28
  • Das SelectionChanged-Ereignis zu verwenden, geht auch.

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { Data_Treeview item = treeStoreDirectories.SelectedItem as Data_Treeview; if (item == null) return; MessageBox.Show("Nummer: " + item.TreeViewNummer);

    }

    • Als Antwort markiert Mezzo80 Sonntag, 15. August 2021 09:42
    Samstag, 14. August 2021 15:13
  • Hallo,

    TreeViewRoot ist der Name des TreeView. Da du in deinem obigen Beispiel folgende Zeile schriebst:

    <TreeView x:Name="TreeViewRoot" ItemsSource="{Binding RootItems}" SelectedItemChanged="TreeView_SelectedItemChanged">

    ... ist innerhalb des MainWindow im C# eine Variable TreeViewRoot vorhanden, über die du auf den TreeView zugreifen kannst.

    Ist TreeViewRoot nicht in deiner MainPage verfügbar, hast dur vermutlich aktuell keinen Namen mehr für den TreeView im XAML vergeben.

    Falls der Name im XAML dennoch vergeben wurde, kannst du mal probiren, das 'x:Name' durch 'Name' zu ersetzen, oder caste den 'sender' zu TreeView:

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
            TreeView treeView = sender as TreeView;
    	Data_Treeview	item = treeView.SelectedItem as Data_Treeview;
    
    	if (item == null)
    		return;
    
    	MessageBox.Show("Nummer: " + item.TreeViewNummer);
    
    }

    Sollte dein TreeView innerhalb einer Auflistung existieren (z.B. als Eintrag in einer ComboBox), kann man nicht mehr über einen eventuell vergebenen Namen auf ihn zugreifen. Dann sollte man den 'sender' im Event-Handler zu TreeView casten.

    Gruß
    Heiko


    • Bearbeitet Heiko65456465 Dienstag, 17. August 2021 12:01
    • Als Antwort markiert Mezzo80 Samstag, 11. September 2021 09:20
    Dienstag, 17. August 2021 11:58

Alle Antworten

  • Hallo Mezzo,

    man kann im TreeViewItem-Style EventSetter unterbringen. Im C# kannst du im Handler eine MessageBox anzeigen. Dabei kannst du den Tag des 'sender' auswerten:

    <Style TargetType="TreeViewItem">
    	<Setter Property="Tag" Value="{Binding}" />
    	<EventSetter Event="MouseLeftButtonUp" Handler="treeViewItem_MouseLeftButtonUp" />
    </Style>

    private void treeViewItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
            // Achtung!
            // Das Event wird für das Element, auf dem geklickt wurde,
            // und für all seine Parent-Elemente bis einschließlich des Root-Knotens aufgerufen.
            // Diese weiteren Aufrufe können unterbunden werden, indem 'e.Handled = true' gesetzt wird.
    e.Handled = true; Data_Treeview item = (sender as TreeViewItem)?.Tag as Data_Treeview; if (item == null) return; // MessageBox anzeigen... }
    Gruß
    Heiko
    • Bearbeitet Heiko65456465 Dienstag, 10. August 2021 15:37
    • Als Antwort markiert Mezzo80 Samstag, 14. August 2021 10:52
    Dienstag, 10. August 2021 15:28
  • Hallo

    Danke für deine Antwort würde das nicht auch mit SelectedItemChanged gehen?

    Ich habe das mal getestet, so kann ich des MouseLeftButtonUp für was anderes verwenden.

    Meine frage ist nun wie lese ich jetzt aus die Variablen den Inhalt aus?

    TreeViewNummer
    TreeViewUnterNummer 
    TreeViewName

    Hier nochmal mein Code wie er jetzt ist.

    XAML:

    <Window x:Class="TreeView.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:TreeView"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <TreeView x:Name="TreeViewRoot" ItemsSource="{Binding RootItems}" SelectedItemChanged="TreeView_SelectedItemChanged">
                <TreeView.ItemContainerStyle>
                    <Style TargetType="{x:Type TreeViewItem}">
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                        <Setter Property="Tag" Value="{Binding}" />
                        <Setter Property="FontWeight" Value="Normal" />
                        
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
    
                                <Setter Property="FontWeight" Value="ExtraBold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <Grid>
                        <TextBlock x:Name="TreeViewTextBlock_Name" Text="{Binding Row._TreeView_Name}" />
                        <TextBlock x:Name="TreeViewTextBlock_Nummer" Text="{Binding Row._TreeView_Nummer}" Visibility="Hidden"/>
                        </Grid>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
    
        </Grid>
    </Window>
    

    C#:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    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;
    
    namespace TreeView
    {
        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            DataSet1 DataSet_TreeView = new DataSet1();
            ObservableCollection<Data_Treeview> col = new ObservableCollection<Data_Treeview>();
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = this;
                DataSet_TreeView.Data_Treeview.Rows.Add("1", "10", "", "test0");
                DataSet_TreeView.Data_Treeview.Rows.Add("2", "11", "", "test1");
                DataSet_TreeView.Data_Treeview.Rows.Add("3", "12", "10", "test01");
                DataSet_TreeView.Data_Treeview.Rows.Add("1", "13", "12", "test02");
                
                
    
    
                
                foreach (DataRow row in DataSet_TreeView.Tables["Data_Treeview"].Rows) col.Add(new Data_Treeview((DataSet1.Data_TreeviewRow)row));
                cvs.Source = col.Where((d) => d.TreeViewUnterNummer == "");
    
    
    
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                
                MessageBox.Show(sender.ToString());
                
            }
        }
    
    
        public class Data_Treeview
        {
    
            public Data_Treeview(DataSet1.Data_TreeviewRow row) { this.Row = row; this.dt = (DataSet1.Data_TreeviewDataTable)row.Table; this.ds = (DataSet1)row.Table.DataSet; }
    
            DataSet1 ds;
            DataSet1.Data_TreeviewDataTable dt;
    
            public DataSet1.Data_TreeviewRow Row { get; set; }
            public string TreeViewNummer { get => Row._TreeView_Nummer; set { Row._TreeView_Nummer = value; } }
            public string TreeViewUnterNummer { get => Row._TreeView_UnterNummer; set { Row._TreeView_UnterNummer = value; } }
            public string TreeViewName { get => Row._TreeView_Name; set { Row._TreeView_Name = value; } }
            public object ChildrenItems => new ObservableCollection<Data_Treeview>(from d in dt where d._TreeView_UnterNummer == this.TreeViewNummer select new Data_Treeview(d));
    
    
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
    
    
    }
    

    Freitag, 13. August 2021 12:02
  • Das SelectionChanged-Ereignis zu verwenden, geht auch.

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { Data_Treeview item = treeStoreDirectories.SelectedItem as Data_Treeview; if (item == null) return; MessageBox.Show("Nummer: " + item.TreeViewNummer);

    }

    • Als Antwort markiert Mezzo80 Sonntag, 15. August 2021 09:42
    Samstag, 14. August 2021 15:13
  • Hallo

    Danke für deine Antwort. Ich habe eine Frage woher kommt das treeStoreDirectories?

    das finde ich bei mir nicht.

    Gruß

    Mezzo

    Sonntag, 15. August 2021 12:40
  • Das ist aus meinem Code. Ersetze es durch TreeViewRoot.
    Sonntag, 15. August 2021 15:12
  • Hallo

    Bei mir gibt das TreeViewRoot auch nicht.

    Nur das TreeView und das TreeViewItems aber bei diese beiden gibt des SelectedItem nicht.

    Gruß

    Mezzo

    Dienstag, 17. August 2021 07:19
  • Hallo,

    TreeViewRoot ist der Name des TreeView. Da du in deinem obigen Beispiel folgende Zeile schriebst:

    <TreeView x:Name="TreeViewRoot" ItemsSource="{Binding RootItems}" SelectedItemChanged="TreeView_SelectedItemChanged">

    ... ist innerhalb des MainWindow im C# eine Variable TreeViewRoot vorhanden, über die du auf den TreeView zugreifen kannst.

    Ist TreeViewRoot nicht in deiner MainPage verfügbar, hast dur vermutlich aktuell keinen Namen mehr für den TreeView im XAML vergeben.

    Falls der Name im XAML dennoch vergeben wurde, kannst du mal probiren, das 'x:Name' durch 'Name' zu ersetzen, oder caste den 'sender' zu TreeView:

    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
            TreeView treeView = sender as TreeView;
    	Data_Treeview	item = treeView.SelectedItem as Data_Treeview;
    
    	if (item == null)
    		return;
    
    	MessageBox.Show("Nummer: " + item.TreeViewNummer);
    
    }

    Sollte dein TreeView innerhalb einer Auflistung existieren (z.B. als Eintrag in einer ComboBox), kann man nicht mehr über einen eventuell vergebenen Namen auf ihn zugreifen. Dann sollte man den 'sender' im Event-Handler zu TreeView casten.

    Gruß
    Heiko


    • Bearbeitet Heiko65456465 Dienstag, 17. August 2021 12:01
    • Als Antwort markiert Mezzo80 Samstag, 11. September 2021 09:20
    Dienstag, 17. August 2021 11:58
  • Hallo

    ich habe nun bei diesen Beispiel ein folgendes Problem und zwar das Aktualisieren.

    Bei Start des Programm wir die Funktion Kategorien geladen hier der Code.

            private void Kategorien_Laden ()
            {
                Tabellekomplett.Kategorie.Clear();
                SQLiteConnection SQLconnect = new SQLiteConnection();
                SQLiteCommand SQLcommand;
                string DBVerzeichnis_Dateiname = Properties.Settings.Default.DatenbankVerzeichnis + "\\DB.sql";
                SQLconnect.ConnectionString = "Data Source=" + DBVerzeichnis_Dateiname + ";";
                SQLconnect.Open();
                SQLcommand = SQLconnect.CreateCommand();
                SQLcommand.CommandText = "SELECT * FROM Kategorie";
                SQLiteDataReader SQLreader = SQLcommand.ExecuteReader();
                while (SQLreader.Read())
                Tabellekomplett.Kategorie.Rows.Add(SQLreader[0], SQLreader[1], SQLreader[2], SQLreader[3]);
                SQLcommand.Dispose();
                SQLconnect.Close();
    
            }

    Beim Programmstart wird es die DB geladen das klappt auch gut. Nun zu mein Problem.

    Ich habe ein WPF Form um eine neue Kategorie hinzufügen. mit dem Klick von Button Speichern wird es in der DB gespeichert und danach wird die DB nochmal neu ausgelesen in das Dataset.

    Aber die neu Ausgelesene Dataset wird nicht neu angezeigt. Es bleibt immer so beim Programm Start.

    Wie kann man das TreeView aktualisieren?

    Gruß

    Mezzo

    Dienstag, 5. Oktober 2021 11:19
  • Hallo,

    wenn dein aktueller Code ähnlich dem von deinem Posting vom 13.08.21 ist, vermute ich, daß 'ChildrenItems' immer wieder neu erzeugt wird. Es wird jedoch nur die erste ChildrenItems-Instanz an die TreeViewItem-ItemsSource gebunden. Deshalb solltest du die erste ChildrenItems-Instanz (ObservableCollection) beibehalten und diese ObservableCollection beim Aktualisieren der Ansicht ebenfalls aktualisieren, statt sie einfach durch eine neue ObservableCollection-Instanz zu ersetzen.

    Alternativ kannst du im C# der TreeView-ItemsSource explzit eine neue ObservableCollection-Instanz zuweisen und damit das Binding von TreeView-ItemsSource umgehen/ausschalten.

    Gruß
    Heiko

    Dienstag, 5. Oktober 2021 14:20
  • Hier mal mein Code

    xaml:

    <Window x:Class="Treeview3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Treeview3"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="643.818">
        <Grid>
            <TreeView x:Name="TreeViewKategorieRoot" HorizontalAlignment="Left" SelectedItemChanged="TreeViewKategorieRoot_SelectedItemChanged" Height="399" Margin="10,10,0,0" VerticalAlignment="Top" Width="284" ItemsSource="{Binding RootItems}">
                <TreeView.ItemContainerStyle>
                    <Style TargetType="{x:Type TreeViewItem}">
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                        <Setter Property="FontWeight" Value="Normal" />
                        <Setter Property="Tag" Value="{Binding}" />
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="FontWeight" Value="ExtraBold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding Row.KategorieName}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <TextBox x:Name="Textbox1" HorizontalAlignment="Left" Height="23" Margin="299,25,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="315"/>
            <Button Content="Speichern" Click="Button_Click_1" HorizontalAlignment="Left" Margin="299,78,0,0" VerticalAlignment="Top" Width="315"/>
            
    
        </Grid>
    </Window>

    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.Shapes;
    
    using System.Data.SQLite;
    
    using System.IO;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Runtime.CompilerServices;
    
    namespace Treeview3
    {
        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
    
            DataSet1 Tabellekomplett = new DataSet1();
            string Selected_KategorieNummer;
            string Selected_UnterKategorieNummer;
            string Selected_KategorieName;
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = this;
    
                Kategorien_Laden();
    
                ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
                foreach (DataRow row in Tabellekomplett.Tables["Kategorie"].Rows) col.Add(new Data_Kategorie((DataSet1.KategorieRow)row));
                cvs.Source = col.Where((d) => d.KategorieUnterNummer == "");
    
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private Data_Kategorie _details = null;
            public Data_Kategorie Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
            #region attached behavior
    
    
            #endregion
    
            #region OnPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
    
            #endregion
    
            private void TreeViewKategorieRoot_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                Data_Kategorie TreeView_item_Selected = TreeViewKategorieRoot.SelectedItem as Data_Kategorie;
                if (TreeView_item_Selected == null)
                    return;
    
                Selected_KategorieNummer = TreeView_item_Selected.KategorieNummer;
                Selected_UnterKategorieNummer = TreeView_item_Selected.KategorieUnterNummer;
                Selected_KategorieName = TreeView_item_Selected.KategorieName;
                MessageBox.Show("Nummer: " + TreeView_item_Selected.KategorieNummer);
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                SQLiteConnection connect = new SQLiteConnection();
                string DBVerzeichnis_Dateiname = "DB.sql";
                connect.ConnectionString = "Data Source=" + DBVerzeichnis_Dateiname + ";";
                connect.Open();
                connect.Close();
    
                SQLiteCommand command;
    
                connect.Open();
                command = connect.CreateCommand();
                command.CommandText = "CREATE TABLE Kategorie(id INTEGER PRIMARY KEY AUTOINCREMENT, KategorieNummer VARCHAR(250), KategorieUnterNummer VARCHAR(250), KategorieName VARCHAR(250));";
                command.ExecuteNonQuery();
                command.Dispose();
                connect.Close();
    
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                string KategorieUnterNummer;
                string KategorieName = Textbox1.Text;
                
                DateTime InNummer = DateTime.Now;
    
                string Jahr = InNummer.Year.ToString();
                string Mon = InNummer.Month.ToString().PadLeft(2, '0');
                string tag = InNummer.Day.ToString().PadLeft(2, '0');
                string Stu = InNummer.Hour.ToString().PadLeft(2, '0');
                string Min = InNummer.Minute.ToString().PadLeft(2, '0');
                string Sek = InNummer.Second.ToString().PadLeft(2, '0');
                string mse = InNummer.Millisecond.ToString().PadLeft(3, '0');
    
                string KategorieNummer = "Kat" + Jahr + Mon + tag + Stu + Min + Sek + mse;
    
    
                if (Selected_KategorieNummer == "")
                {
                    KategorieUnterNummer = "";
                } else
                {
                    KategorieUnterNummer = Selected_KategorieNummer;
                }
    
    
                SQLiteConnection connect = new SQLiteConnection();
                connect.ConnectionString = "Data Source=DB.sql;";
                SQLiteCommand command;
                connect.Open();
                command = connect.CreateCommand();
                command.CommandText = "INSERT INTO Kategorie (KategorieNummer, KategorieUnterNummer, KategorieName) VALUES ('" + KategorieNummer + "', '" + KategorieUnterNummer + "', '" + KategorieName + "')";
                command.ExecuteNonQuery();
                command.Dispose();
                connect.Close();
    
                Kategorien_Laden();
    
    
            }
    
            private void Kategorien_Laden()
            {
                Tabellekomplett.Kategorie.Clear();
                SQLiteConnection SQLconnect = new SQLiteConnection();
                SQLiteCommand SQLcommand;
                string DBVerzeichnis_Dateiname = "db.sql";
                SQLconnect.ConnectionString = "Data Source=" + DBVerzeichnis_Dateiname + ";";
                SQLconnect.Open();
                SQLcommand = SQLconnect.CreateCommand();
                SQLcommand.CommandText = "SELECT * FROM Kategorie";
                SQLiteDataReader SQLreader = SQLcommand.ExecuteReader();
                while (SQLreader.Read())
                    Tabellekomplett.Kategorie.Rows.Add(SQLreader[0], SQLreader[1], SQLreader[2], SQLreader[3]);
                SQLcommand.Dispose();
                SQLconnect.Close();
    
            }
    
    
        }
    
    
        public class Data_Kategorie
        {
    
            public Data_Kategorie(DataSet1.KategorieRow row) { this.Row = row; this.dt = (DataSet1.KategorieDataTable)row.Table; this.ds = (DataSet1)row.Table.DataSet; }
            DataSet1 ds;
    
            DataSet1.KategorieDataTable dt;
    
            public DataSet1.KategorieRow Row { get; set; }
            public string KategorieNummer { get => Row.KategorieNummer; set { Row.KategorieNummer = value; } }
            public string KategorieUnterNummer { get => Row.KategorieUnterNummer; set { Row.KategorieUnterNummer = value; } }
            public string KategorieName { get => Row.KategorieName; set { Row.KategorieName = value; } }
            public object ChildrenItems => new ObservableCollection<Data_Kategorie>(from d in dt where d.KategorieUnterNummer == this.KategorieNummer select new Data_Kategorie(d));
    
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
    
    
    }
    

    Der TreeView wird bei mir nicht Aktuallisiert wenn man auf dem Button Clickt.

    Gruß

    Mezzo

    Mittwoch, 6. Oktober 2021 11:54
  • Hallo,

    im ctor weist du cvs.Source eine temporär erzeugte Enumeration zu. Stattdessen solltest du eine ObservableCollection-Instanz zuweisen, die du dir in einer Klassenvariablen merkst. Später kannst dur dieser ObservableCollection-Instanz weitere Root-Elemente (Typ Data_Kategorie) hinzufügen. Etwa so:

    public MainWindow()
    {
    	//...
    	ObservableCollection<Data_Kategorie> MyRootItems = new ObservableCollection<Data_Kategorie>();
    
    	foreach (DataRow row in Tabellekomplett.Tables["Kategorie"].Rows)
    	{
    		if (KategorieUnterNummer == "")
    			MyRootItems.Add(new Data_Kategorie((DataSet1.KategorieRow)row));
    	}
    	cvs.Source = MyRootItems;
    }
    
    private void Kategorien_Laden()
    {
    	//...
    	while (SQLreader.Read())
    	{
    		Tabellekomplett.Kategorie.Rows.Add(SQLreader[0], SQLreader[1], SQLreader[2], SQLreader[3]);
    		var row = Tabellekomplett.Kategorie.Rows[Tabellekomplett.Kategorie.Rows.Count - 1];
    		MyRootItems.Add(new Data_Kategorie((DataSet1.KategorieRow)row));
    	}
    	//...
    }
    Gruß
    Heiko
    Donnerstag, 7. Oktober 2021 11:46
  • Hallo

    Danke jetzt wird es zwar gleich Aktualiert aber die unterknoten stimmen nicht mehr. Es wird einfach in einer Reiche angezeigt.

    xaml:

    <Window x:Class="Treeview3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Treeview3"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="643.818">
        <Grid>
            <TreeView x:Name="TreeViewKategorieRoot" HorizontalAlignment="Left" SelectedItemChanged="TreeViewKategorieRoot_SelectedItemChanged" Height="399" Margin="10,10,0,0" VerticalAlignment="Top" Width="284" ItemsSource="{Binding RootItems}">
                <TreeView.ItemContainerStyle>
                    <Style TargetType="{x:Type TreeViewItem}">
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                        <Setter Property="FontWeight" Value="Normal" />
                        <Setter Property="Tag" Value="{Binding}" />
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="FontWeight" Value="ExtraBold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding Row.KategorieName}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <TextBox x:Name="Textbox1" HorizontalAlignment="Left" Height="23" Margin="299,25,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="315"/>
            <Button Content="Speichern" Click="Button_Click_1" HorizontalAlignment="Left" Margin="299,78,0,0" VerticalAlignment="Top" Width="315"/>
            
    
        </Grid>
    </Window>
    

    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.Shapes;
    
    using System.Data.SQLite;
    
    using System.IO;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Runtime.CompilerServices;
    
    namespace Treeview3
    {
        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            //ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
            ObservableCollection<Data_Kategorie> MyRootItems = new ObservableCollection<Data_Kategorie>();
            DataSet1 Tabellekomplett = new DataSet1();
            string Selected_KategorieNummer;
            string Selected_UnterKategorieNummer;
            string Selected_KategorieName;
            string KategorieUnterNummer;
            public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = this;
    
                Kategorien_Laden();
    
                foreach (DataRow row in Tabellekomplett.Tables["Kategorie"].Rows)
                {
                    if (KategorieUnterNummer == "")
                        MyRootItems.Add(new Data_Kategorie((DataSet1.KategorieRow)row));
                }
                cvs.Source = MyRootItems;
    
    
    
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private Data_Kategorie _details = null;
            public Data_Kategorie Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
            #region attached behavior
    
    
            #endregion
    
            #region OnPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
    
            #endregion
    
            private void TreeViewKategorieRoot_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                Data_Kategorie TreeView_item_Selected = TreeViewKategorieRoot.SelectedItem as Data_Kategorie;
                if (TreeView_item_Selected == null)
                    return;
    
                Selected_KategorieNummer = TreeView_item_Selected.KategorieNummer;
                Selected_UnterKategorieNummer = TreeView_item_Selected.KategorieUnterNummer;
                Selected_KategorieName = TreeView_item_Selected.KategorieName;
                MessageBox.Show("Nummer: " + TreeView_item_Selected.KategorieNummer);
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                SQLiteConnection connect = new SQLiteConnection();
                string DBVerzeichnis_Dateiname = "DB.sql";
                connect.ConnectionString = "Data Source=" + DBVerzeichnis_Dateiname + ";";
                connect.Open();
                connect.Close();
    
                SQLiteCommand command;
    
                connect.Open();
                command = connect.CreateCommand();
                command.CommandText = "CREATE TABLE Kategorie(id INTEGER PRIMARY KEY AUTOINCREMENT, KategorieNummer VARCHAR(250), KategorieUnterNummer VARCHAR(250), KategorieName VARCHAR(250));";
                command.ExecuteNonQuery();
                command.Dispose();
                connect.Close();
    
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                
                string KategorieName = Textbox1.Text;
                
                DateTime InNummer = DateTime.Now;
    
                string Jahr = InNummer.Year.ToString();
                string Mon = InNummer.Month.ToString().PadLeft(2, '0');
                string tag = InNummer.Day.ToString().PadLeft(2, '0');
                string Stu = InNummer.Hour.ToString().PadLeft(2, '0');
                string Min = InNummer.Minute.ToString().PadLeft(2, '0');
                string Sek = InNummer.Second.ToString().PadLeft(2, '0');
                string mse = InNummer.Millisecond.ToString().PadLeft(3, '0');
    
                string KategorieNummer = "Kat" + Jahr + Mon + tag + Stu + Min + Sek + mse;
    
    
                if (Selected_KategorieNummer == "")
                {
                    KategorieUnterNummer = "";
                } else
                {
                    KategorieUnterNummer = Selected_KategorieNummer;
                }
    
    
                SQLiteConnection connect = new SQLiteConnection();
                connect.ConnectionString = "Data Source=DB.sql;";
                SQLiteCommand command;
                connect.Open();
                command = connect.CreateCommand();
                command.CommandText = "INSERT INTO Kategorie (KategorieNummer, KategorieUnterNummer, KategorieName) VALUES ('" + KategorieNummer + "', '" + KategorieUnterNummer + "', '" + KategorieName + "')";
                command.ExecuteNonQuery();
                command.Dispose();
                connect.Close();
    
                Kategorien_Laden();
    
    
            }
    
            private void Kategorien_Laden()
            {
                Tabellekomplett.Kategorie.Clear();
                SQLiteConnection SQLconnect = new SQLiteConnection();
                SQLiteCommand SQLcommand;
                string DBVerzeichnis_Dateiname = "db.sql";
                SQLconnect.ConnectionString = "Data Source=" + DBVerzeichnis_Dateiname + ";";
                SQLconnect.Open();
                SQLcommand = SQLconnect.CreateCommand();
                SQLcommand.CommandText = "SELECT * FROM Kategorie";
                SQLiteDataReader SQLreader = SQLcommand.ExecuteReader();
    
                MyRootItems.Clear();
                while (SQLreader.Read())
                {
                    Tabellekomplett.Kategorie.Rows.Add(SQLreader[0], SQLreader[1], SQLreader[2], SQLreader[3]);
                    var row = Tabellekomplett.Kategorie.Rows[Tabellekomplett.Kategorie.Rows.Count - 1];
                    MyRootItems.Add(new Data_Kategorie((DataSet1.KategorieRow)row));
                }
                    //Tabellekomplett.Kategorie.Rows.Add(SQLreader[0], SQLreader[1], SQLreader[2], SQLreader[3]);
                SQLcommand.Dispose();
                SQLconnect.Close();
    
                //col.Clear();
                //foreach (DataRow row in Tabellekomplett.Tables["Kategorie"].Rows) col.Add(new Data_Kategorie((DataSet1.KategorieRow)row));
                //cvs.Source = col.Where((d) => d.KategorieUnterNummer == "");
    
            }
    
    
        }
    
    
        public class Data_Kategorie
        {
    
            public Data_Kategorie(DataSet1.KategorieRow row) { this.Row = row; this.dt = (DataSet1.KategorieDataTable)row.Table; this.ds = (DataSet1)row.Table.DataSet; }
            DataSet1 ds;
    
            DataSet1.KategorieDataTable dt;
    
            public DataSet1.KategorieRow Row { get; set; }
            public string KategorieNummer { get => Row.KategorieNummer; set { Row.KategorieNummer = value; } }
            public string KategorieUnterNummer { get => Row.KategorieUnterNummer; set { Row.KategorieUnterNummer = value; } }
            public string KategorieName { get => Row.KategorieName; set { Row.KategorieName = value; } }
            public object ChildrenItems => new ObservableCollection<Data_Kategorie>(from d in dt where d.KategorieUnterNummer == this.KategorieNummer select new Data_Kategorie(d));
    
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
    
    
    }
    

    Wie mach ich es wieder das die Anordnung von die Unterknoten wieder Richtig sind.

    Gruß

    Mezzo

    Freitag, 8. Oktober 2021 07:52
  • Hallo,

    die ObservableCollection, die du in der Klasse Data_Kategorie erzeugst, mußt du dir in einer Variablen merken, damit du ihr später Unterkategorien hinzufügen kannst.

    Über das TreeViewKategorieRoot.SelectedItem kommst du an die aktuelle Data_Kategorie heran und fügst dieser eine neue Unterkategorie hinzu.

    public class Data_Kategorie
    {
    	public ObservableCollection<Data_Kategorie>	ChildrenItems { get; private set; }
    
    	public Data_Kategorie(DataSet1.KategorieRow row)
    	{
    		this.Row = row;
    		this.dt = (DataSet1.KategorieDataTable)row.Table;
    		this.ds = (DataSet1)row.Table.DataSet;
    		ChildrenItems = new ObservableCollection<Data_Kategorie>(from d in dt where d.KategorieUnterNummer == this.KategorieNummer select new Data_Kategorie(d));
    	}
    
    	internal void AddUnterkategorie(DataSet1.KategorieRow row)
    	{
    		ChildrenItems.Add(new Data_Kategorie(row));
    	}
    }
    
    public partial class MainWindow : Window
    {
    	private void button_Click()
    	{
    		// Erzeugen einer neuen Row.
    
    		(TreeViewKategorieRoot.SelectedItem as Data_Kategorie).AddUnterkategorie(newRow);
    	}
    }
    Gruß
    Heiko

    Freitag, 8. Oktober 2021 17:49
  • Hallo

    Leider funktioniert dein Beispiel nicht.

    Das public Data_Kategorie(DataSet1......) wird mir rot unterstrichen.

    Gruß

    Mezzo

    Dienstag, 12. Oktober 2021 08:14
  • Hallo,

    ich habe den ctor (public Data_Kategorie(DataSet1.KategorieRow row)) aus deinem Code kopiert. Wenn es rot unterstrichen wird, wird sicher auch eine Fehlermeldung dazu ausgegeben, vom Compiler und/oder Intellisense, wenn man die Maus auf die rote Linie bewegt.

    Gruß
    Heiko

    Dienstag, 12. Oktober 2021 13:56
  • Hallo

    Kann mir jemand eine einfachere Lösung für TreeView geben? 

    dieses Beispiel funktioniert nicht richtig und ist schon sehr komplex.

    Gruß

    Mezzo

    Dienstag, 16. November 2021 12:41
  • Hi Mezzo,
    ich habe den Thread mehrmals gelesen und nicht verstanden, was die von dir gewünschte einfache Lösung machen soll.

    Die erste Frage ist, warum nutzt du nicht EF sondern das DataSet.

    Die zweite Frage ist, wie soll die Hierarchie aussehen auf Basis der Datenbankdaten.

    Die dritte Frage ist, warum nutzt du nicht eine übersichtlichere Programmierung wie z.B. das MVVM Entwurfsmuster.

    Hier mal ein ganz einfaches Beispiel, wie ich deine Daten verstanden habe:

    <Window x:Class="WpfApp1.Window084"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp084"
            mc:Ignorable="d"
            Title="Window084" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <TreeView ItemsSource="{Binding RootItems}">
          <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding KategorieName}"/>
            </HierarchicalDataTemplate>
          </TreeView.Resources>
        </TreeView>
      </Grid>
    </Window>
    

    Und dazu die Klassen:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApp084
    {
      public class ViewModel
      {
        public ViewModel() => cvs.Source = (new Model()).GetData();
    
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
      }
    
      internal class Model
      {
        internal ObservableCollection<Data_Kategorie> GetData()
        {
          ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
    
          Data_Kategorie level1;
          Data_Kategorie level2;
          Data_Kategorie level3;
    
          level1 = new Data_Kategorie() { KategorieName = "test0" };
          col.Add(level1);
          level2 = new Data_Kategorie() { KategorieName = "test01" };
          level1.ChildrenItems.Add(level2);
          level3 = new Data_Kategorie() { KategorieName = "test001" };
          level2.ChildrenItems.Add(level3);
          level1 = new Data_Kategorie() { KategorieName = "test1" };
          col.Add(level1);
          return col;
        }
      }
    
      public class Data_Kategorie
      {
        public string KategorieNummer { get; set; }
        public string KategorieUnterNummer { get; set; }
        public string KategorieName { get; set; }
        public ObservableCollection<Data_Kategorie> ChildrenItems { get; set; } = new ObservableCollection<Data_Kategorie>();
        public bool IsExpanded { get; set; } = true;
        public bool IsSelected { get; set; }
      }
    }
    

    Ergebnis:


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    Dienstag, 16. November 2021 17:18
  • Hallo

    Danke Peter, durch dein Beispiel ist mir mehr klar geworden.

    Aber ich sehe auch das dein Beispiel Level erhält.

    Level1 = Root

    Level2 = 1. Unterknoten

    Level3 = 2. Unterknoten

    Daraus verstehe ich das nur max 2 unterknoten erstellt werden kann.

    Bei meinen Beispiel soll der Unterknoten bei dem KategorieNummer eingefügt werden. des könnte auch des 20. Unterknoten sein.

    • Die erste Frage ist, warum nutzt du nicht EF sondern das DataSet

    Du hast recht mir hat persönlich das DataSet gefallen aber nach der seit hab ich gemerkt das DataSet nicht mehr wichtig ist. 

    • Die zweite Frage ist, wie soll die Hierarchie aussehen auf Basis der Datenbankdaten.

    In der Datenbank ist es so gespeichert KategorieNummer (das ist die Hauptnummer die jede Kategorie bekomme ob Root oder unterknoten), in KategorieUnterNummer (Hier wird die Nummer gespeichert die darüber ist wenn der eintrag Leer ist dann ist ein ein Hauptknoten) z.b.

    "100", "", "Hauptknoten"

    "101", "100", "Unterknoten 1 zum Hauptknoten"

    "102", "100", "Unterknoten 2 zum Hauptknoten"

    "103", "101", "Unterknoten 3 zum Unterknoten 1"

    "104", "103", "Unterknoten 4 zum Unterknoten 3"

    usw. das geht unändlich.

    • Die dritte Frage ist, warum nutzt du nicht eine übersichtlichere Programmierung wie z.B. das MVVM Entwurfsmuster.

    Ich habe gerade in NuGet Manager geschauft und MVVM eingegeben da gibt es so viele. Welches sollte man dafür nehmen?

    Ich habe schon öfter MVVM gelesen aber verstehe nicht richtig wür was man das überhaupt braucht. ist es dann leichter zu erstellen? wird da schon fertige codes vorgeschrieben? ich bin kein fan von Fertige vorlagen da es immer auch sachen drin sind die man nicht braucht.

    Peter: Kannst du mir bitte ein Beispiel geben nicht auf Level sonder mit die Nummern. und wenn man in TreeView ein Knoten Markiert das ein Messenbox auf geht und mit dann die KategorieNummer, KategorieUnterNummer und KategorieName anzeigt.

    Danke im Vorraus.

    Gruß

    Mezzo

    Mittwoch, 17. November 2021 07:22
  • Hi Mezzo,
    du kann beliebig viele Knotenebenen nutzen. Mein Beispiel war nur auf 3 Ebenen begrenzt, um das Prinzip zu zeigen.

    Für die variable Hierarchie habe ich mal eine Demo mit zufällig generierten Demo-Daten erstellt:

    <Window x:Class="WpfApp1.Window085"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp085"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="Mezzo 17.11.21" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <TreeView ItemsSource="{Binding RootItems}">
          <i:Interaction.Behaviors>
            <local:TreeViewBehavior/>
          </i:Interaction.Behaviors>
          <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding KategorieName}"/>
            </HierarchicalDataTemplate>
          </TreeView.Resources>
        </TreeView>
      </Grid>
    </Window>

    Und der Code dazu:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Interactivity;
    
    namespace WpfApp085
    {
      public class ViewModel
      {
        public ViewModel() => cvs.Source = (new Model()).GetData(0);
    
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
    
        public Data_Kategorie Detail { set { MessageBox.Show($"KategorieNummer: {value.KategorieNummer}\nKategorieUnterNummer: {value.KategorieUnterNummer}\nKategorieName: {value.KategorieName}"); } }
      }
    
      internal class Model
      {
        public Model()
        {
          // Demo-Daten erzeugen
          Random rnd = new Random();
          for (int i = 100; i < 1000; i++) col.Add(new Data_Kategorie(col)
          {
            KategorieNummer = i,
            KategorieUnterNummer = (rnd.NextDouble() > .5) ? 0 : rnd.Next(100, i),
            KategorieName = $"Node {i}"
          });
        }
    
        // Datenspeicher
        internal ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
    
        // Sicht für Root-Level
        internal ObservableCollection<Data_Kategorie> GetData(int levelID) =>
          new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == 0));
      }
    
      public class Data_Kategorie
      {
        public Data_Kategorie(ObservableCollection<Data_Kategorie> data) => col = data;
        private ObservableCollection<Data_Kategorie> col;
        public int KategorieNummer { get; set; }
        public int KategorieUnterNummer { get; set; }
        public string KategorieName { get; set; }
        public ObservableCollection<Data_Kategorie> ChildrenItems { get => new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == this.KategorieNummer)); }
        public bool IsExpanded { get; set; } = true;
        public bool IsSelected { get; set; }
      }
    
      public class TreeViewBehavior : Behavior<TreeView>
      {
        protected override void OnAttached() => AssociatedObject.SelectedItemChanged += AssociatedObject_SelectedItemChanged;
    
        private void AssociatedObject_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
          var tv = sender as TreeView;
          if (tv == null) return;
          var vm = tv.DataContext as ViewModel;
          if (vm == null) return;
          vm.Detail = tv.SelectedItem as Data_Kategorie;
        }
      }
    }

    Die Demo habe ich mit dem MVVM Entwurfsmuster erstellt. Die Grundidee von MVVM besteht in WPF darin, dass Sicht und Code vollständig getrennt werden, d.h. in der Sicht gibt es keinen CodeBehind. Es werden lediglich Eigenschaftsbindung, Befehlsbindung und angehängtes Verhalten (attached behavior) genutzt. Irgendwelche fertigen Codes (Frameworks) sind dafür nicht erforderlich. Für das angehängte Verhalten bietet sich die Nutzung der interactivity-dll aus Nuget an. Damit entfällt die Notwendigkeit der Programmierung von DependencProperties im ViewModel.

    Das Ergebnis kann dann so aussehen:


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Mittwoch, 17. November 2021 08:25
  • Hallo

    Ich habe Ihre beispiel mal bei mir eingefügt aber in WPF wird mir das local:ViewModel und das local:TreeViewBehavior blau unterstrichen und kann es nicht ausführen.

    Es wird gesagt das es nicht gefunden werden kann.

    Hier mein code

    XAML:

    <Window x:Class="Treeview3.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Treeview3"
            mc:Ignorable="d"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            Title="MainWindow" Height="450" Width="643.818">
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <TreeView ItemsSource="{Binding RootItems}">
                <i:Interaction.Behaviors>
                    <local:TreeViewBehavior/>
                </i:Interaction.Behaviors>
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding KategorieName}"/>
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </Grid>
    </Window>
    

    ViewModel.cs

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Interactivity;
    
    namespace Treeview3
    {
        public class ViewModel
        {
            public ViewModel() => cvs.Source = (new Model()).GetData(0);
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            public Data_Kategorie Detail { set { MessageBox.Show($"KategorieNummer: {value.KategorieNummer}\nKategorieUnterNummer: {value.KategorieUnterNummer}\nKategorieName: {value.KategorieName}"); } }
        }
    
        internal class Model
        {
            public Model()
            {
                // Demo-Daten erzeugen
                Random rnd = new Random();
                for (int i = 100; i < 1000; i++) col.Add(new Data_Kategorie(col)
                {
                    KategorieNummer = i,
                    KategorieUnterNummer = (rnd.NextDouble() > .5) ? 0 : rnd.Next(100, i),
                    KategorieName = $"Node {i}"
                });
            }
    
            // Datenspeicher
            internal ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
    
            // Sicht für Root-Level
            internal ObservableCollection<Data_Kategorie> GetData(int levelID) =>
              new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == 0));
        }
    
        public class Data_Kategorie
        {
            public Data_Kategorie(ObservableCollection<Data_Kategorie> data) => col = data;
            private ObservableCollection<Data_Kategorie> col;
            public int KategorieNummer { get; set; }
            public int KategorieUnterNummer { get; set; }
            public string KategorieName { get; set; }
            public ObservableCollection<Data_Kategorie> ChildrenItems { get => new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == this.KategorieNummer)); }
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
        public class TreeViewBehavior : Behavior<TreeView>
        {
            protected override void OnAttached() => AssociatedObject.SelectedItemChanged += AssociatedObject_SelectedItemChanged;
    
            private void AssociatedObject_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                var tv = sender as TreeView;
                if (tv == null) return;
                var vm = tv.DataContext as ViewModel;
                if (vm == null) return;
                vm.Detail = tv.SelectedItem as Data_Kategorie;
            }
        }
    }
    

    Was ist bei mir falsch?

    Gruß

    Mezzo

    Samstag, 20. November 2021 06:51
  • Hi Mezzo,
    C# ist case-sensitive. Bitte nutze die Bezeichner aus meinem Code unverändert!

    Dein Code erkennt nicht den Namensraum "TreeView3", weil du ihn "Treeview3" genannt hast.


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Samstag, 20. November 2021 08:36
  • Hallo

    Danke jetzt funktioniert es.

    Jetzt noch eine Frage und zwar mit der Sortierung.

    Ich habe mir gedacht das ich noch eine Variande dazu mache wo dann die Reihenfolge gespeichert wird.

    • KategorieNummer
    • KategorieUnterNummer
    • KategorieName
    • KategorieReihenfolge

    Wie würde das dann funktionieren?

    Gruß

    Mezzo

    Samstag, 20. November 2021 11:14
  • Hier mein Code

    XAML:

    <Window x:Class="TreeView4.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            xmlns:local="clr-namespace:TreeView4"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <TreeView ItemsSource="{Binding RootItems}" Margin="0,0,530,0">
                <i:Interaction.Behaviors>
                    <local:TreeViewBehavior/>
                </i:Interaction.Behaviors>
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding KategorieName}"/>
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </Grid>
    </Window>
    

    C#

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Interactivity;
    
    namespace TreeView4
    {
        public class ViewModel
        {
            public ViewModel() => cvs.Source = (new Model()).GetData(0);
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            public Data_Kategorie Detail { set { MessageBox.Show($"KategorieNummer: {value.KategorieNummer}\nKategorieUnterNummer: {value.KategorieUnterNummer}\nKategorieName: {value.KategorieName}"); } }
        }
    
        internal class Model
        {
            public Model()
            {
                // Demo-Daten erzeugen
                Random rnd = new Random();
                for (int i = 100; i < 110; i++) col.Add(new Data_Kategorie(col)
                {
                    KategorieNummer = i,
                    KategorieUnterNummer = (rnd.NextDouble() > .5) ? 0 : rnd.Next(100, i),
                    KategorieName = $"Node {i}",
                    KategorieReihenfolge = i
                });
    
                col.Add(new Data_Kategorie(col)
                {
                    KategorieNummer=10,
                    KategorieUnterNummer=0,
                    KategorieName="Hallo",
                    KategorieReihenfolge=10
                }
                    );
            }
    
            // Datenspeicher
            internal ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
    
            // Sicht für Root-Level
            internal ObservableCollection<Data_Kategorie> GetData(int levelID) =>
              new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == 0));
        }
    
        public class Data_Kategorie
        {
            public Data_Kategorie(ObservableCollection<Data_Kategorie> data) => col = data;
            private ObservableCollection<Data_Kategorie> col;
            public int KategorieNummer { get; set; }
            public int KategorieUnterNummer { get; set; }
            public string KategorieName { get; set; }
            public int KategorieReihenfolge { get; set; }
            public ObservableCollection<Data_Kategorie> ChildrenItems { get => new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == this.KategorieNummer)); }
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
        public class TreeViewBehavior : Behavior<TreeView>
        {
            protected override void OnAttached() => AssociatedObject.SelectedItemChanged += AssociatedObject_SelectedItemChanged;
    
            private void AssociatedObject_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                var tv = sender as TreeView;
                if (tv == null) return;
                var vm = tv.DataContext as ViewModel;
                if (vm == null) return;
                vm.Detail = tv.SelectedItem as Data_Kategorie;
            }
        }
    }

    Gruß

    Mezzo

    Samstag, 20. November 2021 11:28
  • Hi,
    füge einfach eine SortDescription hinzu.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Samstag, 20. November 2021 14:52
  • Hallo

    Wie und wo muss ich das SortDescription einfügen?

    geht das nicht in xaml?

    gruß

    Mezzo

    Sonntag, 21. November 2021 10:01
  • Hi Mezzo,
    das kann man im XAML oder im Code machen, z.B. in meiner Demo im Constructor des ViewModels:

        public ViewModel()
        {
          cvs.Source = (new Model()).GetData(0);
          cvs.SortDescriptions.Add(new SortDescription("KategorieNummer", ListSortDirection.Ascending));
        }



    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Sonntag, 21. November 2021 12:56
  • Hallo

    Cool und Danke Peter jetzt hab ich daraus auch gleich 2 sachen gelernt.

    Ich hatte vorher nicht verstanden warum das => stehen soll jetzt weiß ich das

    public ViewModel() => cvs.Source = (new Model()).GetData(0);

    das ersetzt die { } und ich kann damit die funktion verkürzen wenn es nur 1 befehl ist. super danke.

    Jetzt wäre es noch Super wie das verschieben der Noden mit der Maus funktioniert. So das man die Anordnung mit der Maus verschieben kann und das es sich die Reihenvolge auch in Variable KategorieReihenfolge verändert.

    Kannst du mir da auch ein Beispiel geben wie man es mit Drag and Drop es lösen kann?

    Gruß

    Mezzo

    Sonntag, 21. November 2021 20:44
  • Hi Mezzo,
    das Verschieben der Knoten im TreeView ist recht trivial. Vorher ist aber zu definieren, wie die Verschiebetechnologie zu funktionieren hat.

    1. Wie auf ersten Platz verschieben?

    2. Wie nach einem Knoten zu platzieren?

    3. Wie in Unterknoten einordnen?

    Der prinzipielle Code sieht so aus:

    public class DragDropBehavior : Behavior<UIElement> { protected override void OnAttached() { AssociatedObject.PreviewMouseLeftButtonDown += PreviewMouseLeftButtonDown; AssociatedObject.Drop += Tv_Drop; } private void PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (sender is TreeView) { TreeView dragSource = sender as TreeView; object data = GetDataFromTreeView(dragSource, e.GetPosition(AssociatedObject)); if (data != null) DragDrop.DoDragDrop(dragSource, data, DragDropEffects.Move); } } private static object GetDataFromTreeView(TreeView source, Point point) { UIElement element = source.InputHitTest(point) as UIElement; if (element != null) { object data = DependencyProperty.UnsetValue; while (data == DependencyProperty.UnsetValue) { data = source.ItemContainerGenerator.ItemFromContainer(element); if (data == DependencyProperty.UnsetValue) element = VisualTreeHelper.GetParent(element) as UIElement; if (element == source) return null; } if (data != DependencyProperty.UnsetValue) return data; } return null; } private void Tv_Drop(object sender, DragEventArgs e) { if (sender is TreeView) { e.Effects = DragDropEffects.None; e.Handled = true; // Verify that this is a valid drop and then store the drop target Data_Kategorie targetItem = (e.OriginalSource as TextBlock)?.DataContext as Data_Kategorie; ViewModel vm = (sender as TreeView).DataContext as ViewModel; if (targetItem != null && vm != null) { object data = e.Data.GetData(typeof(Data_Kategorie));

    // Hier konkrete Verschiebung programmieren

    e.Effects = DragDropEffects.Move; } } } }



    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Dienstag, 23. November 2021 06:39
  • Hallo

    Irgendwie funktioniert das Verschieben mit dem DragDrop nicht.

    Dazu habe ich noch ein anderes Problem. Ich habe in mein MainWindow noch ein Textbox, Combobox und ein Button hingefügt um da einen neuen Eintrag in TreeView hinzufügen. Aber irgendwie kann ich mit der Action von Button_Click nicht auf col.add zugreifen.

    Das nächste Problem ist bei Combobox wird mir beim öffnen des Combobox nicht das TreeView angezeigt.

    Hier mal mein Code.

    MainWindows.xaml

    <Window x:Class="TreeView4.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            xmlns:local="clr-namespace:TreeView4"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <TreeView ItemsSource="{Binding RootItems}" Margin="0,0,609,0" >
                <i:Interaction.Behaviors>
                    <local:TreeViewBehavior/>
                </i:Interaction.Behaviors>
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding KategorieName}"/>
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="188,10,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="594"/>
            <Button Content="Hinzufügen" Click="Button_Add_Click" HorizontalAlignment="Left" Margin="188,73,0,0" VerticalAlignment="Top" Width="594"/>
            <ComboBox HorizontalAlignment="Left" Margin="188,38,0,0" VerticalAlignment="Top" Width="594">
    
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Margin="3" Foreground="Blue" FontWeight="Bold" Text="{Binding KategorieName}"/>
                            <TreeView ItemsSource="{Binding RootItems}">
    
                                <TreeView.ItemTemplate>
                                    
                                    <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
                                        <TextBlock Text="{Binding KategorieName}"/>
                                    </HierarchicalDataTemplate>
                                
                                    
                                    </TreeView.ItemTemplate>
                            </TreeView>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
    
    
        </Grid>
    </Window>
    

    MainWindow.cs

    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;
    
    namespace TreeView4
    {
        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
    
            private void Button_Add_Click(object sender, RoutedEventArgs e)
            {
                
    
                
            }
        }
    }
    

    ViewModel.cs

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    using System.Windows.Media;
    
    namespace TreeView4
    {
        public class ViewModel
        {
            public ViewModel()
            {
                cvs.Source = (new Model()).GetData(0);
                cvs.SortDescriptions.Add(new SortDescription("KategorieReihenfolge", ListSortDirection.Ascending));
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems 
            { 
                get => cvs.View;
    
            }
            
            public Data_Kategorie Detail { set { MessageBox.Show($"KategorieNummer: {value.KategorieNummer}\nKategorieUnterNummer: {value.KategorieUnterNummer}\nKategorieName: {value.KategorieName}"); } }
    
        }
    
        internal class Model
        {
            public Model()
            {
                // Demo-Daten erzeugen
                Random rnd = new Random();
                for (int i = 100; i < 110; i++) col.Add(new Data_Kategorie(col)
                {
                    KategorieNummer = i,
                    KategorieUnterNummer = (rnd.NextDouble() > .5) ? 0 : rnd.Next(100, i),
                    KategorieName = $"Node {i}",
                    KategorieReihenfolge = i
                });
    
                col.Add(new Data_Kategorie(col)
                {
                    KategorieNummer=10,
                    KategorieUnterNummer=0,
                    KategorieName="Hallo",
                    KategorieReihenfolge=10
                } );
    
                col.Add(new Data_Kategorie(col)
                {
                    KategorieNummer = 11,
                    KategorieUnterNummer = 0,
                    KategorieName = "Hallo1",
                    KategorieReihenfolge = 9
                });
    
            }
    
            // Datenspeicher
            internal ObservableCollection<Data_Kategorie> col = new ObservableCollection<Data_Kategorie>();
    
            // Sicht für Root-Level
            internal ObservableCollection<Data_Kategorie> GetData(int levelID) =>
              new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == 0));
        }
    
        public class Data_Kategorie
        {
            public Data_Kategorie(ObservableCollection<Data_Kategorie> data) => col = data;
            private ObservableCollection<Data_Kategorie> col;
            public int KategorieNummer { get; set; }
            public int KategorieUnterNummer { get; set; }
            public string KategorieName { get; set; }
            public int KategorieReihenfolge { get; set; }
            public ObservableCollection<Data_Kategorie> ChildrenItems { get => new ObservableCollection<Data_Kategorie>(col.Where((d) => d.KategorieUnterNummer == this.KategorieNummer)); }
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
        public class TreeViewBehavior : Behavior<TreeView>
        {
            protected override void OnAttached() => AssociatedObject.SelectedItemChanged += AssociatedObject_SelectedItemChanged;
    
            private void AssociatedObject_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                var tv = sender as TreeView;
                if (tv == null) return;
                var vm = tv.DataContext as ViewModel;
                if (vm == null) return;
                vm.Detail = tv.SelectedItem as Data_Kategorie;
            }
        }
    
        public class DragDropBehavior : Behavior<UIElement>
        {
            protected override void OnAttached()
            {
                AssociatedObject.PreviewMouseLeftButtonDown += PreviewMouseLeftButtonDown;
                AssociatedObject.Drop += Tv_Drop;
            }
    
            private void PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                if (sender is TreeView)
                {
                    TreeView dragSource = sender as TreeView;
                    object data = GetDataFromTreeView(dragSource, e.GetPosition(AssociatedObject));
                    if (data != null) DragDrop.DoDragDrop(dragSource, data, DragDropEffects.Move);
                }
            }
    
            private static object GetDataFromTreeView(TreeView source, Point point)
            {
                UIElement element = source.InputHitTest(point) as UIElement;
                if (element != null)
                {
                    object data = DependencyProperty.UnsetValue;
                    while (data == DependencyProperty.UnsetValue)
                    {
                        data = source.ItemContainerGenerator.ItemFromContainer(element);
                        if (data == DependencyProperty.UnsetValue) element = VisualTreeHelper.GetParent(element) as UIElement;
                        if (element == source) return null;
                    }
                    if (data != DependencyProperty.UnsetValue) return data;
                }
                return null;
            }
    
            private void Tv_Drop(object sender, DragEventArgs e)
            {
                if (sender is TreeView)
                {
                    e.Effects = DragDropEffects.None;
                    e.Handled = true;
                    // Verify that this is a valid drop and then store the drop target
                    Data_Kategorie targetItem = (e.OriginalSource as TextBlock)?.DataContext as Data_Kategorie;
                    ViewModel vm = (sender as TreeView).DataContext as ViewModel;
                    if (targetItem != null && vm != null)
                    {
                        object data = e.Data.GetData(typeof(Data_Kategorie));
                        // Hier konkrete Verschiebung programmieren
                        e.Effects = DragDropEffects.Move;
                    }
                }
            }
        }
    }

    Gruß

    Mezzo

    Freitag, 3. Dezember 2021 10:11
  • Hi Mezzo,
    hier mal der geänderte XAML:

      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="auto"/>
          <RowDefinition Height="auto"/>
          <RowDefinition Height="auto"/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <TreeView Grid.Row="3" ItemsSource="{Binding RootItems}" AllowDrop="True">
          <i:Interaction.Behaviors>
            <local:TreeViewBehavior/>
            <local:DragDropBehavior/>
          </i:Interaction.Behaviors>
          <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding KategorieName}"/>
            </HierarchicalDataTemplate>
          </TreeView.Resources>
        </TreeView>
        <TextBox Grid.Row="0" HorizontalAlignment="Right" Height="23" Margin="5" TextWrapping="Wrap" Text="" Width="594"/>
        <Button Grid.Row="1" Content="Hinzufügen" HorizontalAlignment="Right" Margin="5" Width="594" Command="{Binding}"/>
        <ComboBox Grid.Row="2" HorizontalAlignment="Right" Margin="5" Width="594">
          <ComboBox.ItemTemplate>
            <DataTemplate>
              <StackPanel>
                <TextBlock Margin="3" Foreground="Blue" FontWeight="Bold" Text="{Binding KategorieName}"/>
                <TreeView ItemsSource="{Binding RootItems}">
                  <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:Data_Kategorie}" ItemsSource="{Binding ChildrenItems}">
                      <TextBlock Text="{Binding KategorieName}"/>
                    </HierarchicalDataTemplate>
                  </TreeView.ItemTemplate>
                </TreeView>
              </StackPanel>
            </DataTemplate>
          </ComboBox.ItemTemplate>
        </ComboBox>
      </Grid>

    Und der ViewModel dazu:

      public class ViewModel : ICommand, INotifyPropertyChanged
      {
        /// <summary>
        /// contructor
        /// </summary>
        public ViewModel()
        {
          cvs.Source = m.GetData(0);
          cvs.SortDescriptions.Add(new SortDescription("KategorieReihenfolge", ListSortDirection.Ascending));
        }
    
        Model m = new Model();
        private CollectionViewSource cvs = new CollectionViewSource();
    
        /// <summary>
        /// View
        /// </summary>
        public ICollectionView RootItems { get => cvs.View; }
    
        /// <summary>
        /// Selected node
        /// </summary>
        public Data_Kategorie Detail { set { MessageBox.Show($"KategorieNummer: {value.KategorieNummer}\nKategorieUnterNummer: {value.KategorieUnterNummer}\nKategorieName: {value.KategorieName}"); } }
    
        #region Command
        public event EventHandler CanExecuteChanged;
        public bool CanExecute(object parameter) => true;
        /// <summary>
        /// execute Button
        /// </summary>
        /// <param name="parameter">CommandParameter</param>
        public void Execute(object parameter)
        {
          m.col.Add(new Data_Kategorie(m.col)
          {
            KategorieNummer = 12,
            KategorieUnterNummer = 0,
            KategorieName = "Hallo2",
            KategorieReihenfolge = 8
          });
          cvs.Source = m.GetData(0);
          OnPropertyChanged(nameof(RootItems));
        }
        #endregion
    
        #region NotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
      }
    

    Damit funktioniert das Hinzufügen problemlos.


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Freitag, 3. Dezember 2021 10:49
  • Hallo

    Danke Peter aber wie bekommt man den Inhalt von der Textbox Hinzugefügt so wie ich sehe ist nur der Button der Command als Binding aber der Textbox nicht.

    Gruß

    Mezzo

    Freitag, 3. Dezember 2021 17:20
  • Hi Mezzo,
    ich habe mich nach deinen Code gerichtet. Wenn du den Inhalt der TextBox im ViewModel haben willst, musst du die Texteigenschaft an eine Eigenschaft im ViewModel binden.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Freitag, 3. Dezember 2021 19:12
  • Hallo Peter

    und wie macht man das?

    Ich habe es probiert mit x:Name="txt_add" bei Textbox aber in ViewModel kann ich die txt_add nicht aufrufen.

    Gruß

    Mezzo

    Freitag, 3. Dezember 2021 19:47
  • Hi Mezzo,
    was hast du gebunden? (im XAML: Text="{Binding xxx}")?

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Freitag, 3. Dezember 2021 19:57
  • Hallo Peter

    Ich hab es so probiert

    <TextBox x:Name="txt_Add" Grid.Row="0" HorizontalAlignment="Right" Height="23" Margin="5" TextWrapping="Wrap" Text="{Binding KategorieName}" Width="594"/>

    Aber wenn ich jetzt auf den Button Hinzufügen klicke wird zwar ein Node hingefügt aber ohne Text, es wird einfach ein leeres Node Hinzugefügt

    Samstag, 4. Dezember 2021 07:50
  • Hi Mezzo,
    werden im "Immediate Window" Fehler angezeigt (z.B. Bindungsfehler)?

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Samstag, 4. Dezember 2021 08:13
  • Hallo

    Nein es wird kein Fehler angezeigt.

    Ich habe mir grad überlegt diese mit den Binding würde dann nicht funktionieren wenn ich das TreeView als UserControl mache.

    Weil wie ich gemerkt habe bräuchte ich diese Art von TreeView öfter somit wäre es doch besser dieses TreeView model als UserControl aufzubauen somit ist dieser Code dann nur 1mal die dann öfter verwendet wird sehe ich das Richtig.

    Gruß

    Mezzo

    Samstag, 4. Dezember 2021 11:59
  • Hi Mezzo,
    da kein Bindungsfehler angezeigt wird, funktioniert die Bindung auch und der in der Textbox eingegeben Text wird auch in die Eigenschaft "KategorieName" im ViewModel abgelegt. Das bedeutet, dass die Execute-Methode im ViewModel, die im Ergebnis des Klicks abgearbeitet wird, nicht auf den Eigenschaftswert zugreift. Ohne konkreten Code ist das Problem nicht nachvollziehbar.

    Natürlich kann man anstelle des TreeViews auch eine UserControl mit TreeView nutzen. Konzeptionell muss man sich dabei aber genau überlegen, wer ist DataContext, arbeitet man im UserContral auch mit einem separaten VieModel oder mit CodeBehind usw.


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Samstag, 4. Dezember 2021 13:16
  • Okay ich würde das mit dem UserControl mal ausprobieren.

    Wenn ich es soweit dann hinbekomme habe dann öffnet ich ein neues Ticket weil es ja dann eine anderes Thema ist.

    Gruß

    Mezzo

    Samstag, 4. Dezember 2021 13:22