DataGridColumns具有不同的ItemsSources

时间:2014-05-13 16:51:00

标签: c# wpf data-binding datagrid multibinding

我想创建一个带有两列(X和Y)的 DataGrid ,每个列都可以填充不同的集合。

Y列始终使用 ObservableCollection(NPoint)中的Y数据填充,其中 NPoint 是具有X和Y属性的类。

X列开始填充"默认"其他地方定义的值( ObservableCollection(double))。这个"默认"集合属于单例类。但是,根据附近 CheckBox .IsChecked,可能会使用与Y数据相同的集合中的X数据填充X列。

后一种情况很简单,因为两列都将共享相同的ItemsSource。但是,如何将 DataGrid 的一列绑定到一个对象,将另一列绑定到另一个对象?有没有办法将DataGrid.ItemsSource绑定到两个不同的集合?是否可以使用 PriorityBinding 来完成?

2 个答案:

答案 0 :(得分:2)

简而言之,这在DataGrid上是不可行的,它只能绑定到单个数据源。

请在此处查看同样的问题和建议: Bind a WPF data grid to multiple data sources

答案 1 :(得分:0)

在阅读@ techhero的回答之后,我有一个疯狂的想法,我设法完成了(感谢Tao Ling's answer to this question)。它并不完美,但它可以解决问题。我基本上将 DataGrid 分成两个,一个是X列(变量.ItemsSource),一个是Y列,一个紧挨着另一个。

以下是相关代码:

<强> XAML

<DataGrid Grid.Column="0"
            x:Name="CoordinatesX"
            LoadingRow="RowIndexX"
            VerticalScrollBarVisibility="Disabled"
            AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="X" x:Name="XColumn"/>
    </DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Column="1"
            x:Name="CoordinatesY"
            ItemsSource="{Binding DataContext.Points, ElementName=CableTab}" 
            LoadingRow="RowIndexY"
            RowHeaderWidth="0"
            ScrollViewer.ScrollChanged="ScrollChanged"
            VerticalScrollBarVisibility="Visible"
            AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Y"/>
    </DataGrid.Columns>
</DataGrid>

<强> .CS

private void RowIndexX(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = (e.Row.GetIndex() + 1).ToString();
}
private void RowIndexY(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = " ";
}
void ControlBindings()
{
    var resultSections = NProjectProperties.Instance.ResultSections;
    var cable = DataContext as NCable;
    Binding binding;
    if (EqualToResults.IsChecked == true)
    {
        CoordinatesX.ItemsSource = resultSections;
        XColumn.IsReadOnly = true;
        XColumn.Foreground = Brushes.DarkGray;
        binding = new Binding();
    }
    else
    {
        CoordinatesX.ItemsSource = cable.Points;
        XColumn.IsReadOnly = false;
        XColumn.Foreground = Brushes.Black;
        binding = new Binding("X");
    }
    binding.ValidatesOnDataErrors = true;
    binding.NotifyOnValidationError = true;
    XColumn.Binding = binding;
}
private void EqualToResultsChanged(object sender, RoutedEventArgs e)
{
    ControlBindings();
}
private void ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    var scroll1 = NU.GetDescendantByType(CoordinatesX, typeof(ScrollViewer)) as ScrollViewer;
    var scroll2 = NU.GetDescendantByType(CoordinatesY, typeof(ScrollViewer)) as ScrollViewer;
    scroll1.ScrollToVerticalOffset(scroll2.VerticalOffset);
}

public static class NU
{
    public static Visual GetDescendantByType(Visual element, Type type)
    {
        if (element == null) return null;
        if (element.GetType() == type) return element;
        Visual foundElement = null;
        if (element is FrameworkElement)
        {
            (element as FrameworkElement).ApplyTemplate();
        }
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
            foundElement = GetDescendantByType(visual, type);
            if (foundElement != null)
                break;
        }
        return foundElement;
    }
}

Resulting window

ScrollViewer.ScrollChanged="ScrollChanged"行允许 DataGrids 一起滚动。 但是,第一个 DataGrid 有一个行标题,由于某种原因使行略大。这意味着,如果第二个没有给出标题,它们就不会对齐。因此,第二个 DataGrid 被赋予一个LoadingRowY函数,该函数返回一个自“RowHeaderWidth="0"以来不出现的”“标题。但是,这会使行以与第一个 DataGrid 相同的比例绘制,对齐它们。

可以看出,两个 DataGrids 之间的空间不是很好,干净,应该改进,但我现在很满意。