Frage

Ich habe einige ernsthafte Probleme, einen WPF TreeView mit einem Objekt-Datenbindung zu schaffen.

Die Anwendung ist Config-Datei-Editor. Ich habe eine Objektstruktur definiert, die auf das richtige XML-Format serialisiert werden können.

Das Problem, das ich habe, ist die Formatierung der Objektinstanz in der Strukturansicht die richtige Hierarchie zeigt. Das TreeView wird nur der Kanal Knoten machen, und nichts anderes.

public class Objects
{
    public List<Channel> Channels { get; set; }
}

public class Channel 
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Reader Reader { get; set; }
    public Filters Filters { get; set; }
    public Router Router { get; set; }
    public Persister Persister { get; set; }
}

public class Filters : ArrayList
{
    public string StopOnFailure { get; set; }
}

public class Reader
{
    public string Id { get; set; }
    public string Name { get; set; }
}

Alle untergeordneten Klassen von Channel enthalten Eigenschaften Id und Name. Die Filter-Klasse ist eine Sammlung von anderen Typen mit der gleichen Eigenschaft Definition.

Hier ist die XAML

 <Window.Resources>
    <ObjectDataProvider x:Key="data"/>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Channel}">
        <WrapPanel>
            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
            <TextBlock Text=" [" />
            <TextBlock  Text="{Binding Path=Id}" />
            <TextBlock Text="]" />
        </WrapPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
</Window.Resources>
<Grid>
    <TreeView Margin="12,12,12,96" Name="treeView1" ItemsSource="{Binding Source={StaticResource data}, Path=Channels}">
    </TreeView>
</Grid>

Der Code hinter, um die Dateninstanz zu erstellen

Objects config;
var serializer = new XmlSerializer(typeof(Objects));
using (var stream = new FileStream(@"C:\test.xml", FileMode.Open))
{
    config = (Objects)serializer.Deserialize(stream);
}

var dp = (ObjectDataProvider)FindResource("data");
dp.ObjectInstance = config;

Ich habe an unzähligen Beispielen gesucht, aber ich kann immer noch herauszufinden, was ich falsch mache. Danke für die Hilfe.

Update:

<HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Objects}" ItemsSource="{Binding Path=Channels}"/>
<HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Channel}" ItemsSource="Binding Path=Reader}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

<DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
    <TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>

Keine Änderung des TreeView. Mit dieser Änderung habe ich nur noch die Channel aufgeführt ist, und sonst nichts.

War es hilfreich?

Lösung

Als Erweiterung @ Gimalay Antwort, das Problem ist, dass der TreeView nicht weiß, wo die Daten für alle untergeordneten Knoten zu erhalten. Sie informieren die TreeView durch einen HierarchialDataTemplate, anstatt eine DataTemplate:

<HierarchialDataTemplate DataType="{x:Type ConfigurationEditor:Channel}"
    ItemsSource="...">
    <WrapPanel>
        <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
        <TextBlock Text=" [" />
        <TextBlock  Text="{Binding Path=Id}" />
        <TextBlock Text="]" />
    </WrapPanel>
</HierarchialDataTemplate>

Der wesentliche Unterschied zwischen den beiden ist die ItemsSource Attribut. Dies ist ein verbindlicher Ausdruck, der eine Sammlung von Objekten zurückgibt als untergeordneten Knoten zu verwenden.

Das Problem ist, dass Sie ein paar Eigenschaften haben, um Kinder aus, nicht nur einen. Sie müssen entweder sie alle in eine Eigenschaft zu kombinieren, oder eine andere Eigenschaft hinzufügen, die alle untergeordneten Knoten zurück.

Schließlich benötigen Sie einen DataTemplate für jedes Kind Elementtyp zu definieren, so dass die TreeView weiß, wie sie angezeigt werden (Sie auch eine HierarchialDataTemplate für die Kinder verwenden können, wenn sie wiederum Kindknoten haben).

Andere Tipps

Ich glaube nicht, dass Sie diese Vorlage benötigen, wie Objekte nie in Ihrem TreeView im Bild kommen.

<HierarchicalDataTemplate
    DataType="{x:Type ConfigurationEditor:Objects}" 
    ItemsSource="{Binding Path=Channels}"/>

Sie haben in XAML festlegen diese, die die Kanäle zeigt .. perfekt!

<TreeView 
    Margin="12,12,12,96" Name="treeView1" 
    ItemsSource="{Binding Source={StaticResource data}, Path=Channels}">
</TreeView>

Jetzt wollen Sie die Leser als auch gezeigt werden. Aber man kann nur Objekte vom Typ IEnumerable als Itemssource angeben, so ist die Vorlage unter falsch, die „Reader“ als Itemssource gibt.

<HierarchicalDataTemplate 
    DataType="{x:Type ConfigurationEditor:Channel}" 
    ItemsSource="{Binding Path=Reader}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

Wenn Sie also Leser wollen Namen wie gezeigt unten als auch, um die Vorlage werden.

<DataTemplate 
    DataType="{x:Type ConfigurationEditor:Channel}" >
    <StackPanel>
        <TextBlock Text="{Binding Path=Name}"/>
        <TextBlock Text="{Binding Path=Reader.Name}"/>
    <StackPanel>
</DataTemplate>

Nur aus Gründen davon sind hierarchische Datenvorlagen verwendet werden, wenn die Elemente Quelle tatsächlich eine Hierarchie in sich hat. Das heißt, die Objekte selbst eine gewisse Hierarchie haben, mit übergeordneten Objekte eine Liste der untergeordneten Objekte zu halten.

Als Beispiel kann die jeder Kanal eine Eigenschaft SubChannels wie unten hat.

public class Channel 
{
    public string Id { get; set; }
    public string Name { get; set; }
    public ObservableCollection<Channel> SubChannels { get; }
}

Dann haben wir eine Vorlage wie folgt verwendet haben könnte.

<HierarchicalDataTemplate 
    DataType="{x:Type ConfigurationEditor:Channel}" 
    ItemsSource="{Binding Path=SubChannels}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

Nun kann die Objektstruktur mit mehreren Ebenen sein tief mit jedem Unterkanal wieder Subkanäle hat.

Auch, beachten Sie, dass in dem Beispiel habe ich nur die gleiche Art, Kanal, eine Hierarchie von Unterkanälen zu erstellen. Wir hätten eine andere Art verwendet, sagen jeder Kanal eine Liste der Leser mit.

Okay, Nach viel Versuch ein Fehler konnte ich diese Arbeit bekommen, wie ich wollte. Hier ist, wie ich es tat.

In meinem Channel Objekt habe ich eine neue Eigenschaft, die eine Sammlung von allen anderen Eigenschaften war, die ich in der Strukturansicht

angezeigt werden wollte
public ArrayList Components
{
    get { return new ArrayList { Reader, Filters, Router, Persister  }; } 
    set
    {
        ArrayList list = value;
        if (list != null)
        {
            foreach (var item in list)
            {
                if (item is Reader)
                {
                    Reader = (Reader)item;
                }
                else if (item is Router)
                {
                    Router = (Router) item;
                }
                else if (item is Persister)
                {
                    Persister = (Persister) item;
                }
                else if (item is Filters)
                {
                    Filters = (Filters) item;
                }
            }
        }
    }
}

Dann ist mein XAML ist wie folgt dem Treeview angezeigt werden soll.

    <HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Channel}" ItemsSource="{Binding Path=Components}">
        <WrapPanel>
            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
            <TextBlock Text=" [" />
            <TextBlock  Text="{Binding Path=Id}" />
            <TextBlock Text="]" />
        </WrapPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Filters}" ItemsSource="{Binding Path=.}">
        <TextBlock Text="Filters"/>
        <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate >
                <TextBlock Text="{Binding Path=Name}"/>
            </DataTemplate>
        </HierarchicalDataTemplate.ItemTemplate>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Router}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Persister}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>

Danke Andy für mich auf dem richtigen Weg setzen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top