【问题标题】:DataGridColumns with different ItemsSources具有不同项目源的 DataGrid 列
【发布时间】:2014-07-01 11:30:35
【问题描述】:

我想创建一个具有两列(X 和 Y)的 DataGrid,因为每一列都可能由不同的集合填充。

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

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

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

【问题讨论】:

    标签: c# wpf data-binding datagrid multibinding


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      在阅读了@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;
          }
      }
      

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

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

      【讨论】:

        猜你喜欢
        • 2014-09-16
        • 2013-04-04
        • 1970-01-01
        • 2013-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多