none
TreeView Baumstruktur RRS feed

  • Frage

  • Hallo

    Ich komme leider nicht weiter ich möchte eine einfache TreeView Baumstruktur erstellen.

    Es soll so sein das ich 3 Variablen habe.

    ID

    ChildrenID

    Name

    Die Variablen habe ich nun so in C#

            public Int32 TreeViewRootID { get; set; }
            public Int32 TreeViewRootChildrenID { get; set; }
    
            public string TreeViewName { get; set; }

    Der Aufbau sollte dann so sein

    1, 0, Root1

    2, 1, Children1

    3, 2, Children 1.1

    4, 3, Children 1.1.1

    5, 0, Root2

    6, 5, Children 2

    usw.

    Meine Vermutung für den XAML wäre so.

        <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="Bold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </TreeView.ItemContainerStyle>
    
          <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding TreeViewName}" />
            </HierarchicalDataTemplate>
          </TreeView.ItemTemplate>
        </TreeView>

    Das habe ich aus einer Seite gefunden.

    Wie erstellt man ein ganz einfaches ViewModels so das man den TreeView so füllen kann.

    MyTreeView.Items.Add(1,0,"Root1");

    und wenn man es in TreeView es markiert soll ein Messenbox erscheinen der mit alle 3 Varianten anzeigt.

    Hoffe mir kann dabei jemand das gut erklären.

    Sonntag, 10. Januar 2021 08:10

Antworten

  • Hi,
    Ich habe dir mal eine kleine Demo zu deinen Fragen erstellt. Im ViewModel wird zu Demonstrationszwecken eine Knotenliste entsprechend deinen Vorgaben erzeugt und zur Anzeige im TreeView gebracht. Für den vom Anwender selektierten Knoten werden im rechten Teil des Fensters die Eigenschaften des Datenobjektes des ausgewählten Knotens angezeigt und derer Werte können verändert werden. Der selektierte Knoten wird mittels Behavior aus dem NuGet-Paket "System.Windows.Interactivity" gefangen und in den ViewModel eingetragen (Details-Eigenschaft). Damit diese Änderung auch in der Oberfläche sichtbar wird, ist INotifyPropertyChanged implementiert.

    XAML:

    <Window x:Class="WpfApp1.Window027"
            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:WpfApp027"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="Window027" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <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="Bold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </TreeView.ItemContainerStyle>
          <i:Interaction.Behaviors>
            <local:TreeViewBehavior/>
          </i:Interaction.Behaviors>
          <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding TreeViewName}" />
            </HierarchicalDataTemplate>
          </TreeView.ItemTemplate>
        </TreeView>
        <Grid Grid.Column="1" DataContext="{Binding Detail}">
          <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
          <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
        </Grid>
      </Grid>
    </Window>

    ViewModel:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Interactivity;
    
    namespace WpfApp027
    {
      public class ViewModel : INotifyPropertyChanged
      {
        public ViewModel()
        {
          Random rnd = new Random();
          ObservableCollection<Data> col = new ObservableCollection<Data>();
          for (int i = 1; i < 100; i++)
          {
            Data d = new Data(col) { TreeViewRootID = i, TreeViewName = $"Node {i}", TreeViewRootChildrenID = rnd.Next(0, col.Count) };
            col.Add(d);
          }
          cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
        }
    
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
    
        private Data _details = null;
        public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    
      public class Data
      {
        public Data(ObservableCollection<Data> col) => this.col = col;
        ObservableCollection<Data> col;
        public Int32 TreeViewRootID { get; set; }
        public Int32 TreeViewRootChildrenID { get; set; }
        public string TreeViewName { get; set; }
        public ObservableCollection<Data> ChildrenItems { get => new ObservableCollection<Data>(col.Where((d) => d.TreeViewRootChildrenID == this.TreeViewRootID)); }
    
        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;
        }
      }
    }


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

    Sonntag, 10. Januar 2021 13:17
  • Hi,
    hast du den Code mal ausprobiert? Er kann ohne Änderungen genutzt werden. Lediglich, wenn du andere Namensräume und Fensternamen nutzt, musst du dies anpassen.

    Wenn der Code dann läuft, kannst du Haltepunkte setzen und sehen, bei welchen Aktivitäten welche Codeabschnitte durchlaufen werden.

    Zu deinen Frage:

    1. Füllen der Daten: es wird eine Liste von Datenobjekte vom Typ Data erzeugt. Jedes Datenobjekt bekommt im Constructor einen Verweis auf die Liste der Datenobjekte ("col"). Die Elemente der Liste, die TreeViewRootChildrenID=0 haben werden nur bereitgestellt (Root-Ebene).

    2a. RootItems: Das ist die Eigenschaft im ViewModel, die du in deinem Codeschnipsel für die Bindung der im TreeView anzuzeigenden Knoten vorgegeben hast. 

    2b. Details: darin wird das Datenobjekt des aktuell angeklickten Knotens gehalten. OnPropertyChanged bewirkt eine Mitteilung an die Oberfläche, damit sich diese die aktuellen Daten für die Anzeige und Bearbeitung holt (nach Anklicken eines anderen Knotens). Genutzt wird Details als DataContext im rechten Teil des Windows.

    3. public Data(... ist ein Constructor in der Datenklasse, mit welchem ein Verweis auf die Liste des Datenobjekte übergeben wird. Diese Liste wird dann gefiltert, um die einem Knoten untergeordneten Knoten zur Anzeige zu bringen.

    4. ChildrenItems ist die Eigenschaft, die du in deinem Ausgangsposting für die Liste der untergeordneten Knoten vorgegeben hast.

    Ich habe das ViewModel schon sehr einfach gestaltet. Das Laden der Collection für die CollectionViewSource (im Constructor des ViewModels) könnte man in ein Model auslagern, um z.B. anstelle der generierten zufälligen Testdaten diese Daten aus einer externen Datenquelle zu laden.


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

    Sonntag, 10. Januar 2021 16:45
  • Hi,
    hier mal ein Beispiel mit einem DataSet. Der Übersichtlichkeit halber, damit das Prinzip deutlicher zu erkennen ist, habe ich untypisiertes DataSet genutzt. Mit einem typisierten DataSet (wie bei dir) vereinfacht sich das Ganze etwas. Außerdem habe ich anstelle des NuGet-Paketes eine DependencyProperty eingebaut.

    XAML:

    <Window x:Class="WpfApp1.Window028"
            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:WpfApp028"
            mc:Ignorable="d"
            Title="Window027" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TreeView ItemsSource="{Binding RootItems}" local:ViewModel.TreeViewBevior="True">
        <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="Bold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </TreeView.ItemContainerStyle>
          <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding TreeViewName}" />
            </HierarchicalDataTemplate>
          </TreeView.ItemTemplate>
        </TreeView>
        <Grid Grid.Column="1" DataContext="{Binding Detail}">
          <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
          <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
          <DataGrid Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding DataGridTabelle}"/>
        </Grid>
      </Grid>
    </Window>

    Klassen:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace WpfApp028
    {
      public class ViewModel : INotifyPropertyChanged
      {
        public ViewModel()
        {
          Model m = new Model();
          var ds = m.DatenTabelle;
          ObservableCollection<Data> col = new ObservableCollection<Data>();
          foreach (DataRow row in ds.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
          cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
        }
    
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
    
        private Data _details = null;
        public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
        #region attached behavior
    
        public static readonly DependencyProperty TreeViewBeviorProperty =
          DependencyProperty.RegisterAttached("TreeViewBevior",
            typeof(bool), typeof(TreeView), new UIPropertyMetadata(false, OnTreeViewBevior));
        public static bool GetTreeViewBevior(DependencyObject obj) => (bool)obj.GetValue(TreeViewBeviorProperty);
        public static void SetTreeViewBevior(DependencyObject obj, bool value) => obj.SetValue(TreeViewBeviorProperty, value);
        private static void OnTreeViewBevior(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
          var tv = depObj as TreeView;
          if (tv == null) return;
          if ((e.NewValue is bool) && (bool)(e.NewValue)) tv.SelectedItemChanged += OnLblMouseDown; else tv.SelectedItemChanged -= OnLblMouseDown;
        }
    
        private static void OnLblMouseDown(Object sender, EventArgs 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;
        }
    
        #endregion
    
        #region OnPropertyChanged
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
        #endregion
      }
    
      public class Data
      {
        public Data(DataRow row) { this.row = row; this.dt = row.Table; this.ds = row.Table.DataSet; }
        DataSet ds;
        DataTable dt;
        DataRow row;
        public Int32 TreeViewRootID { get => row.Field<int>("TreeViewRootID"); set { row["TreeViewRootID"] = value; } }
        public Int32 TreeViewRootChildrenID { get => row.Field<int>("TreeViewRootChildrenID"); set { row["TreeViewRootChildrenID"] = value; } }
        public string TreeViewName { get => row.Field<string>("TreeViewName"); set { row["TreeViewName"] = value; } }
        public object ChildrenItems => new ObservableCollection<Data>(from d in dt.AsEnumerable() where d.Field<int>("TreeViewRootChildrenID") == this.TreeViewRootID select new Data(d));
        public DataView DataGridTabelle
        {
          get
          {
            DataTable dt2 = ds.Tables["DataGridTabelle"].Clone();
            var dv = new DataView(ds.Tables["DataGridTabelle"]);
            var req = from dg in ds.Tables["DataGridTabelle"].AsEnumerable()
                      join zu in ds.Tables["Zuordnung"].AsEnumerable()
                        on dg.Field<int>("GridColumn1ID") equals zu.Field<int>("ZuGridColumn1ID")
                      where zu.Field<int>("ZuTreeViewRootID") == TreeViewRootID
                      select dg;
            foreach (var item in req) dt2.Rows.Add(item.ItemArray);
            return dt2.AsDataView();
          }
        }
        public bool IsExpanded { get; set; } = true;
        public bool IsSelected { get; set; }
      }
    
      public class Model
      {
        public Model()
        {
          // generate untyped DataSet
          DatenTabelle = new DataSet();
          DataTable dtTV = new DataTable("TreeViewTabelle");
          DatenTabelle.Tables.Add(dtTV);
          dtTV.Columns.Add("ID", typeof(int));
          dtTV.Columns.Add("TreeViewRootID", typeof(int));
          dtTV.Columns.Add("TreeViewRootChildrenID", typeof(int));
          dtTV.Columns.Add("TreeViewName", typeof(string));
          DataTable dtDG = new DataTable("DataGridTabelle");
          DatenTabelle.Tables.Add(dtDG);
          dtDG.Columns.Add("ID", typeof(int));
          dtDG.Columns.Add("GridColumn1ID", typeof(int));
          dtDG.Columns.Add("GridColumn2Text1", typeof(string));
          dtDG.Columns.Add("GridColumn3Text2", typeof(string));
          DataTable dtZO = new DataTable("Zuordnung");
          DatenTabelle.Tables.Add(dtZO);
          dtZO.Columns.Add("ID", typeof(int));
          dtZO.Columns.Add("ZuTreeViewRootID", typeof(int));
          dtZO.Columns.Add("ZuGridColumn1ID", typeof(int));
          // load data
          LoadData();
        }
    
        public DataSet DatenTabelle { get; set; }
    
        private void LoadData()
        {
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(1, 100, 0, "Root1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(2, 101, 0, "Root2");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(3, 102, 0, "Root3");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(4, 103, 100, "Children1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(5, 104, 100, "Children2");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(6, 105, 104, "Children2.1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(7, 106, 101, "Children1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(8, 107, 106, "Children1.1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(9, 108, 107, "Children1.1.1");
    
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(1, 100, "Test1", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(2, 101, "Test2", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(3, 102, "Test3", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(4, 103, "Test4", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(5, 104, "Test5", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(6, 105, "Test6", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(7, 106, "Test7", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(8, 107, "Test8", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(9, 108, "Test9", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(10, 109, "Test10", "Test1");
    
          DatenTabelle.Tables["Zuordnung"].Rows.Add(1, 103, 100);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(2, 103, 101);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(3, 103, 102);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(4, 105, 103);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(5, 105, 104);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(6, 105, 105);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(7, 105, 100);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(8, 101, 107);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(9, 101, 108);
        }
      }
    }


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

    Montag, 11. Januar 2021 11:12

Alle Antworten

  • Hi,
    Ich habe dir mal eine kleine Demo zu deinen Fragen erstellt. Im ViewModel wird zu Demonstrationszwecken eine Knotenliste entsprechend deinen Vorgaben erzeugt und zur Anzeige im TreeView gebracht. Für den vom Anwender selektierten Knoten werden im rechten Teil des Fensters die Eigenschaften des Datenobjektes des ausgewählten Knotens angezeigt und derer Werte können verändert werden. Der selektierte Knoten wird mittels Behavior aus dem NuGet-Paket "System.Windows.Interactivity" gefangen und in den ViewModel eingetragen (Details-Eigenschaft). Damit diese Änderung auch in der Oberfläche sichtbar wird, ist INotifyPropertyChanged implementiert.

    XAML:

    <Window x:Class="WpfApp1.Window027"
            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:WpfApp027"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="Window027" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <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="Bold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </TreeView.ItemContainerStyle>
          <i:Interaction.Behaviors>
            <local:TreeViewBehavior/>
          </i:Interaction.Behaviors>
          <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding TreeViewName}" />
            </HierarchicalDataTemplate>
          </TreeView.ItemTemplate>
        </TreeView>
        <Grid Grid.Column="1" DataContext="{Binding Detail}">
          <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
          <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
        </Grid>
      </Grid>
    </Window>

    ViewModel:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Interactivity;
    
    namespace WpfApp027
    {
      public class ViewModel : INotifyPropertyChanged
      {
        public ViewModel()
        {
          Random rnd = new Random();
          ObservableCollection<Data> col = new ObservableCollection<Data>();
          for (int i = 1; i < 100; i++)
          {
            Data d = new Data(col) { TreeViewRootID = i, TreeViewName = $"Node {i}", TreeViewRootChildrenID = rnd.Next(0, col.Count) };
            col.Add(d);
          }
          cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
        }
    
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
    
        private Data _details = null;
        public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    
      public class Data
      {
        public Data(ObservableCollection<Data> col) => this.col = col;
        ObservableCollection<Data> col;
        public Int32 TreeViewRootID { get; set; }
        public Int32 TreeViewRootChildrenID { get; set; }
        public string TreeViewName { get; set; }
        public ObservableCollection<Data> ChildrenItems { get => new ObservableCollection<Data>(col.Where((d) => d.TreeViewRootChildrenID == this.TreeViewRootID)); }
    
        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;
        }
      }
    }


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

    Sonntag, 10. Januar 2021 13:17
  • Hallo

    Danke für deine Antwort werde es heute Abend testen.

    Nun wie kommt man auf diesen Code

    Dieser Code ist klar das ist für füllen der Daten:

          Random rnd = new Random();
          ObservableCollection<Data> col = new ObservableCollection<Data>();
          for (int i = 1; i < 100; i++)
          {
            Data d = new Data(col) { TreeViewRootID = i, TreeViewName = $"Node {i}", TreeViewRootChildrenID = rnd.Next(0, col.Count) };
            col.Add(d);
          }
          cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);

    für was ist dieser Code?

       private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
    
        private Data _details = null;
        public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    


    Für das ist das?

        public Data(ObservableCollection<Data> col) => this.col = col;
        ObservableCollection<Data> col;

    und für was ist das?

        public ObservableCollection<Data> ChildrenItems { get => new ObservableCollection<Data>(col.Where((d) => d.TreeViewRootChildrenID == this.TreeViewRootID)); }
    

    geht dieses Model noch einfacher?

    Ich hab gelesen das es mit dem MenuItems vielleicht auch funktionieren würde. Wäre das einfacher?

    Sonntag, 10. Januar 2021 15:58
  • Perfekt das funktioniert Super leider bin ich kein Fan von Nut-Get Paket

    Immer wenn ich mein PC auf Werkeinstellung und Visual Studio neu installiere habe ich immer Probleme das ich meine Projekte nicht mehr öffnen kann selbst wenn ich das Nut-Get Paket danach Installiere.

    das gehört jetzt nicht zum Thema.

    Ich schaue jetzt dein Code genauer an und hoffe das ich diese auch Verstehe. Diesen Beitrag bitte noch nicht schließen ich denke ich habe dazu noch ein paar Fragen.

    MfG.

    Mezzo 

    Sonntag, 10. Januar 2021 16:39
  • Hi,
    hast du den Code mal ausprobiert? Er kann ohne Änderungen genutzt werden. Lediglich, wenn du andere Namensräume und Fensternamen nutzt, musst du dies anpassen.

    Wenn der Code dann läuft, kannst du Haltepunkte setzen und sehen, bei welchen Aktivitäten welche Codeabschnitte durchlaufen werden.

    Zu deinen Frage:

    1. Füllen der Daten: es wird eine Liste von Datenobjekte vom Typ Data erzeugt. Jedes Datenobjekt bekommt im Constructor einen Verweis auf die Liste der Datenobjekte ("col"). Die Elemente der Liste, die TreeViewRootChildrenID=0 haben werden nur bereitgestellt (Root-Ebene).

    2a. RootItems: Das ist die Eigenschaft im ViewModel, die du in deinem Codeschnipsel für die Bindung der im TreeView anzuzeigenden Knoten vorgegeben hast. 

    2b. Details: darin wird das Datenobjekt des aktuell angeklickten Knotens gehalten. OnPropertyChanged bewirkt eine Mitteilung an die Oberfläche, damit sich diese die aktuellen Daten für die Anzeige und Bearbeitung holt (nach Anklicken eines anderen Knotens). Genutzt wird Details als DataContext im rechten Teil des Windows.

    3. public Data(... ist ein Constructor in der Datenklasse, mit welchem ein Verweis auf die Liste des Datenobjekte übergeben wird. Diese Liste wird dann gefiltert, um die einem Knoten untergeordneten Knoten zur Anzeige zu bringen.

    4. ChildrenItems ist die Eigenschaft, die du in deinem Ausgangsposting für die Liste der untergeordneten Knoten vorgegeben hast.

    Ich habe das ViewModel schon sehr einfach gestaltet. Das Laden der Collection für die CollectionViewSource (im Constructor des ViewModels) könnte man in ein Model auslagern, um z.B. anstelle der generierten zufälligen Testdaten diese Daten aus einer externen Datenquelle zu laden.


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

    Sonntag, 10. Januar 2021 16:45
  • Hallo ja dein Code Funktioniert und hab es schon ein mehr verstanden.

    Ich habe das jetzt mal ein Bissen erweitert und schon Funktioniert es nicht mehr. Nun zu meinem Aufbau.

    Ich habe ein DataSet hinzugefügt mit dem Namen DataSet1.xsd

    Da habe ich nun 3 Tabellen drin und sind miteinander Verbunden. Das Ziel ist es wenn man bei TreeView einen Knoten Markiert das es in DataGrid nur die Daten anzeigt die mit dem Knoten verbunden ist. Das habe ich mit der Tabelle "Zuordnung" gemacht.

    Leider kann ich noch kein Bild im Beitrag einfügen weil mein Konto noch geprüft werden muss

    Ich schreibe die 3 Tabellennamen mit Spalten auf

    TreeViewtabelle

    --- ID   int32      Schlüssen Primar

    --- TreeViewRootID  int32

    --- TreeViewRootChildrenID   int32

    --- TreeViewName   string

    DataGridTabelle

    --- ID   int32      Schlüssen Primar

    --- GridColumn1ID  int32

    --- GridColumn2Text1   string

    --- GridColumn3Text2   string

    Zuordnung

    --- ID    int32      Schlüssen Primar

    --- ZuTreeViewRootID    int32

    --- ZuGridColumn1ID     int32

    Hoffe man versteht die DataSet auch ohne Bild

    MainWindow.xaml

    <Window x:Class="TreeView_DataGrid_Test.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_DataGrid_Test"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <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="Bold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <i:Interaction.Behaviors>
                    <local:TreeViewBehavior/>
                </i:Interaction.Behaviors>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding TreeViewName}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <Grid Grid.Column="1" DataContext="{Binding Detail}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
                <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
                <Label Grid.Row="2" Grid.Column="0" Content="ColumnID: " HorizontalAlignment="Right" Grid.ColumnSpan="2" Margin="0,5,193,336"/>
                <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Column1ID}" IsReadOnly="True" Margin="0,5,0,336"/>
                <Label Grid.Row="2" Grid.Column="0" Content="ColumnText: " HorizontalAlignment="Right" Margin="0,36,0,305"/>
                <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Column2Text1}" Margin="0,36,0,305"/>
                <DataGrid x:Name="DataGrid1" ItemsSource="{Binding DataGridTabelle}" Margin="0,84,0,0" Grid.Row="2" Grid.ColumnSpan="2">
                    <DataGrid.Columns>
    
                        <DataGridTextColumn Width="100" Binding="{Binding GridColumn1ID}" Header="Column1ID"/>
                        <DataGridTextColumn Width="100" Binding="{Binding GridColumn2Text1}" Header="Column2Text1"/>
                        <DataGridTextColumn Width="100" Binding="{Binding GridColumn3Text2}" Header="Column3Text2"/>
                        
                    </DataGrid.Columns>
                </DataGrid>
    
    
            </Grid>
        </Grid>
    </Window>

    Das ViewModel habe ich in einer Klasser ViewModel_TreeView.cs

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Interactivity;
    
    namespace TreeView_DataGrid_Test
    {
        class ViewModel_TreeView
        {
        }
    
        public class ViewModel : INotifyPropertyChanged
        {
            
    
            public ViewModel()
            {
                DataSet1 DatenTabelle = new DataSet1();
    
                DatenTabelle.TreeViewTabelle.Rows.Add(1, 100, 0, "Root1");
                DatenTabelle.TreeViewTabelle.Rows.Add(2, 101, 0, "Root2");
                DatenTabelle.TreeViewTabelle.Rows.Add(3, 102, 0, "Root3");
                DatenTabelle.TreeViewTabelle.Rows.Add(4, 103, 100, "Children1");
                DatenTabelle.TreeViewTabelle.Rows.Add(5, 104, 100, "Children2");
                DatenTabelle.TreeViewTabelle.Rows.Add(6, 105, 104, "Children2.1");
                DatenTabelle.TreeViewTabelle.Rows.Add(7, 106, 101, "Children1");
                DatenTabelle.TreeViewTabelle.Rows.Add(8, 107, 106, "Children1.1");
                DatenTabelle.TreeViewTabelle.Rows.Add(9, 108, 107, "Children1.1.1");
    
                DatenTabelle.DataGridTabelle.Rows.Add(1, 100, "Test1", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(2, 101, "Test2", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(3, 102, "Test3", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(4, 103, "Test4", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(5, 104, "Test5", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(6, 105, "Test6", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(7, 106, "Test7", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(8, 107, "Test8", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(9, 108, "Test9", "Test1");
                DatenTabelle.DataGridTabelle.Rows.Add(10, 109, "Test10", "Test1");
    
                DatenTabelle.Zuordnung.Rows.Add(1, 103, 100);
                DatenTabelle.Zuordnung.Rows.Add(2, 103, 101);
                DatenTabelle.Zuordnung.Rows.Add(3, 103, 102);
                DatenTabelle.Zuordnung.Rows.Add(4, 105, 103);
                DatenTabelle.Zuordnung.Rows.Add(5, 105, 104);
                DatenTabelle.Zuordnung.Rows.Add(6, 105, 105);
                DatenTabelle.Zuordnung.Rows.Add(7, 105, 100);
                DatenTabelle.Zuordnung.Rows.Add(8, 101, 107);
                DatenTabelle.Zuordnung.Rows.Add(9, 101, 108);
    
    
    
                //Random rnd = new Random();
                //ObservableCollection<Data> col = new ObservableCollection<Data>();
                //for (int i = 1; i < 100; i++)
                //{
                //    Data d = new Data(col) { TreeViewRootID = i, TreeViewName = $"Node {i}", TreeViewRootChildrenID = rnd.Next(0, col.Count) };
    
                //    col.Add(d);
                //}
                //cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
    
                ObservableCollection<Data> col = new ObservableCollection<Data>();
                for (int i = 1; DatenTabelle.TreeViewTabelle.Rows.Count; i++)
                {
                    Data d = new Data(col) { TreeViewRootID = DatenTabelle.TreeViewTabelle.Rows[i].ItemArray[1], TreeViewName = DatenTabelle.TreeViewTabelle.Rows[i].ItemArray[3], TreeViewRootChildrenID = DatenTabelle.TreeViewTabelle.Rows[i].ItemArray[2] };
                    col.Add(d);
    
                }
                cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
    
            }
    
            public DataSet1 DatenGrid { set; get; }
    
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private Data _details = null;
            public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    
        public class Data
        {
            public Data(ObservableCollection<Data> col) => this.col = col;
            ObservableCollection<Data> col;
            public Int32 TreeViewRootID { get; set; }
            public Int32 TreeViewRootChildrenID { get; set; }
            public string TreeViewName { get; set; }
            public ObservableCollection<Data> ChildrenItems { get => new ObservableCollection<Data>(col.Where((d) => d.TreeViewRootChildrenID == this.TreeViewRootID)); }
    
            public bool IsExpanded { get; set; } = false;
            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;
            }
        }
    }
    

    Ich weiß die Befüllung von die Tabellen in DataSet ist nicht grad das beste. Das ist hier jetzt nur ein Beispiel. Normal werden die Tabellen von der Datenbank mit while Schleife befüllt.

    Ich Arbeite gerne mit DataSet, da ich die Tabellen schön anlegen kann und die Tabellen mit einander verbinden kann. So das wenn man in Datagrid was auswählt Automatisch die Daten angezeigt werden die in einer anderen Tabelle verbunden sind.

    Nur bekomme ich das mit WPF nicht so hin. Was habe ich da Falsch?

    Sonntag, 10. Januar 2021 22:46
  • HI,
    anstelle des von mit genutzten NuGet-Pakets "System.Windows.Interactivity" kannst du auch die Funktionalität mit einem eigenen "attached behavior" realisieren. Da wird eine statische DependencyProperty genutzt, mit der während der Instanziierung (im konkreten Fall TreeView) der Verweis auf die TreeView-Instanz "gefangen" wird und damit das SelectedItemChanged Ereignis genutzt werden kann. Diese Technologie ist erforderlich, wenn das MVVM Entwurfsmuster genutzt werden soll, da in diesem Fall der ViewModel die View nicht kennt.

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

    Montag, 11. Januar 2021 05:35
  • Hi,
    hier mal ein Beispiel mit einem DataSet. Der Übersichtlichkeit halber, damit das Prinzip deutlicher zu erkennen ist, habe ich untypisiertes DataSet genutzt. Mit einem typisierten DataSet (wie bei dir) vereinfacht sich das Ganze etwas. Außerdem habe ich anstelle des NuGet-Paketes eine DependencyProperty eingebaut.

    XAML:

    <Window x:Class="WpfApp1.Window028"
            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:WpfApp028"
            mc:Ignorable="d"
            Title="Window027" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TreeView ItemsSource="{Binding RootItems}" local:ViewModel.TreeViewBevior="True">
        <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="Bold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </TreeView.ItemContainerStyle>
          <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding TreeViewName}" />
            </HierarchicalDataTemplate>
          </TreeView.ItemTemplate>
        </TreeView>
        <Grid Grid.Column="1" DataContext="{Binding Detail}">
          <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
          <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
          <DataGrid Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding DataGridTabelle}"/>
        </Grid>
      </Grid>
    </Window>

    Klassen:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace WpfApp028
    {
      public class ViewModel : INotifyPropertyChanged
      {
        public ViewModel()
        {
          Model m = new Model();
          var ds = m.DatenTabelle;
          ObservableCollection<Data> col = new ObservableCollection<Data>();
          foreach (DataRow row in ds.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
          cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
        }
    
        private CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView RootItems { get => cvs.View; }
    
        private Data _details = null;
        public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
        #region attached behavior
    
        public static readonly DependencyProperty TreeViewBeviorProperty =
          DependencyProperty.RegisterAttached("TreeViewBevior",
            typeof(bool), typeof(TreeView), new UIPropertyMetadata(false, OnTreeViewBevior));
        public static bool GetTreeViewBevior(DependencyObject obj) => (bool)obj.GetValue(TreeViewBeviorProperty);
        public static void SetTreeViewBevior(DependencyObject obj, bool value) => obj.SetValue(TreeViewBeviorProperty, value);
        private static void OnTreeViewBevior(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
          var tv = depObj as TreeView;
          if (tv == null) return;
          if ((e.NewValue is bool) && (bool)(e.NewValue)) tv.SelectedItemChanged += OnLblMouseDown; else tv.SelectedItemChanged -= OnLblMouseDown;
        }
    
        private static void OnLblMouseDown(Object sender, EventArgs 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;
        }
    
        #endregion
    
        #region OnPropertyChanged
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
        #endregion
      }
    
      public class Data
      {
        public Data(DataRow row) { this.row = row; this.dt = row.Table; this.ds = row.Table.DataSet; }
        DataSet ds;
        DataTable dt;
        DataRow row;
        public Int32 TreeViewRootID { get => row.Field<int>("TreeViewRootID"); set { row["TreeViewRootID"] = value; } }
        public Int32 TreeViewRootChildrenID { get => row.Field<int>("TreeViewRootChildrenID"); set { row["TreeViewRootChildrenID"] = value; } }
        public string TreeViewName { get => row.Field<string>("TreeViewName"); set { row["TreeViewName"] = value; } }
        public object ChildrenItems => new ObservableCollection<Data>(from d in dt.AsEnumerable() where d.Field<int>("TreeViewRootChildrenID") == this.TreeViewRootID select new Data(d));
        public DataView DataGridTabelle
        {
          get
          {
            DataTable dt2 = ds.Tables["DataGridTabelle"].Clone();
            var dv = new DataView(ds.Tables["DataGridTabelle"]);
            var req = from dg in ds.Tables["DataGridTabelle"].AsEnumerable()
                      join zu in ds.Tables["Zuordnung"].AsEnumerable()
                        on dg.Field<int>("GridColumn1ID") equals zu.Field<int>("ZuGridColumn1ID")
                      where zu.Field<int>("ZuTreeViewRootID") == TreeViewRootID
                      select dg;
            foreach (var item in req) dt2.Rows.Add(item.ItemArray);
            return dt2.AsDataView();
          }
        }
        public bool IsExpanded { get; set; } = true;
        public bool IsSelected { get; set; }
      }
    
      public class Model
      {
        public Model()
        {
          // generate untyped DataSet
          DatenTabelle = new DataSet();
          DataTable dtTV = new DataTable("TreeViewTabelle");
          DatenTabelle.Tables.Add(dtTV);
          dtTV.Columns.Add("ID", typeof(int));
          dtTV.Columns.Add("TreeViewRootID", typeof(int));
          dtTV.Columns.Add("TreeViewRootChildrenID", typeof(int));
          dtTV.Columns.Add("TreeViewName", typeof(string));
          DataTable dtDG = new DataTable("DataGridTabelle");
          DatenTabelle.Tables.Add(dtDG);
          dtDG.Columns.Add("ID", typeof(int));
          dtDG.Columns.Add("GridColumn1ID", typeof(int));
          dtDG.Columns.Add("GridColumn2Text1", typeof(string));
          dtDG.Columns.Add("GridColumn3Text2", typeof(string));
          DataTable dtZO = new DataTable("Zuordnung");
          DatenTabelle.Tables.Add(dtZO);
          dtZO.Columns.Add("ID", typeof(int));
          dtZO.Columns.Add("ZuTreeViewRootID", typeof(int));
          dtZO.Columns.Add("ZuGridColumn1ID", typeof(int));
          // load data
          LoadData();
        }
    
        public DataSet DatenTabelle { get; set; }
    
        private void LoadData()
        {
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(1, 100, 0, "Root1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(2, 101, 0, "Root2");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(3, 102, 0, "Root3");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(4, 103, 100, "Children1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(5, 104, 100, "Children2");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(6, 105, 104, "Children2.1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(7, 106, 101, "Children1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(8, 107, 106, "Children1.1");
          DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(9, 108, 107, "Children1.1.1");
    
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(1, 100, "Test1", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(2, 101, "Test2", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(3, 102, "Test3", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(4, 103, "Test4", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(5, 104, "Test5", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(6, 105, "Test6", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(7, 106, "Test7", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(8, 107, "Test8", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(9, 108, "Test9", "Test1");
          DatenTabelle.Tables["DataGridTabelle"].Rows.Add(10, 109, "Test10", "Test1");
    
          DatenTabelle.Tables["Zuordnung"].Rows.Add(1, 103, 100);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(2, 103, 101);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(3, 103, 102);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(4, 105, 103);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(5, 105, 104);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(6, 105, 105);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(7, 105, 100);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(8, 101, 107);
          DatenTabelle.Tables["Zuordnung"].Rows.Add(9, 101, 108);
        }
      }
    }


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

    Montag, 11. Januar 2021 11:12
  • Hallo Mezzo80,

    Ich nehme an, dass Peters Antwort Dir weitergeholfen hat. Bitte lass uns wissen, wenn Du zusätzliche Fragen hast.

    Gruß,

    Ivan Dragov

    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Freitag, 22. Januar 2021 06:37
    Administrator
  • Hallo

    mir ist aufgefallen das ich des Treeview immer so brauche.

    Wie macht man sowas als Steuerelement? So das ich es in VS in der Toolbox habe und er nur noch einfügen muss.

    Gruß

    Mezzo

    Samstag, 27. Februar 2021 11:58
  • Hi Mezo,
    so etwas kann man erreichen, wenn man die gewünschten Funktionalitäten in einem UserControl kapselt, am besten in einer separaten Bibliothek. Nach der fehlerfreien Übersetzung der Bibliotheks-Anwendung steht das UserControl im Werkzeugkasten bereit und kann eingefügt werden.

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

    Sonntag, 28. Februar 2021 08:40
  • Hallo Peter danke für deine Antwort das werde ich mir Später im Angriff nehmen und bei fragen ein neues Forum Thema aufmachen.

    Ich hab noch ein Problem mit den TreeView nun habe ich ein paar Felder hinzugefügt und im WPF wird mit das ViewModel blau unterstrichen. Denke es liegt bestimmt irgendwas ein die Einstellungen.

    Siehe Bild:

    WPF code:

    <Window x:Class="TreeView_Test.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_Test"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TreeView ItemsSource="{Binding RootItems}" local:ViewModel.TreeViewBevior="True">
                <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="Bold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding TreeViewName}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <Grid Grid.Column="1" DataContext="{Binding Detail}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
                <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewText}"/>
    
            </Grid>
        </Grid>
    </Window>

    ViewModel.cs

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace TreeView_Test
    {
        public class ViewModel : INotifyPropertyChanged
        {
            public ViewModel()
            {
                Model m = new Model();
                var ds = m.DatenTabelle;
                ObservableCollection<Data> col = new ObservableCollection<Data>();
                foreach (DataRow row in ds.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
                cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private Data _details = null;
            public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
            #region attached behavior
    
            public static readonly DependencyProperty TreeViewBeviorProperty =
              DependencyProperty.RegisterAttached("TreeViewBevior",
                typeof(bool), typeof(TreeView), new UIPropertyMetadata(false, OnTreeViewBevior));
            public static bool GetTreeViewBevior(DependencyObject obj) => (bool)obj.GetValue(TreeViewBeviorProperty);
            public static void SetTreeViewBevior(DependencyObject obj, bool value) => obj.SetValue(TreeViewBeviorProperty, value);
            private static void OnTreeViewBevior(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
            {
                var tv = depObj as TreeView;
                if (tv == null) return;
                if ((e.NewValue is bool) && (bool)(e.NewValue)) tv.SelectedItemChanged += OnLblMouseDown; else tv.SelectedItemChanged -= OnLblMouseDown;
            }
    
            private static void OnLblMouseDown(Object sender, EventArgs 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;
            }
    
            #endregion
    
            #region OnPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
            #endregion
        }
    
        public class Data
        {
            public Data(DataRow row) { this.row = row; this.dt = row.Table; this.ds = row.Table.DataSet; }
            DataSet ds;
            DataTable dt;
            DataRow row;
            public Int32 TreeViewRootID { get => row.Field<int>("TreeViewRootID"); set { row["TreeViewRootID"] = value; } }
            public Int32 TreeViewRootChildrenID { get => row.Field<int>("TreeViewRootChildrenID"); set { row["TreeViewRootChildrenID"] = value; } }
            public string TreeViewName { get => row.Field<string>("TreeViewName"); set { row["TreeViewName"] = value; } }
            public string TreeViewText { get => row.Field<string>("TreeViewText"); set { row["TreeViewText"] = value; } }
            public string TreeViewVideo { get => row.Field<string>("TreeViewVideo"); set { row["TreeViewVideo"] = value; } }
            public object ChildrenItems => new ObservableCollection<Data>(from d in dt.AsEnumerable() where d.Field<int>("TreeViewRootChildrenID") == this.TreeViewRootID select new Data(d));
    
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    
        public class Model
        {
            public Model()
            {
                // generate untyped DataSet
                DatenTabelle = new DataSet();
                DataTable dtTV = new DataTable("TreeViewTabelle");
                DatenTabelle.Tables.Add(dtTV);
                dtTV.Columns.Add("ID", typeof(int));
                dtTV.Columns.Add("TreeViewRootID", typeof(int));
                dtTV.Columns.Add("TreeViewRootChildrenID", typeof(int));
                dtTV.Columns.Add("TreeViewName", typeof(string));
                dtTV.Columns.Add("TreeViewText", typeof(string));
                dtTV.Columns.Add("TreeViewVideo", typeof(string));
    
                // load data
                LoadData();
            }
    
            public DataSet DatenTabelle { get; set; }
    
            private void LoadData()
            {
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(1, 100, 0, "Root1","","");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(2, 101, 0, "Root2","","");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(3, 102, 0, "Root3","","");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(4, 103, 100, "Children1","Text1","Video1");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(5, 104, 100, "Children2", "Text2", "Video2");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(6, 105, 104, "Children2.1", "Text3", "Video3");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(7, 106, 101, "Children1", "Text4", "Video4");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(8, 107, 106, "Children1.1", "Text5", "Video5");
                DatenTabelle.Tables["TreeViewTabelle"].Rows.Add(9, 108, 107, "Children1.1.1", "Text6", "Video6");
    
     
            }
        }
    }
    

    Ich denke im Code habe ich alles richtig gemacht wenn ich auf Start gehe dann funktioniert das auch. 

    Dann wird es eher wohl an die Einstellungen von Visual Studio sein.

    Gruß

    Mezzo

    Sonntag, 28. Februar 2021 10:31
  • Hi Mezzo,
    der Designer (Anzeige im Studio) arbeitet genau so wie zur Ausführungszeit. Er holt sich alle Details für die Anzeige, instanziiert sie bei Notwendigkeit und nutzt sie dann für die Sicht im Studio. Dazu müssen natürlich die erforderliche dll's bzw. exe'n fehlerfrei übersetzt vorliegen. Wenn du jedoch im Code änderst, dann befinden sich die dll's bzw. exe'n in einem nicht übersetzten Zustand und der Designer kann sie nicht nutzen. Die Syntaxprüfung dagegen findet die Details im Code und zeigt deshalb erst einmal keinen Syntaxfehler an. Mit der Wellenlinie wird lediglich gezeigt, dass wegen fehlender fehlerfreier Übersetzung keine Designanzeige möglich ist. Wenn du nach Änderungen einen Übersetzungslauf (Build bzw. Rebuild) ausführst, verschwindet die Wellenlinie (jedenfalls meistens). Da vor einer Ausführung vorher eine Compilierung gestartet wird, wenn es Änderungen gab, stehen dann zur Ausführung auch die fehlerfrei übersetzten dll's und exe'n zur Verfügung und das Programm läuft problemlos.

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

    Sonntag, 28. Februar 2021 10:58
  • Hallo Peter

    Das ist ja das Problem selbst wenn es gestartet wurde ist es immer noch Blau unterstrichen.

    Ich hab auch schon die Dateien aus dem Bin Verzeichnis gelöscht so das es neu erstellt wird, selbst da ist es dann immer noch Blau unterstrichen.

    Wenn es gestartet ist dann funktioniert es zwar. Aber es stört wenn man wieder zurück im VS ist und weiter arbeiten will.

    Was kann man da machen?

    Gruß

    Mezzo 

    Sonntag, 28. Februar 2021 14:07
  • Hallo

    Ich versuche gerade diese Sache mit dem DataSet1 Designer darzustellen leider komme ich da nicht so Weiter.

    Ich habe ein paar Sachen schon geändert.

    Schritt 1:

            public ViewModel()
            {
                //Model m = new Model();
                DataSet1 m = new DataSet1();
                
                //var ds = m.DatenTabelle;
                ObservableCollection<Data> col = new ObservableCollection<Data>();
                //foreach (DataRow row in ds.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
                foreach (DataRow row in m.TreeViewTabelle.Rows) col.Add(new Data(row));
                cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
            }

    Nun weiß ich nicht wie ich die Klasse Data ändern kann.

        public class Data
        {
            public Data(DataRow row) { this.row = row; this.dt = row.Table; this.ds = row.Table.DataSet; }
            DataSet ds;
            DataTable dt;
            DataRow row;
    
           
            
            
            
            public Int32 TreeViewRootID { get => row.Field<int>("TreeViewRootID"); set { row["TreeViewRootID"] = value; } }
            public Int32 TreeViewRootChildrenID { get => row.Field<int>("TreeViewRootChildrenID"); set { row["TreeViewRootChildrenID"] = value; } }
            public string TreeViewName { get => row.Field<string>("TreeViewName"); set { row["TreeViewName"] = value; } }
            public object ChildrenItems => new ObservableCollection<Data>(from d in dt.AsEnumerable() where d.Field<int>("TreeViewRootChildrenID") == this.TreeViewRootID select new Data(d));
            public DataView DataGridTabelle
            {
                get
                {
                    
                    DataTable dt2 = ds.Tables["DataGridTabelle"].Clone();
                    var dv = new DataView(ds.Tables["DataGridTabelle"]);
                    var req = from dg in ds.Tables["DataGridTabelle"].AsEnumerable()
                              join zu in ds.Tables["Zuordnung"].AsEnumerable()
                                on dg.Field<int>("GridColumn1ID") equals zu.Field<int>("ZuGridColumn1ID")
                              where zu.Field<int>("ZuTreeViewRootID") == TreeViewRootID
                              select dg;
                    foreach (var item in req) dt2.Rows.Add(item.ItemArray);
                    return dt2.AsDataView();
                }
            }
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }

    DataSet = ds habe ich schon versucht auf DataSet1 = ds zu ändern haber das hilft nicht.

    können Sie mir Bitte ein diese obere Beispiel mit einen DataSet1 Designer geben.

    Gruß

    Mezzo

    Dienstag, 18. Mai 2021 05:59
  • Hi,
    wenn den DataSet Designer nutzt, dann wird ein typisiertes DataSet erzeugt. Dieses typisierte DataSet erbt von der DataSet-Klasse. Damit können alle nicht typisierten Techniken auch angewandt werden und der Code ist unverändert nutzbar. Wichtig ist lediglich, dass alle Member auch die richtigen Namen haben. Ich vermute, dass das bei dir nicht der Fall ist und Fehler geworfen werden, die du bisher noch nicht gezeigt hast.

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

    Dienstag, 18. Mai 2021 10:31
  • Hallo

    Ich sende dir mein ganzen Code irgendwas habe ich Falsch gemacht da mit nichts angezeigt wird.

    MainWindow.XAML:

    <Window x:Class="Mezzo_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:Mezzo_TreeView"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TreeView ItemsSource="{Binding RootItems}" local:ViewModel.TreeViewBevior="True">
                <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="Bold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding TreeViewName}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <Grid Grid.Column="1" DataContext="{Binding Detail}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
                <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
                <DataGrid Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding DataGridTabelle}"/>
            </Grid>
        </Grid>
    </Window>
    

    ViewModel.cs

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace Mezzo_TreeView
    {
        public class ViewModel : INotifyPropertyChanged
        {
            public DataSet1 m = new DataSet1();
            public ViewModel()
            {
                //Model test = new Model();
                // DataSet1 m = new DataSet1();
    
                //var ds = m.DatenTabelle;
                //var ds = m.
                ObservableCollection<Data> col = new ObservableCollection<Data>();
                foreach (DataRow row in m.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
                cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
                loadData2();
            }
    
            public void loadData2()
            {
                m.Tables["TreeViewTabelle"].Rows.Add(1, 100, 0, "Root1");
                m.Tables["TreeViewTabelle"].Rows.Add(2, 101, 0, "Root2");
                m.Tables["TreeViewTabelle"].Rows.Add(3, 102, 0, "Root3");
                m.Tables["TreeViewTabelle"].Rows.Add(4, 103, 100, "Children1");
                m.Tables["TreeViewTabelle"].Rows.Add(5, 104, 100, "Children2");
                m.Tables["TreeViewTabelle"].Rows.Add(6, 105, 104, "Children2.1");
                m.Tables["TreeViewTabelle"].Rows.Add(7, 106, 101, "Children1");
                m.Tables["TreeViewTabelle"].Rows.Add(8, 107, 106, "Children1.1");
                m.Tables["TreeViewTabelle"].Rows.Add(9, 108, 107, "Children1.1.1");
    
                m.Tables["DataGridTabelle"].Rows.Add(1, 100, "Test1", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(2, 101, "Test2", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(3, 102, "Test3", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(4, 103, "Test4", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(5, 104, "Test5", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(6, 105, "Test6", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(7, 106, "Test7", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(8, 107, "Test8", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(9, 108, "Test9", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(10, 109, "Test10", "Test1");
    
                m.Tables["Zuordnung"].Rows.Add(1, 103, 100);
                m.Tables["Zuordnung"].Rows.Add(2, 103, 101);
                m.Tables["Zuordnung"].Rows.Add(3, 103, 102);
                m.Tables["Zuordnung"].Rows.Add(4, 105, 103);
                m.Tables["Zuordnung"].Rows.Add(5, 105, 104);
                m.Tables["Zuordnung"].Rows.Add(6, 105, 105);
                m.Tables["Zuordnung"].Rows.Add(7, 105, 100);
                m.Tables["Zuordnung"].Rows.Add(8, 101, 107);
                m.Tables["Zuordnung"].Rows.Add(9, 101, 108);
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private Data _details = null;
            public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
            #region attached behavior
    
            public static readonly DependencyProperty TreeViewBeviorProperty =
              DependencyProperty.RegisterAttached("TreeViewBevior",
                typeof(bool), typeof(TreeView), new UIPropertyMetadata(false, OnTreeViewBevior));
            public static bool GetTreeViewBevior(DependencyObject obj) => (bool)obj.GetValue(TreeViewBeviorProperty);
            public static void SetTreeViewBevior(DependencyObject obj, bool value) => obj.SetValue(TreeViewBeviorProperty, value);
            private static void OnTreeViewBevior(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
            {
                var tv = depObj as TreeView;
                if (tv == null) return;
                if ((e.NewValue is bool) && (bool)(e.NewValue)) tv.SelectedItemChanged += OnLblMouseDown; else tv.SelectedItemChanged -= OnLblMouseDown;
            }
    
            private static void OnLblMouseDown(Object sender, EventArgs 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;
            }
    
            #endregion
    
            #region OnPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
            #endregion
        }
    
        public class Data
        {
            public Data(DataRow row) { this.row = row; this.dt = row.Table; this.ds = (DataSet1)row.Table.DataSet; }
            DataSet1 ds;
            DataTable dt;
            DataRow row;
            public Int32 TreeViewRootID { get => row.Field<int>("TreeViewRootID"); set { row["TreeViewRootID"] = value; } }
            public Int32 TreeViewRootChildrenID { get => row.Field<int>("TreeViewRootChildrenID"); set { row["TreeViewRootChildrenID"] = value; } }
            public string TreeViewName { get => row.Field<string>("TreeViewName"); set { row["TreeViewName"] = value; } }
            public object ChildrenItems => new ObservableCollection<Data>(from d in dt.AsEnumerable() where d.Field<int>("TreeViewRootChildrenID") == this.TreeViewRootID select new Data(d));
            public DataView DataGridTabelle
            {
                get
                {
                    DataTable dt2 = ds.Tables["DataGridTabelle"].Clone();
                    var dv = new DataView(ds.Tables["DataGridTabelle"]);
                    var req = from dg in ds.Tables["DataGridTabelle"].AsEnumerable()
                              join zu in ds.Tables["Zuordnung"].AsEnumerable()
                                on dg.Field<int>("GridColumn1ID") equals zu.Field<int>("ZuGridColumn1ID")
                              where zu.Field<int>("ZuTreeViewRootID") == TreeViewRootID
                              select dg;
                    foreach (var item in req) dt2.Rows.Add(item.ItemArray);
                    return dt2.AsDataView();
                }
            }
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    }
    

    Was habe ich da falsch gemacht? und wie mach ich das Richtig

    Gruß

    Mezzo

    Dienstag, 18. Mai 2021 19:15
  • Hi,
    da kann auch nichts angezeigt werden, da du die Liste der anzuzeigenden Daten aus einer leeren Tabelle "TreeViewTabelle" erzuegst. Erst danach lädst du die Daten, was dann natürlich unwirksam ist.

    public class ViewModel : INotifyPropertyChanged { public DataSet1 m = new DataSet1(); public ViewModel() { //Model test = new Model(); // DataSet1 m = new DataSet1(); //var ds = m.DatenTabelle; //var ds = m. ObservableCollection<Data> col = new ObservableCollection<Data>(); foreach (DataRow row in m.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row)); cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);

    //-------------------------------- loadData2();

    //-------------------------------- }

    Lade erst mal die Daten, bevor du die Liste der anzuzeigenden Daten erzeugst.

      public class ViewModel : INotifyPropertyChanged
      {
        public DataSet1 m = new DataSet1();
        public ViewModel()
        {
    
    //----------------------------
          loadData2(); 
    //----------------------------
    
          ObservableCollection<Data> col = new ObservableCollection<Data>();
          foreach (DataRow row in m.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
          cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == 0);
        }


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


    Dienstag, 18. Mai 2021 19:55
  • Super danke es Funktioniert, aber nun habe ich versucht es mit dem DataSet1 Designer den Datagrid auszulesen.

    Ich habe ja im DataSet1 ja eine Verbindung zu die andern Tabellen, also sollte es doch Automatisch mir dann die Daten in DataGrid anzeigen wenn man in TreeView ein Notes auswählt.

    Hier mein Beispiel

    XAML:

    <Window x:Class="Mezzo_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:Mezzo_TreeView"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
        <Window.Resources>
            <local:DataSet1 x:Key="dataSet1"/>
            <CollectionViewSource x:Key="dataGridTabelleViewSource" Source="{Binding DataGridTabelle, Source={StaticResource dataSet1}}"/>
        </Window.Resources>
        <Window.DataContext>
            <local:ViewModel/>
        </Window.DataContext>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TreeView ItemsSource="{Binding RootItems}" local:ViewModel.TreeViewBevior="True">
                <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="Bold" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TreeView.ItemContainerStyle>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
                        <TextBlock Text="{Binding TreeViewName}" />
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <Grid Grid.Column="1" DataContext="{Binding Detail}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TreeViewRootID}" IsReadOnly="True"/>
                <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TreeViewName}"/>
                <DataGrid Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding DataGridTabelle}" Margin="0,0,0,201"/>
                <DataGrid x:Name="dataGridTabelleDataGrid" AutoGenerateColumns="False" Grid.ColumnSpan="2" EnableRowVirtualization="True" ItemsSource="{Binding Source={StaticResource dataGridTabelleViewSource}}" Margin="0,171,-4,0" Grid.Row="2" RowDetailsVisibilityMode="VisibleWhenSelected">
                    <DataGrid.Columns>
                        <DataGridTextColumn x:Name="iDColumn" Binding="{Binding ID}" Header="ID" Width="SizeToHeader"/>
                        <DataGridTextColumn x:Name="gridColumn1IDColumn" Binding="{Binding GridColumn1ID}" Header="Grid Column 1 ID" Width="SizeToHeader"/>
                        <DataGridTextColumn x:Name="gridColumn2Text1Column" Binding="{Binding GridColumn2Text1}" Header="Grid Column 2 Text 1" Width="SizeToHeader"/>
                        <DataGridTextColumn x:Name="gridColumn3Text2Column" Binding="{Binding GridColumn3Text2}" Header="Grid Column 3 Text 2" Width="SizeToHeader"/>
                    </DataGrid.Columns>
                </DataGrid>
            </Grid>
        </Grid>
    </Window>
    


    ViewModel.cs:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace Mezzo_TreeView
    {
        public class ViewModel : INotifyPropertyChanged
        {
            public DataSet1 m = new DataSet1();
            public ViewModel()
            {
                //Model test = new Model();
                // DataSet1 m = new DataSet1();
                loadData2();
                //var ds = m.DatenTabelle;
                //var ds = m.
                ObservableCollection<Data> col = new ObservableCollection<Data>();
                foreach (DataRow row in m.Tables["TreeViewTabelle"].Rows) col.Add(new Data(row));
                cvs.Source = col.Where((d) => d.TreeViewRootChildrenID == "0");
               
            }
    
            public void loadData2()
            {
                m.Tables["TreeViewTabelle"].Rows.Add(1, 100, 0, "Root1");
                m.Tables["TreeViewTabelle"].Rows.Add(2, 101, 0, "Root2");
                m.Tables["TreeViewTabelle"].Rows.Add(3, 102, 0, "Root3");
                m.Tables["TreeViewTabelle"].Rows.Add(4, 103, 100, "Children1");
                m.Tables["TreeViewTabelle"].Rows.Add(5, 104, 100, "Children2");
                m.Tables["TreeViewTabelle"].Rows.Add(6, 105, 104, "Children2.1");
                m.Tables["TreeViewTabelle"].Rows.Add(7, 106, 101, "Children1");
                m.Tables["TreeViewTabelle"].Rows.Add(8, 107, 106, "Children1.1");
                m.Tables["TreeViewTabelle"].Rows.Add(9, 108, 107, "Children1.1.1");
    
                m.Tables["DataGridTabelle"].Rows.Add(1, 100, "Test1", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(2, 101, "Test2", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(3, 102, "Test3", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(4, 103, "Test4", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(5, 104, "Test5", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(6, 105, "Test6", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(7, 106, "Test7", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(8, 107, "Test8", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(9, 108, "Test9", "Test1");
                m.Tables["DataGridTabelle"].Rows.Add(10, 109, "Test10", "Test1");
    
                m.Tables["Zuordnung"].Rows.Add(1, 103, 100);
                m.Tables["Zuordnung"].Rows.Add(2, 103, 101);
                m.Tables["Zuordnung"].Rows.Add(3, 103, 102);
                m.Tables["Zuordnung"].Rows.Add(4, 105, 103);
                m.Tables["Zuordnung"].Rows.Add(5, 105, 104);
                m.Tables["Zuordnung"].Rows.Add(6, 105, 105);
                m.Tables["Zuordnung"].Rows.Add(7, 105, 100);
                m.Tables["Zuordnung"].Rows.Add(8, 101, 107);
                m.Tables["Zuordnung"].Rows.Add(9, 101, 108);
            }
    
            private CollectionViewSource cvs = new CollectionViewSource();
            public ICollectionView RootItems { get => cvs.View; }
    
            private Data _details = null;
            public Data Detail { get => this._details; set { this._details = value; OnPropertyChanged(); } }
    
            #region attached behavior
    
            public static readonly DependencyProperty TreeViewBeviorProperty =
              DependencyProperty.RegisterAttached("TreeViewBevior",
                typeof(bool), typeof(TreeView), new UIPropertyMetadata(false, OnTreeViewBevior));
            public static bool GetTreeViewBevior(DependencyObject obj) => (bool)obj.GetValue(TreeViewBeviorProperty);
            public static void SetTreeViewBevior(DependencyObject obj, bool value) => obj.SetValue(TreeViewBeviorProperty, value);
            private static void OnTreeViewBevior(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
            {
                var tv = depObj as TreeView;
                if (tv == null) return;
                if ((e.NewValue is bool) && (bool)(e.NewValue)) tv.SelectedItemChanged += OnLblMouseDown; else tv.SelectedItemChanged -= OnLblMouseDown;
            }
    
            private static void OnLblMouseDown(Object sender, EventArgs 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;
            }
    
            #endregion
    
            #region OnPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
            #endregion
        }
    
        public class Data
        {
            public Data(DataRow row) { this.row = row; this.dt = row.Table; this.ds = (DataSet1)row.Table.DataSet; }
            DataSet1 ds;
            DataTable dt;
            DataRow row;
            public string TreeViewRootID { get => row.Field<string>("TreeViewRootID"); set { row["TreeViewRootID"] = value; } }
            public string TreeViewRootChildrenID { get => row.Field<string>("TreeViewRootChildrenID"); set { row["TreeViewRootChildrenID"] = value; } }
            public string TreeViewName { get => row.Field<string>("TreeViewName"); set { row["TreeViewName"] = value; } }
            public object ChildrenItems => new ObservableCollection<Data>(from d in dt.AsEnumerable() where d.Field<string>("TreeViewRootChildrenID") == this.TreeViewRootID select new Data(d));
            public DataView DataGridTabelle
            {
                get
                {
                    DataTable dt2 = ds.Tables["DataGridTabelle"].Clone();
                    var dv = new DataView(ds.Tables["DataGridTabelle"]);
                    var req = from dg in ds.Tables["DataGridTabelle"].AsEnumerable()
                              join zu in ds.Tables["Zuordnung"].AsEnumerable()
                                on dg.Field<string>("GridColumn1ID") equals zu.Field<string>("ZuGridColumn1ID")
                              where zu.Field<string>("ZuTreeViewRootID") == TreeViewRootID
                              select dg;
                    foreach (var item in req) dt2.Rows.Add(item.ItemArray);
                    return dt2.AsDataView();
                }
            }
            public bool IsExpanded { get; set; } = true;
            public bool IsSelected { get; set; }
        }
    }
    


    Normal sollte man doch diesen Code nicht mehr brauchen oder?

            public DataView DataGridTabelle
            {
                get
                {
                    DataTable dt2 = ds.Tables["DataGridTabelle"].Clone();
                    var dv = new DataView(ds.Tables["DataGridTabelle"]);
                    var req = from dg in ds.Tables["DataGridTabelle"].AsEnumerable()
                              join zu in ds.Tables["Zuordnung"].AsEnumerable()
                                on dg.Field<string>("GridColumn1ID") equals zu.Field<string>("ZuGridColumn1ID")
                              where zu.Field<string>("ZuTreeViewRootID") == TreeViewRootID
                              select dg;
                    foreach (var item in req) dt2.Rows.Add(item.ItemArray);
                    return dt2.AsDataView();
                }
            }

    Für was wird das noch gebraucht wenn im DataSet1 schon die Verbindung gemacht wurde.

    Ich kann mir nur vorstellen das man die Auswahl (Selected) in DataSet1 übergeben muss.

    Gruß

    Mezzo

    Dienstag, 18. Mai 2021 20:22
  • Hi,
    mit dem DataSet Designer erzeugst du eine Klasse, mit der auf die Werte der Objekte im DataSet (Tabellen, Spalten) typsicher zugegriffen werden kann. Da diese Klassen von den Basisklassen erben, kann man auch mit den Basistechniken zugreifen, z.B.

    // untypisiert (Basisklasse)
    
    row.Field<string>("TreeViewRootID")
    
    // typisiert (von Designer erzeugte Klasse)
    
    row.TreeViewRootID

    Der Vorteil des typisierten Zugriffs ist die Erkennung von Fehlern bei der Typumwandlung bereits zur Entwurfszeit und auch eine höhere Verarbeitungsgeschwindigkeit, was sich bei größeren Datenmengen bemerkbar machen kann.

    aber nun habe ich versucht es mit dem DataSet1 Designer den Datagrid auszulesen.

    Die vom DataSet Designer erzeugte Klasse kann man nicht auslesen, außer sich den Quellcode anschauen. Vom Typ dieser vom DataSet Designer erzeugten Klasse muss man erst einmal eine Instanz erzeugt, diese dann mit Daten füllen, z.B. mit dem TableAdapter (oder auch mit den Basismethoden wie DataAdapter).

    Ich habe ja im DataSet1 ja eine Verbindung zu die andern Tabellen, also sollte es doch Automatisch mir dann die Daten in DataGrid anzeigen wenn man in TreeView ein Notes auswählt.

    ...

    Für was wird das noch gebraucht wenn im DataSet1 schon die Verbindung gemacht wurde.

    Die Daten in einem DataSet liegen in "flachen" Listen ohne hierarchische Beziehungen vor. Die logische Struktur der Daten ist in deinem Fall lediglich durch Zeiger in einer weiteren Tabelle "Zuordnung" abgelegt. Zusätzlich geibt es noch Relation-Objekte. Zur Darstellung im TreeView ist aber eine hierarchische Objektstruktur erforderlich, die das DataSet nicht liefert. Da musst du per Code umwandeln.

    Ich kann mir nur vorstellen das man die Auswahl (Selected) in DataSet1 übergeben muss.

    Das ist etwas wirres Deutsch, was du mal übersetzen solltest, damit man aus der "Übersetzung" einen Algorithmus ableiten und implementieren kann.

    Für dein typisiertes DataSet könnte die Klasse Data so aussehen.

      public class Data
      {
        public Data(DataSet1.TreeViewTabelleRow row) { this.row = row; this.dt = (DataSet1.TreeViewTabelleDataTable)row.Table; this.ds = (DataSet1)row.Table.DataSet; }
        DataSet1 ds;
        DataSet1.TreeViewTabelleDataTable dt;
        DataSet1.TreeViewTabelleRow row;
        public Int32 TreeViewRootID { get => row.TreeViewRootID; set { row.TreeViewRootID = value; } }
        public Int32 TreeViewRootChildrenID { get => row.TreeViewRootChildrenID; set { row.TreeViewRootChildrenID = value; } }
        public string TreeViewName { get => row.TreeViewName; set { row.TreeViewName = value; } }
        public object ChildrenItems => new ObservableCollection<Data>(from d in dt where d.TreeViewRootChildrenID == this.TreeViewRootID select new Data(d));
        public DataView DataGridTabelle
        {
          get
          {
            DataTable dt2 = ds.DataGridTabelle.Clone();
            var dv = new DataView(ds.DataGridTabelle);
            var req = from dg in ds.DataGridTabelle
                      join zu in ds.Zuordnung on dg.GridColumn1ID equals zu.ZuGridColumn1ID
                      where zu.ZuTreeViewRootID == TreeViewRootID
                      select dg;
            foreach (var item in req) dt2.Rows.Add(item.ItemArray);
            return dt2.AsDataView();
          }
        }
        public bool IsExpanded { get; set; } = true;
        public bool IsSelected { get; set; }
      }

    Es gibt aber auch noch andere Lösungswege. Man kann beispielsweise auf die Eigenschaften in der Data-Klasse verzichten, die die einzelnen Werte bereitstellen und dafür lediglich eine row-Eigenschaft bereitstellen. In der UI muss dann aber über row.Eigenschaft gebunden werden.

    Z.B. könnte die Klasse Data so aussehen:

      public class Data
      {
        public Data(DataSet1.TreeViewTabelleRow row) { this.Row = row; this.dt = (DataSet1.TreeViewTabelleDataTable)row.Table; this.ds = (DataSet1)row.Table.DataSet; }
        DataSet1 ds;
        DataSet1.TreeViewTabelleDataTable dt;
        public DataSet1.TreeViewTabelleRow Row { get; set; }
        public object ChildrenItems => new ObservableCollection<Data>(from d in dt where d.TreeViewRootChildrenID == this.Row.TreeViewRootID select new Data(d));
        public DataView DataGridTabelle
        {
          get
          {
            DataTable dt2 = ds.DataGridTabelle.Clone();
            var dv = new DataView(ds.DataGridTabelle);
            var req = from dg in ds.DataGridTabelle
                      join zu in ds.Zuordnung on dg.GridColumn1ID equals zu.ZuGridColumn1ID
                      where zu.ZuTreeViewRootID == Row.TreeViewRootID
                      select dg;
            foreach (var item in req) dt2.Rows.Add(item.ItemArray);
            return dt2.AsDataView();
          }
        }
        public bool IsExpanded { get; set; } = true;
        public bool IsSelected { get; set; }
      }

    Der XAML-Code im Window müsste dann so aussehen:

      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TreeView ItemsSource="{Binding RootItems}" local:ViewModel.TreeViewBevior="True">
          <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="Bold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </TreeView.ItemContainerStyle>
          <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildrenItems}">
              <TextBlock Text="{Binding Row.TreeViewName}" />
            </HierarchicalDataTemplate>
          </TreeView.ItemTemplate>
        </TreeView>
        <Grid Grid.Column="1" DataContext="{Binding Detail}">
          <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Label Grid.Row="0" Grid.Column="0" Content="TreeViewRootID: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Row.TreeViewRootID}" IsReadOnly="True"/>
          <Label Grid.Row="1" Grid.Column="0" Content="TreeViewName: " HorizontalAlignment="Right"/>
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Row.TreeViewName}"/>
          <DataGrid Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding DataGridTabelle}"/>
        </Grid>
      </Grid>


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


    Mittwoch, 19. Mai 2021 05:12