来自 DataTemplate 的 WPF 数据绑定 - 多对多关系
Posted
技术标签:
【中文标题】来自 DataTemplate 的 WPF 数据绑定 - 多对多关系【英文标题】:WPF databinding from DataTemplate - many-to-many relationship 【发布时间】:2014-07-24 11:44:03 【问题描述】:我有一个用于布局项目的 WPF 控件并将 ItemsSource
设置为
ItemsSource="Binding item_portfolio" DataContext="Binding SelectedItem"
在布局控件的资源中,我为其项目设置了模板:
<Style>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock Text="Binding portfolio.PortfolioName" />
<ListView ItemsSource="Binding ?">
</ListView>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
绑定的数据是多对多关系(一个项目可以有多个投资组合,一个投资组合可以有多个项目)并在数据库中的 3 个单独的表中指定(我使用实体框架来访问它)。下面的架构和示例数据:
item item_portfolio portfolio
ID (PK) Name itemID (FK) portfolioID (FK) ID PortfolioName
1 Item 1 1 1 1 Portfolio 1
2 Item 2 1 2 2 Portfolio 2
1 3 3 Portfolio 3
2 2
2 3
TextBlock
在DataTemplate
下的绑定工作正常。
但是我不知道如何绑定 ListView
ItemsSource
以便它显示属于该投资组合的所有项目对象。
编辑: 我想在布局控件中列出投资组合。然后在投资组合下,我想显示它包含哪些项目。下图显示了 SelectedItem 为 Item 1 时的 UI。
(首先我显示这个项目有哪些投资组合。这给出了 3 个投资组合。这工作正常。然后在 UI 上单击投资组合 3,它应该显示属于该投资组合的所有项目(项目 1 和项目 2)。那还不行。)
【问题讨论】:
【参考方案1】:我们在代码中建模数据模型的方式与在数据库中建模的方式不同。我们不制作“连接类”来模拟“连接表”。相反,我们创建分层数据模型。在您的情况下,您应该有一个Item
类,该类具有Portfolio
类型的Portfolio
属性。不应该有ItemPortfolio
类,因为它没有任何意义。那么,你的Binding
应该是这样的:
<ItemsControl ItemsSource="Binding Items" ... />
那么您的DataTemplate
(将自动将其DataContext
设置为Item
类集合中的一个项目)应该看起来更像这样:
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock Text="Binding PortfolioName" />
<ListView ItemsSource="Binding Portfolio">
</ListView>
</StackPanel>
</DataTemplate>
显然,要完成这项工作,您需要在 Item
类中定义这些属性。
更新>>>
在这种情况下,使用Items
类型的ObservableCollection<Item>
属性创建一个Portfolio
类,并像这样设置ItemsSource
:
<ItemsControl ItemsSource="Binding Item.Portfolios" ... />
澄清一下,您的Item
类还应该有一个ObservableCollection<Portfolio>
类型的集合属性...这将导致一些数据对象重复,但在 WPF 中提供更重要的是您的意见与他们需要的数据。
【讨论】:
在我的 item.item_portfolio 绑定中,item_portfolio 是一个实体框架导航属性。这个中间表应该作为一个类删除(正如你提到的),但由于某种原因,Entity Framework 在从数据库创建模型时没有这样做,尽管它在项目和投资组合之间存在多对多关系。 我不想绑定到项目列表。相反,我想绑定到投资组合列表。更新了我的问题以澄清。【参考方案2】:我在这里使用 扩展器控件,因为您希望 PortfolioName 作为标题并单击 PortfolioName 要显示相应的 PortfolioItemList。
xaml 代码
<ItemsControl MaxHeight="300" ItemsSource="Binding PortfolioInfo" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.Header>
<TextBlock Background="YellowGreen" Text="Binding name"></TextBlock>
</Expander.Header>
<Expander.Content>
<ListBox ItemsSource="Binding ItemList"></ListBox>
</Expander.Content>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
C# 代码
public partial class MainWindow : Window
public ObservableCollection<Portfolio> PortfolioInfo get; set;
public MainWindow()
InitializeComponent();
PortfolioInfo = new ObservableCollection<Portfolio>()
new Portfolio()name="Portfolio1", ItemList= new List<string>()"Item1","Item2","Item3",
new Portfolio()name="Portfolio2", ItemList= new List<string>()"Item1","Item2","Item3",
new Portfolio()name="Portfolio3", ItemList= new List<string>()"Item1","Item2","Item3"
;
this.DataContext = this;
public class Portfolio
public string name get; set;
public List<string> ItemList get; set;
注意:编辑Expander样式/模板以实现所需的UI
结果
【讨论】:
以上是关于来自 DataTemplate 的 WPF 数据绑定 - 多对多关系的主要内容,如果未能解决你的问题,请参考以下文章
WPF 菜单事件绑定 DataTemplate下button Command事件绑定 DataTemplate遍历实体数据
WPF -- DataTemplate与ControlTemplate结合使用