使用Object数据绑定创建WPF TreeView时遇到了一些问题。
该应用程序是配置文件编辑器。我已经定义了一个Object结构,可以将其序列化为正确的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
的所有子类都包含属性Id
和Name
。 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
,而没有其他内容。
答案 0 :(得分:2)
扩展@Gimalay的答案,问题是TreeView
不知道从哪里获取任何子节点的数据。您使用TreeView
而不是HierarchialDataTemplate
通知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
好吧,如果他们又有子节点)。
答案 1 :(得分:2)
我认为你不需要这个模板,因为对象永远不会出现在TreeView的图片中。
<HierarchicalDataTemplate
DataType="{x:Type ConfigurationEditor:Objects}"
ItemsSource="{Binding Path=Channels}"/>
你已经在XAML中设置了它,它显示了Channels .. perfect!
<TreeView
Margin="12,12,12,96" Name="treeView1"
ItemsSource="{Binding Source={StaticResource data}, Path=Channels}">
</TreeView>
现在您也想要显示Reader。 但是只能将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>
答案 2 :(得分:0)
只是为了它,当项目源本身具有层次结构时,使用分层数据模板。也就是说,对象本身具有一些层次结构,父对象保留子对象列表。
例如,可能每个频道都有如下所示的属性SubChannel。
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来创建子通道的层次结构。我们可以使用另一种类型,比如每个频道都有一个读者列表。
答案 3 :(得分: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>
感谢Andy让我走上正轨。