WPF数据表格:将集合属性绑定到列

9

我有一个名为Person的类:

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

  // Properties
}

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

    // Properties
}

我有一个数据表格(DataGrid)。我的问题是:

是否有一种方法可以使我的数据表格看起来像这样:

enter image description here

所有人都有相同的智能手机收藏,但“IsWorking”值不同...

编辑: 我已经尝试了在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:如果有一个复选框而不是“真/假”就好了 :)


好问题。如果您也发布您的尝试,那会更好。 - Sriram Sakthivel
我猜这可以很容易地通过使用“DataTable”完成。你所需要做的就是将“List<Person>”转换为带有必要列的数据表。另一种方法是使用“CustomTypeDescriptor”(不过我不确定)。 - Sriram Sakthivel
1个回答

10

试试这个

SmartPhone.cs 和 Person.cs

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();
    }
}

XAML

    <StackPanel>
    <local:MyDataGrid AutoGenerateColumns="False"
                      ColumnHeaders="{Binding ColumnHeaders}"
                      ItemsSource="{Binding PersonCollection}"
                      CanUserAddRows="False" IsReadOnly="True">

    </local:MyDataGrid>
</StackPanel>

xaml.cs

    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; }
}

输出

输出

我希望这会有所帮助。


我猜OP需要它的长度是动态的。 - Sriram Sakthivel
好的,可能有人有两部手机,也可能有人有三部或更多的手机... 问题是,当我打开窗口时,我不知道每个人有多少手机,所以我需要动态生成列 :) - Kajetan Jauk
我已经在 DP 中添加了 "static readonly",现在它可以工作了 :) - Kajetan Jauk
1
这仍然是一个有效的解决方案吗? - Yessir
@Yessir非常抱歉回复晚了 - 很久没有关注这个问题了。 但是仍然回答一下:对我来说,它仍然有效 - 我仍在为办公室开发的软件中使用它 :) - Kajetan Jauk
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接