C# 在treeview中指定数据上下文和绑定分层数据的正确方法是什么?
我有一个相当简单的数据模型:C# 在treeview中指定数据上下文和绑定分层数据的正确方法是什么?,c#,wpf,data-binding,treeview,hierarchicaldatatemplate,C#,Wpf,Data Binding,Treeview,Hierarchicaldatatemplate,我有一个相当简单的数据模型: public class ServiceModel { private static readonly IQmiServiceManager ServiceManager = Bootstrap.Instance.DomainManager.QmiServiceManager; private string _serviceName; private ObservableCollection<string> _serviceMe
public class ServiceModel
{
private static readonly IQmiServiceManager ServiceManager = Bootstrap.Instance.DomainManager.QmiServiceManager;
private string _serviceName;
private ObservableCollection<string> _serviceMessages;
public string Name
{
get { return _serviceName; }
private set { _serviceName = value.ToUpper(); }
}
public ObservableCollection<string> Messages
{
get { return _serviceMessages; }
private set { _serviceMessages = value; }
}
public ServiceModel(string ServiceName, IList<string> ServiceMessages)
{
Name = ServiceName;
Messages = new ObservableCollection<string>(ServiceMessages);
}
}
公共类服务模型
{
专用静态只读IQmiServiceManager ServiceManager=Bootstrap.Instance.DomainManager.QmiServiceManager;
私有字符串_serviceName;
私有可观察收集服务消息;
公共字符串名
{
获取{return\u serviceName;}
私有集{u serviceName=value.ToUpper();}
}
公共可观察收集消息
{
获取{return\u serviceMessages;}
私有集{u serviceMessages=value;}
}
公共服务模型(字符串ServiceName,IList ServiceMessages)
{
名称=服务名称;
消息=新的ObservableCollection(ServiceMessages);
}
}
…封装在此视图模型中:
public class ServiceCollectionViewModel
{
private readonly ObservableCollection<ServiceModel> _serviceModels = new ObservableCollection<ServiceModel>();
public ObservableCollection<ServiceModel> ServiceModels
{
get { return _serviceModels; }
}
}
公共类ServiceCollectionViewModel
{
私有只读ObservableCollection _serviceModels=新ObservableCollection();
公共可观测收集服务模型
{
获取{return\u serviceModels;}
}
}
我有以下treeview xaml定义:
<TreeView Name="ServiceTree" Grid.Row="1" ItemsSource="{Binding Services}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding}">
<TextBlock Text="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Messages}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
树中没有输出任何内容。我尝试了以下几个关于分层数据绑定的教程,但我很难理解适合我具体情况的适当技术
另外,应该如何设置数据上下文?我在视图的代码隐藏中设置上下文如下:
public partial class ServiceView : UserControl
{
private readonly ServiceCollectionViewModel _serviceCollection = new ServiceCollectionViewModel();
public ObservableCollection<ServiceModel> Services
{
get { return _serviceCollection.ServiceModels; }
}
public ServiceView()
{
InitializeComponent();
DataContext = _serviceCollection;
_serviceCollection.LoadServices();
}
}
public部分类ServiceView:UserControl
{
私有只读ServiceCollectionViewModel _serviceCollection=new ServiceCollectionViewModel();
公共收集服务
{
获取{return\u servicecolection.ServiceModels;}
}
公共服务视图()
{
初始化组件();
DataContext=\u serviceCollection;
_serviceCollection.LoadServices();
}
}
你似乎很困惑。您正试图将数据绑定到ServiceView.Services
属性,那么ServiceCollectionViewModel
类的作用是什么?视图模型的唯一目的是提供其视图所需的所有数据(和功能)
现在我们可以走不同的路线。。。这完全取决于你真正想要什么。如果要从UserControl
外部将数据绑定到ServiceView.Services
属性,则必须将Services
属性声明为dependencProperty
。在UserControl
中,然后使用相对资源绑定将数据绑定到属性,如下所示:
<TreeView Name="ServiceTree" Grid.Row="1" ItemsSource="{Binding Services}">
...
</TreeView>
外部:
<YourPrefix:ServiceView Services="{Binding YourExternalViewModelProperty}" />
综上所述,如果您将DataContext
设置为对象的实例,那么您的绑定路径将查看该对象中的属性以解析它们自己。否则,如果在绑定路径
中设置了相对资源
(或元素名称
),则仅更改该绑定
的数据源,而绑定路径
应该是这些对象的属性
更新>>>
基本上是对常规的DataTemplate
类的一个轻微扩展,可以认为是一个带有ItemsSource
属性的DataTemplate
。因此,如果可以定义数据模板的内容
,则可以定义层次数据模板的内容
。。。只需确保将HierarchycalDataTemplate.ItemsSource
属性设置为有效的集合属性。。。在您的情况下,消息
属性:
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type YourPrefix:ServiceModel}"
ItemsSource="{Binding Messages}"> <!-- Collection Property In ServiceModel -->
<TextBlock Text="{Binding Name}" /> <!-- Property In ServiceModel -->
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
如果您对DataTemplate
不太清楚,请查看MSDN上的页面。这里有许多问题
ItemsSource
绑定应该是到ServiceModels
而不是Services
,因为这是ServiceCollectionViewModel
中的属性名称。这样你就可以得到顶级的物品
您试图在项目样式内部绑定到IsExpanded
和IsSelected
属性,但视图模型上没有此类属性
在您的HierarchycalDataTemplate
中,您可以将ItemsSource
属性直接绑定到TreeViewItem
的DataContext
,在本例中,该属性是ServiceModel
。使ServiceModel
实现IEnumerable
公开您的消息,或直接绑定到messages
属性:
第二级层次数据模板
将文本
属性绑定到消息
,但此级别的数据上下文
为字符串
类型,没有消息
属性。因此,这里您应该绑定到数据上下文本身:
关于数据上下文,最好使用静态资源在XAML中初始化它。此外,定义分层数据模板的更简洁的方法是基于项目类型使用隐式模板。因为您确实不想为更多的层次结构级别(例如:4、5)内联定义层次结构模板。请参见下面完全固定的XAML:
<Grid>
<Grid.Resources>
<!--Data context for the whole Grid-->
<myNamespace:ServiceCollectionViewModel x:Key="MyViewModel" />
</Grid.Resources>
<TreeView Name="ServiceTree"
DataContext="{StaticResource MyViewModel}"
ItemsSource="{Binding ServiceModels}">
<TreeView.Resources>
<!--Implicit style for TreeViewItem, IsExpanded and IsSelected have no binding because
they are not used by view-models-->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
<!--Template for the first level items-->
<HierarchicalDataTemplate DataType="{x:Type myNamespace:ServiceModel}" ItemsSource="{Binding Messages}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<!--Template for the second level, due to the fact that String is not hierarchical
regular DataTemplate is enough-->
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
<Grid>
<Grid.Resources>
<!--Data context for the whole Grid-->
<myNamespace:ServiceCollectionViewModel x:Key="MyViewModel" />
</Grid.Resources>
<TreeView Name="ServiceTree"
DataContext="{StaticResource MyViewModel}"
ItemsSource="{Binding ServiceModels}">
<TreeView.Resources>
<!--Implicit style for TreeViewItem, IsExpanded and IsSelected have no binding because
they are not used by view-models-->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
<!--Template for the first level items-->
<HierarchicalDataTemplate DataType="{x:Type myNamespace:ServiceModel}" ItemsSource="{Binding Messages}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<!--Template for the second level, due to the fact that String is not hierarchical
regular DataTemplate is enough-->
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>