Hallo zusammen,
ich habe wieder ein Problem. Nach unzähligen Selbstversuchen hab ich jetzt aufgegeben und hoffe jemand von euch kann mir helfen, oder wenigstens den entscheidenden Denkanstoß geben. Mein Problem ist etwas komplexer, ich habe deswegen noch eine Skizze angefertigt und sie mit angehängt, trotzdem versuche ich es erst einmal mit Worten zu beschreiben:
Meine Hauptklasse enthält viele Daten, die alle grafisch dargestellt werden sollen. Dazu gehören ein paar Eigenschaften wie Name etc, und vor allem viele Kindelemente. Die Kindelemente können in zwei verschiedenen Gruppen auftauchen. Diese Gruppen habe ich mit List<> Instanzen umgesetzt, damit ich sie dynamisch jederzeit erweitern kann. In diesen beiden Gruppen (List<> liste1, List<> liste2) haben ich viele Instanzen der Klasse Objekt (nicht zu verwechseln mit Object, habe sie nur der Einfachheit halber mal abstrakt Objekt genannt). Für diese Objekte habe ich bereits ein Template erstellt. Wenn ich also z.B. ein einziges solches Objekt einem Canvas hinzufüge, wird es schon richtig angezeigt. Mein Problem ist jetzt ein Template für das ganze Objekt Klasse zu erstellen, das dann selbstständig irgendwie zwei "Panels" für die beiden Listen erstellt, die jeweils auch ein Design bekommen sollen, und letztenendes dann ihre Instanzen von Objekten da drin darstellen.
Mein Ansatz ging von einem Einfachen ContentControl aus. Nur scheint dieses nicht geeignet zu sein für mehrere Daten. Dann habe ich ein DataTemplate versucht, das ich aber leider nur in Kombination mit einem ItemsControl verwenden kann, also hat das auch nicht recht funktioniert. Ich weiß nicht wie ich weiter machen soll ...
Ich bitte um Hilfe. Danke.
Mfg Felsen
Hallo Felsen,
Mein Ansatz ging von einem Einfachen ContentControl aus. Nur scheint dieses nicht geeignet zu sein für mehrere Daten. Dann habe ich ein DataTemplate versucht, das ich aber leider nur in Kombination mit einem ItemsControl verwenden kann, also hat das auch nicht recht funktioniert.
Wenn ich das Problem richtig verstanden habe, hast du dir die Antwort schon selbst gegeben: Verwende zwei ItemsControls in deinem DataTemplate.
Schemenhaft also so:
<DataTemplate TargetType="{x:Type ...}">
<!-- Code der allgemeines anzeigt -->
<ItemsControl ItemSource="{Binding Path=Liste1}">
<!-- DataTemplates, ItemsPanelTemplate etc. -->
</ItemsControl>
</DataTemplate>
Hi WinSharp93,
danke für die Antwort. Du hast richtig gelegen. Ich hab mich so drauf fixiert irgendeine fertige Klasse zu nehmen die von ItemsControl ableitet, dass ich ganz vergessen hab, dass ich doch die Klasse selbst nehmen könnte ...
Hab dann zwischenzeitlich etwas rumexperimentiert und konnte auch kleine Erfolge verzeichnen, jedoch bin ich jetzt wieder in ner Sackgasse, und ich verstehe einfach nicht was an meinem Code nicht stimm. Vielleicht kannst du ja mal einen kurzen Blick drauf werfen:
<Window x:Class="Template_Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Test="clr-namespace:Template_Test"
Title="Window1" Height="300" Width="300">
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type Test:Objekt}">
<Border Background="Beige" CornerRadius="8" Height="30" Margin="10">
<Label Content="{Binding ObjektName}"></Label>
</Border>
</DataTemplate>
</StackPanel.Resources>
<ItemsControl Background="Black">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type Test:Klasse}">
<Border Background="green" Height="100">
<StackPanel>
<Label Content="{Binding KlasseName}"></Label>
<ItemsControl ItemsSource="{Binding liste1}">
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<Test:Klasse></Test:Klasse>
</ItemsControl>
</StackPanel>
</Window>
Wie gesagt, das Objekt wird bereits richtig formatiert dargestellt, wenn ich es ganz allein darstelle. Aber irgendwie findet er die Objekt Instanzen in liste1 nicht richtig und stellt deswegen auch nichts dar. Das Binding an KlasseName funktioniert übrigens hervorragend, der Name wird im Design richtig angezeigt, nur unter dem Name sollten eben dann die einzelnen Objekte angezeigt werden, von denen aber keines zu sehen ist. (Die Klassen Instanz ist übrigens auch richtig initialisiert, alle Variablen enthalten ihre Daten, das habe ich bereits überprüft)
Mfg Felsen
Prüfe mal das Output-Fenster, vielleicht steht da was drin.
Ist liste1 auch tatsächlich public
?
Keine Meldungen im Outputfenster. Hier mal der Code meiner CodeBehind Datei:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Template_Test
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
public class Klasse
{
public string KlasseName { get; set; }
public List<Objekt> liste1 = new List<Objekt>();
public List<Objekt> liste2 = new List<Objekt>();
public List<Objekt> liste3 = new List<Objekt>();
public Klasse()
{
KlasseName = "Test...";
for (int i = 0; i < 5; i++)
{
liste1.Add(new Objekt());
liste2.Add(new Objekt());
liste3.Add(new Objekt());
}
}
}
public class Objekt
{
public static int count = 0;
public string ObjektName { get; set; }
public Objekt()
{
ObjektName = String.Format("String{0}",count++);
}
}
}
Mfg Felsen
EDIT: @ Briefkasten, kleier Fehler beim abtippen, nun ausgebessert, daran lag es aber nicht.
Hallo,
mach aus der Membervariable liste1 eine Propertie. Dann sollte es gehen.
Ich nehm mal an dass Net() der Konstruktor der Klasse Klasse ist und den falschen Namen hat. So sollte es nicht compelierfähig sein.
Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp
Hi Briefkasten,
ja der Konstruktor war falsch abgetippt, hatte vorher noch andere Bezeichner. Da jetzt eigene Dependency Properties ins Spiel kommen übersteigt das etwas meinen bisherigen Erfahrungshorizont. Ich habs trotzdem mal nach bestem Wissen angepasst, jedoch wird beim Kompilieren eine XAMLParseException geworfen.
Hier mal soweit der angepasste Code:
public class Klasse: DependencyObject
{
...
public List<Objekt> Liste1
{
get { return (List<Objekt>)GetValue(Liste1Property); }
set { SetValue(Liste1Property, value); }
}
public static readonly DependencyProperty Liste1Property =
DependencyProperty.Register("Liste1", typeof(List<Objekt>), typeof(Klasse));
...
public Klasse()
{
...
for (int i = 0; i < 5; i++)
{
...
Liste1.Add(new Objekt());
}
}
Mfg Felsen
Hi,
eine DependecyPropertie benötigst du in diesem Fall nicht. Eine normale tut es auch.
public ObservableCollection<Objekt> liste1 { get; set; }
Und nicht vergessen die Propertie im Konstruktor zu initialisieren.
Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp
OK, der Code sieht nun so aus:
public class Klasse: DependencyObject
{
...
public ObservableCollection<Objekt> liste1;
public Klasse()
{
liste1 = new ObservableCollection<Objekt>();
for (int i = 0; i < 5; i++)
{
liste1.Add(new Objekt());
}
}
}
Bedauerlicherweise hat sich nichts geändert. Aber es gibt trotzdem noch was zu berichten. Bei diesem Beispiel zeigt der Designer nicht das aktuelle Fenster an, sondern eine Fehlermeldung, dass das Dokument einen Fehler enthält. Trotz alle dem lässt es sich kompilieren und ausführen. Als Fehler wird folgender Code unterringelt:
<DataTemplate DataType="{x:Type Test:Objekt}">
<Border Background="Beige" CornerRadius="8" Height="30" Margin="10">
<Label Content="{Binding ObjektName}"></Label>
</Border>
</DataTemplate>
Die Fehlermeldung lautet:
Der öffentliche Typ mit dem Namen "Objekt" kann von dem Typverweis nicht gefunden werden.
Welche Rolle dieser Fehler genau spielt weiß ich nit, da erstens sich das Projekt ja kompilieren lässt, und zweitens, das in den Resourcen abgelegte Template auch wunderbar auf einzelne Objekt Instanzen im XAML Code anwendbar wäre.
Weiß jemand trotzdem noch nen Rat?
Mfg Felsen
Hallo,
laut dem gepostetem Code hast du auch nach wie vor eine Membervariable und keine öffentliche Propertie.
Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp
Das glaub ich jetzt nicht...
Wenn ich der Property tatsächlich { get; set; } anfüge funktionierts ... Aber ich verstehe nicht wieso. Diese beiden Methoden sind doch nur eine Art Wrapper um die eigentliche Property. Die Zuweisung funktioniert doch in beiden fällen Identisch, es wird letztenendes nur auf eine Membervariable zugegriffen. Dass es für XAML da einen Unterschied gibt hätte ich nie gedacht...
Man o man, aber aus sowas lernt man, das werd ich bestimmt nicht nochmal falsch machen. Danke für eure Geduld und Hilfe. Wirklich vielen Dank.
Schöne Grüße
Felsen
Hallo,
Das glaub ich jetzt nicht...
Wenn ich der **Property **tatsächlich { get; set; } anfüge funktionierts ... Aber ich verstehe nicht wieso.
Erst in dem Moment als du das {get;set;} hinzugefügt hast, handelt es sich um eine Propertie / Eigenschaft.
Davor war es eine Membervariable.
Die Zuweisung funktioniert doch in beiden fällen Identisch, es wird letztenendes nur auf eine **Membervariable **zugegriffen. Dass es für XAML da einen Unterschied gibt hätte ich nie gedacht...
Beim Binding wird immer auf die Propertie zugegriffen. Die Propertie speichert oder gibt den Wert der Membervariable zurück (solang es sich um eine stink normale Propertie handelt).
Wenn du auf eine Membervariable zugreifen willst must du das so machen:
public static string name="asdf";
<TextBlock Text="{Binding Source={x:Static local:Window1.name}}"></TextBlock>
In deinem Fall ist aber die Propertie genau richtig.
Auf Statische Membervariablen zugreifen macht z.B. bei Converter sinn.
Informationen zum Binding findest du hier:
Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp
Hi,
danke dir nochmal für die Mühe deines letzten Beitrags. Werde das bei meinen künftigen Aufgaben im Hinterkopf behalten.
Mfg Felsen