WPF DataGrid:将集合属性绑定到列

WPF DataGrid:将集合属性绑定到列,wpf,collections,binding,datagrid,Wpf,Collections,Binding,Datagrid,我有一门课叫Person: public class Person { private string _Name; private ObservableCollection<Smartphone> _Smartphones; // Properties } public class Smartphone { private string _Manufacturer; private bool _IsWorking; // Properties

我有一门课叫Person:

public class Person
{
  private string _Name;
  private ObservableCollection<Smartphone> _Smartphones;

  // Properties
}

public class Smartphone
{
    private string _Manufacturer;
    private bool _IsWorking;

    // Properties
}
公共类人物
{
私有字符串\u名称;
私人可观测收集"智能手机;;
//性质
}
公共级智能手机
{
私人字符串制造商;
私人厕所正在工作;
//性质
}
在我看来,我有一个数据网格。 我的问题是:

有没有办法让我的DataGrid看起来像这样:

所有人在他们的收藏中都有相同的智能手机,但“正在工作”的价值观不同

编辑: 我在DataGrid中尝试了DataGrid,如:

<DataGrid ItemsSource="{Binding PersonCollection}"
                  AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" Header="Name" />
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DataGrid ItemsSource="{Binding Smartphones}">
                            </DataGrid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

但这不是我想要的“解决方案”

编辑2:如果有一个复选框而不是“真/假”,那就太好了。

试试这个

SmartPhone.cs Person.cs

视图模型

公共类视图模型
{
公共视图模型()
{
ColumnHeaders=新的ObservableCollection();
PersonCollection=新的ObservableCollection()
{
new Person(){Name=“Foo”,
智能手机=新的ObservableCollection()
{new SmartPhone(){Manufacturer=“Manufacturer1”,IsWorking=true}
,新智能手机(){Manufacturer=“Manufacturer2”,IsWorking=false}
,new Person(){Name=“Bar”,
智能手机=新的ObservableCollection()
{new SmartPhone(){Manufacturer=“Manufacturer1”,IsWorking=true}
,新智能手机(){Manufacturer=“Manufacturer2”,IsWorking=false}
,新智能手机(){Manufacturer=“Manufacturer3”,IsWorking=true}}
,new Person(){Name=“FooBar”,
智能手机=新的ObservableCollection()
{new SmartPhone(){Manufacturer=“Manufacturer1”,IsWorking=true}
,新智能手机(){Manufacturer=“Manufacturer2”,IsWorking=false}
,新智能手机(){Manufacturer=“Manufacturer3”,IsWorking=true}
,新智能手机(){Manufacturer=“Manufacturer4”,IsWorking=false}
,新智能手机(){Manufacturer=“Manufacturer5”,IsWorking=true}
}}
};
foreach(PersonCollection.SelectMany(s=>s.smartners.Select)(s=>s.Manufacturer.Distinct())中的var项)
{
列标题。添加(项);
}
}
公共ObservableCollection PersonCollection{get;set;}
公共ObservableCollection列标题{get;set;}
}
输出

我希望这会有所帮助


好问题。如果您也发布您的尝试会更好。我想这可以通过
DataTable
轻松完成。您只需将
列表
转换为带有必要列的datatable。另一种方法是
CustomTypeDescriptor
(虽然不确定)。我想OP需要它在长度上是动态的,那么我想我误解了这个问题。我不确定,让OP确认一下。否则,这是一个很好的答案。每个皮尔逊会有相同数量的手机吗?这仍然是一个有效的解决方案吗?
public class Person 
{
    public string Name { get; set; }

    public ObservableCollection<SmartPhone> SmartPhones { get; set; }
}

public class SmartPhone
{
    public string Manufacturer { get; set; }

    public bool IsWorking { get; set; }
}
    public class MyDataGrid:DataGrid
{
    public ObservableCollection<string> ColumnHeaders
    {
        get { return GetValue(ColumnHeadersProperty) as ObservableCollection<string>; }
        set { SetValue(ColumnHeadersProperty, value); }
    }

    public static readOnly DependencyProperty ColumnHeadersProperty = DependencyProperty.Register("ColumnHeaders", typeof(ObservableCollection<string>), typeof(MyDataGrid), new PropertyMetadata(new PropertyChangedCallback(OnColumnsChanged)));

    static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid=d as MyDataGrid;
        dataGrid.Columns.Clear();
        //Add Person Column
        dataGrid.Columns.Add(new DataGridTextColumn() { Header = "Name", Binding = new Binding("Name") });
        //Add Manufactures Columns
        foreach (var value in dataGrid.ColumnHeaders)
        {
            var column=new DataGridCheckBoxColumn(){Header=value,Binding=new Binding("SmartPhones"){ConverterParameter=value,Converter=new ManufacturerConverter()}};
            dataGrid.Columns.Add(column);
        }
    }
}

public class ManufacturerConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var smartPhones = value as IEnumerable<SmartPhone>;
        if (smartPhones != null && parameter!=null)
        {
            var phone=smartPhones.FirstOrDefault(s => s.Manufacturer == parameter.ToString());
            if (phone != null)
                return phone.IsWorking;
            return false;
        }
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
    <StackPanel>
    <local:MyDataGrid AutoGenerateColumns="False"
                      ColumnHeaders="{Binding ColumnHeaders}"
                      ItemsSource="{Binding PersonCollection}"
                      CanUserAddRows="False" IsReadOnly="True">

    </local:MyDataGrid>
</StackPanel>
    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}
public class ViewModel
{
    public ViewModel()
    {
        ColumnHeaders = new ObservableCollection<string>();
        PersonCollection = new ObservableCollection<Person>()
        {
            new Person(){Name="Foo",
                SmartPhones=new ObservableCollection<SmartPhone>()
                {new SmartPhone(){Manufacturer="Manufacturer1",IsWorking=true}
                    ,new SmartPhone(){Manufacturer="Manufacturer2",IsWorking=false}}}
        , new Person(){Name="Bar",
                SmartPhones=new ObservableCollection<SmartPhone>()
                {new SmartPhone(){Manufacturer="Manufacturer1",IsWorking=true}
                    ,new SmartPhone(){Manufacturer="Manufacturer2",IsWorking=false}
                    ,new SmartPhone(){Manufacturer="Manufacturer3",IsWorking=true}}}

        , new Person(){Name="FooBar",
                SmartPhones=new ObservableCollection<SmartPhone>()
                {new SmartPhone(){Manufacturer="Manufacturer1",IsWorking=true}
                    ,new SmartPhone(){Manufacturer="Manufacturer2",IsWorking=false}
                    ,new SmartPhone(){Manufacturer="Manufacturer3",IsWorking=true}
                    ,new SmartPhone(){Manufacturer="Manufacturer4",IsWorking=false}
                    ,new SmartPhone(){Manufacturer="Manufacturer5",IsWorking=true}
                }}


        };
        foreach (var item in PersonCollection.SelectMany(s=>s.SmartPhones).Select(s=>s.Manufacturer).Distinct())
        {
            ColumnHeaders.Add(item);
        }
    }

    public ObservableCollection<Person> PersonCollection { get; set; }

    public ObservableCollection<string> ColumnHeaders { get; set; }
}