【问题标题】:Dynamically bind columns from Dictionary to Silverlight DataGrid将 Dictionary 中的列动态绑定到 Silverlight DataGrid
【发布时间】:2011-07-30 19:04:58
【问题描述】:

我想将对象集合绑定到 Silverlight 中的 DataGrid。对象属于以下类型:

public class Seats
{
    Dictionary<Group, long> dctValues = new Dictionary<Group, long>();

    public int Id { get; set; }

    public Dictionary<Group, long> Values
    {
        get { return dctValues; }
    }
}

而 Group 表示为:

public class Group
{
    public int Id { get; set; }
    public string Name { get; set; }
}

我希望能够根据组字典生成列,其中每列的标题设置为 Group.Name 并且每个项目的单元格值等于 字典中的长值。

【问题讨论】:

  • 到目前为止,我们有一个标题一列和该列中的单元格值。您希望该列还有多少其他单元格? IOW 行从何而来?
  • 假设我们有 List 包含 5 个项目,每个项目将有 3 个组,其名称属性分别为“GroupA”、“GroupB”和“GroupC”。 5项划分如下:Item1:Id:1,GroupA:100,GroupB:200,GroupC:300 Item2:Id:2,GroupA:1000,GroupB:2000,GroupC:3000
  • 好的,下一个问题可能需要考虑一下。 Seats 的两个不同实例(每个 List&lt;Seats&gt; 的成员)在其各自的 Values 字典中都有一个名为“GroupA”的组的条目。它们是否都引用了Group 的单个实例它们是否都有自己不同的Group 实例,而IdName 恰好具有相同的值?跨度>

标签: silverlight


【解决方案1】:

我将假设我们不能保证每个组名只有一个 Group 类的实例。 (否则您会根据已知组的列表生成列吗?)

这是一个派生自DataGrid的类:

public class SeatsGrid : DataGrid, IValueConverter
{
    public SeatsGrid()
    {
        AutoGenerateColumns = false;
    }
    #region public List<Seats> SeatsList

    public List<Seats> SeatsList
    {
        get { return GetValue(SeatsListProperty) as List<Seats>; }
        set { SetValue(SeatsListProperty, value); }
    }

    public static readonly DependencyProperty SeatsListProperty =
        DependencyProperty.Register(
            "SeatsList",
            typeof(List<Seats>),
            typeof(SeatsGrid),
            new PropertyMetadata(null, OnSeatsListPropertyChanged));

    private static void OnSeatsListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SeatsGrid source = d as SeatsGrid;
        List<Seats> value = e.NewValue as List<Seats>;
        source.OnSeatsListPropertyChanged(value);
    }

    private void OnSeatsListPropertyChanged(List<Seats> value)
    {
        ItemsSource = null;
        Columns.Clear();

        var groups = value
            .SelectMany(seats => seats.Values.Keys)
            .Select(g => g.Name)
            .Distinct();

        foreach (var group in groups)
        {
            DataGridTextColumn col = new DataGridTextColumn();
            col.Binding = new Binding()
            {
                Converter = this,
                ConverterParameter = group
            };
            col.Header = group;
            Columns.Add(col);
        }

        ItemsSource = value;
    }
    #endregion public List<Seats> SeatsList

    object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Seats seats = (Seats)value;
        string group = (string)parameter;

        Group actualGroup = seats.Values.Keys.FirstOrDefault(g => g.Name == group);
        if (actualGroup != null)
        {
            return seats.Values[actualGroup].ToString();
        }
        else
        {
            return null;
        }
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在 Xaml 中放置此类的一个实例,并将 List&lt;Seats&gt; 分配给它的 SeatsList 属性,它会生成列并呈现行。

它是如何工作的?

魔法始于OnSeatsListPropertyChanged 方法。它首先获取不同组名称的列表。它为每个组名生成一个新的文本列,将标题自然设置为组名。

为列设置绑定时出现了奇怪的东西。为绑定提供了一个转换器,为了方便起见,我决定在SeatsGrid 类上也实现它。转换器参数是组名。由于没有指定路径,所以当绑定实际发生时,整个Seats 对象将被传递给转换器。

现在查看IValueConverter.Convert 方法。它在与转换器参数同名的席位中找到Group 的实例(是任何实例)。 If found 使用 Group 作为键来查找要返回的值。

如果已知组的每个名称都是唯一的,则可以简化代码,但原理相同。

【讨论】:

  • 完美!转换器实际上做到了。非常感谢!
猜你喜欢
  • 2011-03-14
  • 2011-04-13
  • 2014-10-17
  • 1970-01-01
  • 2012-12-19
  • 2014-01-04
  • 1970-01-01
  • 2015-01-16
  • 2012-04-02
相关资源
最近更新 更多