TreeView에는 객체 계층이 표시되지 않습니다
-
06-07-2019 - |
문제
객체 데이터 핀딩으로 WPF TreeView를 만드는 데 심각한 어려움이 있습니다.
응용 프로그램은 구성 파일 편집기입니다. 올바른 XML 형식으로 직렬화 될 수있는 객체 구조를 정의했습니다.
내가 가지고있는 문제는 올바른 계층 구조를 보여주는 treeview에서 개체 인스턴스를 서식하는 것입니다. TreeView는 채널 노드 만 렌더링합니다.
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
. 필터 클래스는 동일한 속성 정의를 가진 다른 유형의 모음입니다.
여기 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
나열되어 있고 다른 것은 없습니다.
해결책
@limalay의 답변을 확장하면 문제는 TreeView
자식 노드의 데이터를 어디서 얻을 수 있는지 모릅니다. 당신은 알립니다 TreeView
a HierarchialDataTemplate
, a보다는 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
기인하다. 이것은 하위 노드로 사용할 객체 모음을 반환하는 바인딩 표현입니다.
문제는 어린이를 하나뿐만 아니라 자녀를 얻을 수있는 속성이 몇 개 있다는 것입니다. 당신은 그것들을 하나의 속성에 결합하거나 모든 자식 노드를 반환하는 다른 속성을 추가해야합니다.
마지막으로 a를 정의해야합니다 DataTemplate
각 어린이 항목 유형에 대해 TreeView
표시하는 방법을 알고 있습니다 (사용할 수 있습니다. HierarchialDataTemplate
어린이들에게도 자녀 노드가 있다면).
다른 팁
객체가 TreeView의 그림에 들어오지 않기 때문에이 템플릿이 필요하다고 생각하지 않습니다.
<HierarchicalDataTemplate
DataType="{x:Type ConfigurationEditor:Objects}"
ItemsSource="{Binding Path=Channels}"/>
당신은 이것을 XAML로 설정했습니다.
<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>
이를 위해 항목 소스에 실제로 계층 구조가있을 때 계층 적 데이터 템플릿이 사용됩니다. 즉, 객체 자체는 계층 구조를 가지고 있으며, 부모 객체는 자식 객체 목록을 유지합니다.
예를 들어, 각 채널에는 아래와 같은 속성 하위 채널이있을 수 있습니다.
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
객체 나는 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은 다음과 같습니다. TreeView를 표시합니다.
<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>
앤디에게 올바른 길을 가셔서 감사합니다.