Benutzer mit den meisten Antworten
TreeView Baumstruktur

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.
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- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 15. Januar 2021 14:03
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 22. Januar 2021 06:34
-
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- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 15. Januar 2021 14:04
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 22. Januar 2021 06: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- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 15. Januar 2021 14:04
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 22. Januar 2021 06:35
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- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 15. Januar 2021 14:03
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 22. Januar 2021 06:34
-
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?
-
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
-
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- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 15. Januar 2021 14:04
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 22. Januar 2021 06:35
-
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?
-
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 -
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- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Freitag, 15. Januar 2021 14:04
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Freitag, 22. Januar 2021 06:35
-
Hallo Mezzo80,
Ich nehme an, dass Peters Antwort Dir weitergeholfen hat. Bitte lass uns wissen, wenn Du zusätzliche Fragen hast.
Gruß,
Ivan DragovBitte 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.
-
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 -
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
-
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 -
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
-
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
-
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 -
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
-
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
- Bearbeitet Peter Fleischer Dienstag, 18. Mai 2021 19:57
-
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
-
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- Bearbeitet Peter Fleischer Mittwoch, 19. Mai 2021 05:21