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

TextBlockDataTemplate 下的绑定工作正常。 但是我不知道如何绑定 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&lt;Item&gt; 属性创建一个Portfolio 类,并像这样设置ItemsSource

<ItemsControl ItemsSource="Binding Item.Portfolios" ... />

澄清一下,您的Item 类还应该有一个ObservableCollection&lt;Portfolio&gt; 类型的集合属性...这导致一些数据对象重复,但在 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--模板化

WPF--模板化

WPF 菜单事件绑定 DataTemplate下button Command事件绑定 DataTemplate遍历实体数据

WPF -- DataTemplate与ControlTemplate结合使用

WPF 后台获得 数据模板里的内容控件(DataTemplate)

WPF Template模版之DataTemplate与ControlTemplate的关系和应用