【问题标题】:WPF databinding from DataTemplate - many-to-many relationship来自 DataTemplate 的 WPF 数据绑定 - 多对多关系
【发布时间】: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)。那还不行。)

【问题讨论】:

    标签: wpf many-to-many datatemplate


    【解决方案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

    结果

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多