【问题标题】:How can I use data binding in WPF to create a new user control for each element in a list?如何在 WPF 中使用数据绑定为列表中的每个元素创建新的用户控件?
【发布时间】:2024-05-02 15:10:04
【问题描述】:

我有一个对象列表。对于列表中的每个项目,我想创建一个绑定到该项目的新用户控件。根据我的阅读,以编程方式执行此操作对 WPF 来说是不好的做法(也不太简单),因此我应该使用数据绑定作为解决方案。问题是,我不知道该怎么做。我在编译时不知道列表的内容(只是类型),因此我无法为每个元素创建和绑定 XAML。谷歌和 MSDN 似乎没有任何答案,所以也许我想错了?我需要做什么?

谢谢

编辑:澄清一下,我正在尝试制作自己的音乐评分软件,比如 Rosegarden。该列表将包含所有度量,用户控件将是它们的可视化表示。

【问题讨论】:

    标签: c# wpf user-controls binding


    【解决方案1】:

    比 Julien Lebosquain 的建议更通用的方法(当项目列表包含多种数据类型的对象时,这种方法将起作用):

    创建一个DataTemplate 用于显示列表中的类型项目,例如:

    <DataTemplate DataType="local:Measure">
       <local:MeasureUserControl DataContext="{Binding}"/>
    </DataTemplate>
    

    使用ItemsControl 来展示项目:

    <ItemsControl ItemsSource="{Binding MeasureList}"/>
    

    您可以将ItemsControlItemsPanel 属性设置为ItemsPanelTemplate,以控制其布局用户控件的方式,例如:

    <ItemsControl.ItemsPanel>
       <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal"/>
       </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    

    当您不想要ListBox 的功能时,这种方法通常比使用ListBox 更可取,例如它的默认边框和选择行为。

    【讨论】:

      【解决方案2】:

      您可以使用带有自定义项目样式的标准ListBox

      资源中的某处:

      <Style TargetType="{x:Type ListBoxItem}" x:Key="CustomItemStyle">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
              <yourns:YourControl />
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
      

      在您的窗口/页面/用户控件中:

      <ListBox ItemsSource="{Binding ...}" ItemContainerStyle="{StaticResource CustomItemStyle}" />
      

      由于您的对象将绑定到列表框,因此将为每个对象创建一个隐式 ListBoxItem,并将其 DataContext 设置为该对象,因此您可以毫无顾虑地使用 YourControl 中的绑定。

      【讨论】:

      • 别傻了...只需使用 DataTemplates.. 更简单、更干净! :)
      【解决方案3】:

      以上所有答案都有效,但我将在我的应用程序中说明我是如何做到这一点的。 我正在实现利用这些 WPF 功能的MVVM 架构。 这是我正在使用的UserControl,其中ItemsControl 填充了某种类型的项目:

      <UserControl x:Class="Controls.StepView"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:my="clr-namespace:Controls"
          Background="Transparent">
      
          <UserControl.Resources>
              <DataTemplate DataType="{x:Type my:ParameterViewModel}" >
                  <my:ParameterView HorizontalAlignment="Stretch" Margin="25 0 0 0"/> 
              </DataTemplate>
          </UserControl.Resources>
      
          <Grid>
              <ItemsControl Name="stkStepContent" ItemsSource="{Binding Parameters}" />
          </Grid>
      </UserControl>
      

      让我为你解释一下代码。在DataTemplate 部分我说我想用UserControl ParameterView 渲染类ParameterViewModel 的对象。我的ItemsControlItemsSource 属性绑定到List&lt;ParameterViewModel&gt;。当 ItemsControl 为 List 上的每个 ParameterViewModel 启动时,它将创建一个 ParameterView 并将其 DataContext 设置为它正在呈现的 ParameterViewmodel。 我发现这种架构模式对于我构建 WPF 应用程序来说是最直观的。

      【讨论】:

      • 我自己试过这个,但是我可以完全根据我的需要重新调整 DataTemplate。 DataTempalte 是否被我们在示例中看不到的 ParameterViewModel 内部访问?