2009-09-13 85 views
2

我有一些嚴重的麻煩創建一個對象數據綁定的WPF TreeView。TreeView不顯示對象層次

該應用程序是配置文件編輯器。我已經定義了一個可以序列化爲正確的XML格式的對象結構。

我遇到的問題是格式化TreeView中的對象實例,顯示正確的層次結構。 TreeView將只呈現Channel節點,而不是其他任何東西。

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; } 
} 

所有Channel子類包含屬性IdName。 Filters類是具有相同屬性定義的其他類型的集合。

這裏是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> 

後面的代碼來創建數據實例

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; 

我已經看了無數的例子,但我還是能找出我做錯了。謝謝您的幫助。

更新:

<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> 

沒有變化的TreeView。有了這個改變,我仍然只有Channel列出,沒有別的。

+1

Nitpicking有一點點,但請在您的文章中將文字「WCF」替換爲「WPF」。 WCF和WPF是獨立的技術。 – 2009-09-13 01:22:17

+0

@大衛:我解決這個問題以避免混淆。 – Andy 2009-09-13 01:58:33

回答

2

在@ Gimalay的回答中展開,問題是TreeView不知道從何處獲取任何子節點的數據。您可以通過使用HierarchialDataTemplate通知TreeView,而不是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> 

兩者之間的主要區別是ItemsSource屬性。這是一個綁定表達式,它返回要用作子節點的對象集合。

問題是你有幾個屬性讓孩子,而不僅僅是一個。您可能需要將它們全部組合到一個屬性中,或者添加另一個返回所有子節點的屬性。

最後,你需要定義一個DataTemplate爲每個孩子的項目類型,從而使TreeView知道如何顯示它們(你可以使用一個兒童HierarchialDataTemplate爲好,如果他們又將有子節點)。

+0

'Objects'類擁有一個包含'Channel'對象集合的屬性。所以我創建了一個使用該類型和屬性的'HierarchialDataTemplate'。然後,我可以通過添加另一個模板來顯示'Channel'節點,但是葉節點仍然不顯示 – Karl 2009-09-13 02:30:26

+0

您可以發佈更新後的代碼嗎?這可能有助於調試問題。 – Andy 2009-09-13 03:54:08

2

我不認爲你需要這個模板,因爲對象永遠不會在你的TreeView中出現。

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

您已經在XAML中設置了它,它顯示了Channels ..完美!

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

現在您還想要顯示讀取器。 但是,只能指定IEnumerable類型的對象作爲ItemsSource,所以下面的模板不正確,它將「Reader」指定爲ItemsSource。

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

因此,如果您希望顯示讀者姓名,請使用如下所示的模板。

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

感謝您的評論,這是有幫助的,但不是我想要實現的效果。最終,我希望將'Channel'對象複製爲一棵樹。意思是'Channel'的所有屬性都顯示爲TreeView中的子節點。 在你給出的例子中,'Reader'的名字與'Channel'出現在同一層。從您在下面提出的評論看來,似乎我想做的事可能是不可能的。 – Karl 2009-09-13 14:41:54

0

只是爲了它,層次數據模板用於項目源實際上在其本身具有層次結構時。也就是說,對象本身有一些層次結構,父對象保留着一個子對象列表。

作爲一個例子,可能是每個Channel都有一個屬性SubChannels,如下所示。

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

然後,我們可以使用這樣的模板。

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

現在,對象結構可以是多層深的,每個子通道又具有子通道。

另外,請注意,在示例中,我只是使用相同類型的Channel來創建子通道的層次結構。我們可以使用另一種類型,比如說每個頻道都有一個讀者列表。

0

好吧,經過多次試驗,我發現一個錯誤能夠讓我按照自己的意願工作。這是我做到的。

在我Channel對象我添加了一個新的屬性,這是所有其他屬性的集合,我想在TreeView

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; 
       } 
      } 
     } 
    } 
} 

然後我的XAML是如下顯示樹形視圖來顯示。

<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> 

謝謝安迪讓我走上正軌。