将对象列表绑定到 ItemsControl,在 MVVM 中使用自定义 ItemTemplate



当前设置

我有一个表示安装程序文件和有关该文件的一些属性的自定义类,符合以下接口

public interface IInstallerObject
{
    string FileName { get; set; }
    string FileExtension { get; set; }
    string Path { get; set; }
    int Build { get; set; }
    ProductType ProductType { get; set; }
    Architecture ArchType { get; set; }
    bool Configurable { get; set; }
    int AverageInstallTime { get; set; }
    bool IsSelected { get; set; }
}

我的ViewModel有一个名为 AvailableInstallerObjectsReadOnlyObservableCollection<IInstallerObject>属性。

我的View有一个包含与上述财产绑定的ItemsControlGroupBox

    <GroupBox Header="Products">
        <ItemsControl ItemsSource="{Binding Path=AvailableInstallerObjects}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding Path=IsSelected}"
                                  VerticalAlignment="Center" Margin="5"/>
                        <TextBlock Text="{Binding Path=FileName}" Margin="5" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </GroupBox>

绑定工作正常,但它不是用户友好的。 显示 100+ 项。

在这里需要帮助

我希望能够使用我的IInstallerObject集合,但View以以下ItemTemplate结构呈现它们。

    <GroupBox Header="Products">
        <ItemsControl ItemsSource="{Binding Path=AvailableInstallerObjects}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding Path=IsSelected}"
                                  VerticalAlignment="Center" Margin="5"/>
                        <TextBlock Text="{Binding Path=ProductType}" Margin="5" />
                        <ComboBox ItemsSource="{Binding Path=Build}" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </GroupBox>

基本上,我希望能够按ProductType属性分组,显示可用产品的列表,ComboBox表示ProductTypeIInstallerObject的可用Build属性值。

我可以在ViewModel中使用LINQ来提取分组,但我不知道如何绑定到我提取的内容。

我的研究也发现了使用CollectionViewSource的可能性,但我不确定如何将它应用于我当前的设置。

我提前感谢您的帮助。我愿意学习,所以如果我忽略了一些明显的东西,请引导我了解信息,我很乐意教育自己。

如果 Build 应该是集合类型。

所以你的类应该像这样作为例子。

Public Class Customer
 Public Property FirstName as string
Public Property LastName as string
Public Property CustomerOrders as observableCollection(OF Orders)
End Class

这应该会给你预期的结果。主项目演示器中的每个项目将显示与该客户订单绑定的名字姓氏和组合框。我知道这很简单,但这应该可以。

您所

要做的就是在视图中声明一个CollectionViewSource并将其绑定到ObservableCollection。在此对象中,您可以声明一个或多个GroupDescriptions,这些会将源拆分为多个组。

将此源绑定到列表框,为组说明创建一个模板,您就完成了。

可在此处找到一个示例:WPF 示例系列 – 列表框分组、排序、分类汇总和可折叠区域。有关 CollectionViewSource 的更多信息,请参见:WPF 的 CollectionViewSource

对问题的描述使我相信您正在寻找某种合并/扩展/分组/树视图之类的东西。

树视图的 XAML

<Window x:Class="WPFLab12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:WPFLab12"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
      <GroupBox Header="Products">
        <TreeView ItemsSource="{Binding Path=ProductTypes}">
            <TreeView.Resources>
                <HierarchicalDataTemplate 
                    DataType="{x:Type loc:ProductType}"
                    ItemsSource="{Binding AvailableInstallerObjects}">
                    <TextBlock Text="{Binding Description}" />
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type loc:InstallerObject}">
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding Path=IsSelected}" 
                                  VerticalAlignment="Center" Margin="5"/>
                        <TextBlock Text="{Binding Path=FileName}" Margin="5" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
      </GroupBox>
    </Grid>
</Window>

这是做什么的?好吧,它根据找到的数据类型在树中建立控件层次结构。第一个HierarchicalDataTemplate处理如何显示每个类的数据,以及它们在层次结构中的关联方式。第二个HierarchicalDataTemplate处理如何显示每个InstallerObject

主窗口的代码隐藏:

public partial class MainWindow : Window
{
    public ReadOnlyObservableCollection<ProductType> ProductTypes
    {
        get { return (ReadOnlyObservableCollection<ProductType>)GetValue(ProductTypesProperty); }
        set { SetValue(ProductTypesProperty, value); }
    }
    // Using a DependencyProperty as the backing store for ProductTypes.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ProductTypesProperty =
        DependencyProperty.Register("ProductTypes", typeof(ReadOnlyObservableCollection<ProductType>), typeof(MainWindow), new UIPropertyMetadata(null));
    public MainWindow()
    {
        this.InitializeComponent();
        this.ProductTypes = new ReadOnlyObservableCollection<ProductType>(
            new ObservableCollection<ProductType>()
            {
                new ProductType() 
                { 
                    Description = "Type A",
                    AvailableInstallerObjects = new ReadOnlyObservableCollection<InstallerObject>(
                        new ObservableCollection<InstallerObject>()
                        {
                            new InstallerObject() { FileName = "A" },
                            new InstallerObject() { FileName = "B" },
                            new InstallerObject() { FileName = "C" },
                        })
                },
                new ProductType() 
                { 
                    Description = "Type B",
                    AvailableInstallerObjects = new ReadOnlyObservableCollection<InstallerObject>(
                        new ObservableCollection<InstallerObject>()
                        {
                            new InstallerObject() { FileName = "A" },
                            new InstallerObject() { FileName = "D" },
                        })
                }
            });
        this.DataContext = this;
    }
}

不过,这完全是作弊 - 通常MainWindow.cs不会用作DataContext并拥有所有这些东西。但是对于这个例子,我只是让它列出ProductType,并用InstallerObject实例填充每个ProductType类。

我使用的类,

请注意,我做了一些假设并修改了您的类以更好地适应此视图模型:

public class InstallerObject
{
    public string FileName { get; set; }
    public string FileExtension { get; set; }
    public string Path { get; set; }
    public int Build { get; set; }
    public bool Configurable { get; set; }
    public int AverageInstallTime { get; set; }
    public bool IsSelected { get; set; }
}
public class ProductType
{
    public string Description { get; set; }
    public ReadOnlyObservableCollection<InstallerObject> AvailableInstallerObjects
    {
        get;
        set; 
    }
    public override string ToString()
    {
        return this.Description;
    }
}

所以,在 MVVM 中,在我看来,您当前的InstallerObject类更像是模型层之类的东西。您可以考虑在 ViewModel 中将其转换为一组更易于在视图中管理的集合类。ViewModel 中的想法是模拟事物,类似于如何查看和交互它们。将InstallerObjects的平面列表转换为新的分层数据集合,以便更轻松地绑定到视图。

有关使用和自定义树视图的各种方法的详细信息:http://www.codeproject.com/Articles/124644/Basic-Understanding-of-Tree-View-in-WPF

最新更新