【问题标题】:Binding to multiple sources绑定到多个源
【发布时间】:2013-06-11 17:48:55
【问题描述】:

我正在用D3 绘制图表。目前我正在通过这种方式绑定:

<d3:ChartPlotter x:Name="plotter" ItemsSource="Charts" Margin="20">

然后我在图表中添加/删除项目,绘图仪会自动更新。效果很好。

问题是我需要从几个集合中绑定,但显然我不能设置 ItemsSource 两次。我读过一些关于 CompositeCollections 的文章,但几乎每篇文章都是基于 StaticResource,这不是我的情况。

 <d3:ChartPlotter x:Name="plotter"Margin="20">
 <d3:ChartPlotter.ItemsSource>
    <CompositeCollection>
      <CollectionContainer Collection="{Binding Charts}" />
      <CollectionContainer Collection="{Binding Charts2}" />
      </CompositeCollection>
  </d3:ChartPlotter.ItemsSource>

此代码可以编译,但绑定不起作用。

我搜索了很多,但令人惊讶的是我没有找到答案。我认为这必须是 WPF 中的一项常见任务。

我对将多个集合绑定到单个 ItemsSource 的其他方式持开放态度,但是手动将每个子集合中的每个项目添加到 Charts 我认为这太麻烦了。谢谢你。

编辑:

我正在尝试通过 MultiBinding 来实现,这是转换器的方案

EDIT2:

图表是ObservableCollection&lt;LineGraph&gt;

public class ConcatConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        ObservableCollection<LineGraph> enumerables = new ObservableCollection<LineGraph>();

        foreach (LineGraph line in values[0])
        {
            enumerables.Add(line);
        }

        foreach (LineGraph line in values[1])
        {
            enumerables.Add(line);
        }

        return enumerables;

    }
    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

由于此错误,我无法编译:“foreach 语句可以在“object”类型的变量中运行,因为“object”不包含“GetEnumerator”的公共定义。

【问题讨论】:

  • Charts 和 Charts2 是两个独立的集合吗?另外,如果你只是连接两个集合可以吗?
  • 是的,不知道那个concat操作,我会马上搜索。谢谢
  • 不要搜索,你不会找到的!我只是在问将两个系列放在一起是否可以。
  • 我认为 concat 方法不适合我,因为我需要在添加项目的每个地方连接我的集合。可能我会有几个来源,不仅仅是两个。但是谢谢。你知道是否可以做一些类似于 concat 但在 XAML 中并与绑定兼容的事情?
  • 是的,MultiBinding + IMultiValueConverter。 ;)

标签: c# wpf binding collections


【解决方案1】:

使用MultiBinding。首先,制作一个可以满足您需求的转换器:

public class ConcatConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        List<IEnumerable> enumerables = new List<IEnumerable>();
        foreach (object obj in values)
        {
            IEnumerable temp = obj as IEnumerable;
            if (temp == null) throw new ArgumentException();
            enumerables.Add(temp);
        }
        List<dynamic> enDynamic = new List<dynamic>();
        enDynamic.AddRange(enumerables);
        return Concat((dynamic)enDynamic);
    }
    private IEnumerable<T> Concat<T>(params IEnumerable<T>[] toConcat)
    {
        return toConcat.Aggregate((a, b) => a.Concat(b));
    }
    private IEnumerable Concat(params IEnumerable[] toConcat)
    {
        ArrayList temp = new ArrayList();
        foreach (IEnumerable x in toConcat)
        {
            foreach (object n in x)
            {
                temp.Add(n);
            }
        }
        return temp;
    }
    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

(非泛型,但我不想使用钝量的反射)

然后将其添加到您窗口的资源中:

<!--in your window declaration-->
xmlns:local="clr-namespace:YourNameSpace"
<!--after that-->
<Window.Resources>
    <ttp:ConcatConverter x:Key="Concat"/>
</Window.Resources>
<!--finally:-->
<d3:ChartPlotter.ItemsSource>
    <MultiBinding Converter="{StaticResource ResourceKey=Concat}">    
        <Binding Source="Charts"/>
        <Binding Source="Charts2"/>
    </MultiBinding>
</d3:ChartPlotter.ItemsSource>

【讨论】:

  • 这太棒了。非常感谢。我已经尝试过了,但它不起作用,我认为问题可能出在 temp 的返回类型中。我不知道我的绘图仪是否可以绘制 ArrayList 中的项目,我尝试将其更改为 List 但 Add 方法失​​败(无法从对象转换为 IEnumerable)。
  • 这可能是因为返回类型不是通用的,我需要处理一些(很多)反射。
  • @Sturm 现在应该修复了。
  • 非常感谢您的努力,但不幸的是仍然无法使用。复杂性增加了,我无法正确操作该表达式,难道没有办法合并 Charts 和 Charts2(只有两个)吗?请查看我编辑的问题。
  • @Sturm 又编辑了一遍,如果这次不行,那肯定是DLR有问题了。
猜你喜欢
  • 2011-07-27
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多