【问题标题】:Binding list of objects to ItemsControl with custom ItemTemplate in MVVM在 MVVM 中使用自定义 ItemTemplate 将对象列表绑定到 ItemsControl
【发布时间】:2012-07-27 20:06:59
【问题描述】:

当前设置

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

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 有一个名为ReadOnlyObservableCollection<IInstallerObject> 的属性AvailableInstallerObjects

我的View 有一个GroupBox,其中包含绑定到上述属性的ItemsControl

    <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 多个项目。

这里需要帮助

我希望能够使用我的IInstallerObjects 集合,但让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 代表IInstallerObjects 的ProductType 的可用Build 属性值。

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

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

提前感谢您的帮助。我愿意学习,所以如果我忽略了一些明显的事情,请引导我查看相关信息,我很乐意自学。

【问题讨论】:

    标签: c# wpf data-binding grouping itemscontrol


    【解决方案1】:

    如果 Build 应该是一个集合类型。

    所以你的班级应该以这样的结构为例。

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

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

    【讨论】:

      【解决方案2】:

      您所要做的就是在您的视图中声明一个CollectionViewSource 并将其绑定到ObservableCollection。在此对象中,您声明一个或多个GroupDescriptions,它将源分成几组。

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

      可以在此处找到示例:WPF Sample Series – ListBox Grouping, Sorting, Subtotals and Collapsible Regions。更多关于 CollectionViewSource 的信息可以在这里找到:WPF’s CollectionViewSource

      【讨论】:

        【解决方案3】:

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

        用于树视图的 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 并拥有所有这些东西。但是对于这个例子,我只是让它列出ProductTypes 并用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 平面列表转换为新的分层数据集合,以便更轻松地绑定到视图。

        有关使用和自定义 TreeView 的各种方式的更多信息:http://www.codeproject.com/Articles/124644/Basic-Understanding-of-Tree-View-in-WPF

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-09
          • 2010-12-03
          • 1970-01-01
          • 2013-10-09
          • 1970-01-01
          • 2014-09-24
          • 1970-01-01
          • 2012-02-17
          相关资源
          最近更新 更多