Laden...

Canvas im Canvas aus OberservableCollection

Erstellt von Phil100Vol vor 2 Jahren Letzter Beitrag vor 2 Jahren 403 Views
P
Phil100Vol Themenstarter:in
4 Beiträge seit 2021
vor 2 Jahren
Canvas im Canvas aus OberservableCollection

Hallo myCSharp Community,

ich befinde mich noch auf den ersten Schritten zur Erlernung von c# und WPF, wo mir sicherlich noch einige Grundlagen fehlen. Dennoch habe ich bereits ein konkretes Problem, an dem ich bereits seit Tagen hadere.

Ich möchte in einer UI meine ObservableCollection "ObservableAxis" mit verschiedenen Canvases darstellen. Da die Werte der Bestandteile und UI mal dynamisch sein sollen, verwende ich die ObservableCollection.

Grundlage ist die o.g. ObservableAxis, die sich wie folgt aufbaut:


public partial class MainWindow : Window
    {

        public static ObservableCollection<Axis> ObservableAxis = new ObservableCollection<Axis>();

        public MainWindow()
        {
            InitializeComponent();

            Axis Axis0 = new Axis(0);
            Axis0.MySegments.Add(new Segment(0, 10, 100, Axis0.Axis_Number));
            Axis0.MySegments.Add(new Segment(1, 20, 200, Axis0.Axis_Number));

            Axis Axis1 = new Axis(1);
            Axis1.MySegments.Add(new Segment(0, 50, 500, Axis1.Axis_Number));
            Axis1.MySegments.Add(new Segment(1, 60, 600, Axis1.Axis_Number));

            ObservableAxis.Add(Axis0);
            ObservableAxis.Add(Axis1);

            ItemsControl_Axis.ItemsSource = ObservableAxis;
        }
    }

Jede Axis besteht widerum aus mehreren Segmenten, mit verschiedenen Eigenschaften


 public class Axis
    
    {
        public ObservableCollection<Segment> MySegments;
        public int Axis_Number { get; set; }

        public Axis(int axis_number)
        {
            Axis_Number = axis_number;
            MySegments = new ObservableCollection<Segment>();
        }
    }


public class Segment
    {

        public int Counter_Seg { get; set; }
        public double Start { get; set; }
        public double Duration { get; set; }
        public int Axis_Counter { get; set; }

        public string ID { get; set; }

        public Segment(int counter_seg, double start, double duration, int axis_counter)
        {
            Counter_Seg = counter_seg;
            Start = start;
            Duration = duration;
            Axis_Counter = axis_counter;
        }
    }

Jede Axis soll durch einen grünen Canvas über die gesamte Breite dargestellt werden (StackPanel vertical) und innerhalb einer jeden Axis sollen die zugeordneten Segmente als gelbe Canvases **horizontal **erfolgen.

Bisher habe ich folgendes Bild erreicht --> siehe Bild im Anhang oben
Im unteren Teil des Bildes ist das Ziel angedeutet, welches ich verfolge.

Im XAML habe ich bereits folgendes umgesetzt:


<Window x:Class="WpfApp2.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:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>
        
        <HierarchicalDataTemplate x:Key="myLevel1Template" DataType="{x:Type local:Axis}" ItemsSource="{Binding Path=MySegments}">
            <Border BorderBrush="Black" BorderThickness="1">
                <Canvas Width="750" Height="50" Background="DarkSeaGreen"/>
            </Border>
        </HierarchicalDataTemplate>

        <Style x:Key="Canvas" TargetType="Canvas">
            <Setter Property="Canvas.Left" Value="{Binding Start}"/>
            <Setter Property="Canvas.Top" Value="5"/>
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="Height" Value="40"/>
            <Setter Property="Width" Value="{Binding Duration}"/>
        </Style>


    </Window.Resources>
    
    <Grid>
        <Canvas Background="NavajoWhite">

            <ItemsControl x:Name="ItemsControl_Axis" 
                          ItemTemplate="{StaticResource myLevel1Template}">
                <ItemsControl.Resources>

                    <DataTemplate DataType="{x:Type local:Segment}">
                        <Canvas Style="{StaticResource Canvas}">
                            <Label Content="{Binding Path=Axis_Counter}" Canvas.Left="10" Canvas.Top="10"/>
                        </Canvas>
                    </DataTemplate>
                    
                    
                </ItemsControl.Resources>

            </ItemsControl>
                                                         
        </Canvas>
    </Grid>
    
</Window>

Schon mal Danke für eure Hilfe und Gruß

Phil

5.658 Beiträge seit 2006
vor 2 Jahren

Wo genau liegt das Problem? Was funktioniert nicht? Was hast du schon probiert?

Schau mal in [Hinweis] Wie poste ich richtig?, du mußt uns schon ein paar mehr Infos geben, um dir helfen zu können.

Schau auch mal in [Artikel] MVVM und DataBinding, besonders in den Abschnitt Debugging, um deine DataBindings debuggen zu können.

Weeks of programming can save you hours of planning

P
Phil100Vol Themenstarter:in
4 Beiträge seit 2021
vor 2 Jahren

Sry für die nicht ausführliche Beschreibung des Problems.

Ich bekomme es nicht hin, dass mir wie auf dem Screenshot (unterer Abschnitt) die zweite Ebene meiner OberserveableCollection dargestellt wird. Ich schaffe es nur die erste Ebene zu visualisieren.

  1. Ebene = Class Axis = Grüner Canvas und die
  2. Ebene = Class Segement = Gelber Canvas

Auch wenn ich nur die blanken Zahlenwerte darstellen möchte, sagen wir "axis_number" auf der ersten Ebene und "Segment.Start" aus der zweiten Ebene wird mir partout nur die erste Ebene angezeigt.

Durch Ändern der Art der Darstellung (<-- hier fehlt mir der richtige Begriff) von


<ItemsControl ItemsSource= ...>
...
</ItemsControl>

in einen TreeView


<TreeView ItemsSource= ...>
...
</TreeView>

ist es möglich, dass mir auch die zweite Ebene angezeigt wird. --> siehe Anhang. Ziel ist es jedoch, dass die gelben Canvas innerhalb der grünen sein sollen.

Ist es überhaupt möglich mit einem ItemsControl oder ListBox die verschiedenen Ebenen einer ObservableCollection darzustellen oder muss man sobald es mehr als eine Schicht hat auf einen TreeView zurückgreifen? Wenn es möglich ist wie?

Danke

4.939 Beiträge seit 2008
vor 2 Jahren

Ich denke, du brauchst einfach 2 ineinander verschachtelte ItemsControl. Also baue statt dem HierarchicalDataTemplate daraus ein ItemsControl (mit entsprechender Anpassung des DataTemplate).

Edit: Für das innere ItemsControl benötigst du dann noch die horizontale Ausrichtung, s. z.B. ItemsControl with horizontal orientation.

Außerdem könnte noch How to position controls using Canvas control in WPF using MVVM für dich interessant sein (da du ja freie Positionierung der Canvas willst).

P
Phil100Vol Themenstarter:in
4 Beiträge seit 2021
vor 2 Jahren

Danke für die Hinweise, werde ich ausprobieren, sobald ich wieder da bin und die Antwort posten

P
Phil100Vol Themenstarter:in
4 Beiträge seit 2021
vor 2 Jahren

Hi,

nach längerer Stille habe ich mittlerweile folgenden Fortschritt, der mir das beigefügte Bild darstellt (oben links).

Noch nicht ganz das Ergebnis was ich erreichen möchte (Bild unten rechts) und daher meine Nachfrage wo mein Denkfehler ist. Das kleine gelbe Rechteck sollte eigentlich in der selben Reihe/Höhe sein wie das direkt oben drüber.

Ich habe es nach dem Vorschlag der verschachtelten ItemsControl mit horizontaler Ausrichtung probiert, aber klappt noch nicht ganz.


<TreeView x:Name="trv">
        <TreeView.Resources>

            <HierarchicalDataTemplate ItemsSource="{Binding MySegments}" DataType="{x:Type local:Axis}">
                <TextBlock Text="{Binding Path=Axis_Number}"/>
            </HierarchicalDataTemplate>

            <DataTemplate DataType="{x:Type local:Segment}">

                <ItemsControl >
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas Width="800" Height="50" Background="DarkSeaGreen"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>

                    <ItemsControl ItemsSource="{Binding}" Canvas.Left="{Binding Path=Start}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>

                        <Canvas Width="{Binding Path=Duration}" Background="Yellow" Height="50"/>

                    </ItemsControl>
                </ItemsControl>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
</Window>

Und die zugrundeliegende ObservableCollection:


ObservableAxis = new ObservableCollection<Axis>();

Axis Axis0 = new Axis(0);
Axis0.MySegments.Add(new Segment(10, 100));
Axis0.MySegments.Add(new Segment(200, 30));

Axis Axis1 = new Axis(1);
Axis1.MySegments.Add(new Segment(50, 500));

ObservableAxis.Add(Axis0);
ObservableAxis.Add(Axis1);

trv.ItemsSource = ObservableAxis;

Danke für eure Hilfe und Gruß

Phil