如何在两个DataGridView控件之间绘制线条

我在Window窗体上有两个网格,我需要在用户点击第一个网格单元时显示从一个网格到其他网格的单元格之间的线条,并且此function与滚动条一起工作意味着线条位置将根据单元格位置而改变当用户移动垂直滚动条时。

请使用以下链接查看图片以获得更多说明。

http://sofzh.miximages.com/c%23/Mapping.png

任何帮助表示赞赏,并提前致谢
最好的祝福
SHAILESH

好。 我发布这个作为答案,因为OP要求它。

这是我对WPF的看法:

                                   

代码背后:

  public partial class DataGridConnectors : Window { public List Items1 { get; set; } public List Items2 { get; set; } public List Connectors { get; set; } private ObservableCollection _visibleConnectors; public ObservableCollection VisibleConnectors { get { return _visibleConnectors ?? (_visibleConnectors = new ObservableCollection()); } } public DataGridConnectors() { Connectors = new List(); InitializeComponent(); Loaded += OnLoaded; Items1 = Enumerable.Range(0, 1000).Select(x => "Item1 - " + x.ToString()).ToList(); Items2 = Enumerable.Range(0, 1000).Select(x => "Item2 - " + x.ToString()).ToList(); DataContext = this; } private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) { var scrollviewer1 = FindDescendent(DG1).FirstOrDefault(); var scrollviewer2 = FindDescendent(DG2).FirstOrDefault(); if (scrollviewer1 != null) scrollviewer1.ScrollChanged += scrollviewer_ScrollChanged; if (scrollviewer2 != null) scrollviewer2.ScrollChanged += scrollviewer_ScrollChanged; } private void scrollviewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { var visiblerows1 = GetVisibleContainers(Items1, DG1.ItemContainerGenerator); var visiblerows2 = GetVisibleContainers(Items2, DG2.ItemContainerGenerator); var visibleitems1 = visiblerows1.Select(x => x.DataContext); var visibleitems2 = visiblerows2.Select(x => x.DataContext); var visibleconnectors = Connectors.Where(x => visibleitems1.Contains(x.Start) && visibleitems2.Contains(x.End)); VisibleConnectors.Where(x => !visibleconnectors.Contains(x)) .ToList() .ForEach(x => VisibleConnectors.Remove(x)); visibleconnectors.Where(x => !VisibleConnectors.Contains(x)) .ToList() .ForEach(x => VisibleConnectors.Add(x)); foreach(var connector in VisibleConnectors) { var startrow = visiblerows1.FirstOrDefault(x => x.DataContext == connector.Start); var endrow = visiblerows2.FirstOrDefault(x => x.DataContext == connector.End); if (startrow != null) connector.StartPoint = Point.Add(startrow.TransformToAncestor(Root).Transform(new Point(0, 0)), new Vector(startrow.ActualWidth + 5, (startrow.ActualHeight / 2)*-1)); if (endrow != null) connector.EndPoint = Point.Add(endrow.TransformToAncestor(Root).Transform(new Point(0, 0)), new Vector(-5,(endrow.ActualHeight / 2 ) * -1)); } } private static List GetVisibleContainers(IEnumerable source, ItemContainerGenerator generator) { return source.Select(generator.ContainerFromItem).Where(x => x != null).OfType().ToList(); } public static List FindDescendent(DependencyObject element) where T : DependencyObject { var f = new List(); for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = VisualTreeHelper.GetChild(element, i); if (child is T) f.Add((T)child); f.AddRange(FindDescendent(child)); } return f; } private void Sequential_Click(object sender, RoutedEventArgs e) { Connectors.Clear(); Enumerable.Range(0, 1000).Select(x => new DataItemConnector() { Start = Items1[x], End = Items2[x] }) .ToList() .ForEach(x => Connectors.Add(x)); scrollviewer_ScrollChanged(null, null); } private void Random_Click(object sender, RoutedEventArgs e) { Connectors.Clear(); var random = new Random(); Enumerable.Range(500, random.Next(600, 1000)) .Select(x => new DataItemConnector() { Start = Items1[random.Next(0, 999)], End = Items2[random.Next(0, 999)] }) .ToList() .ForEach(Connectors.Add); scrollviewer_ScrollChanged(null, null); } } 

连接器:

  public class DataItemConnector: PropertyChangedBase { public object Start { get; set; } public object End { get; set; } private Point _startPoint; public Point StartPoint { get { return _startPoint; } set { _startPoint = value; OnPropertyChanged("StartPoint"); } } private Point _endPoint; public Point EndPoint { get { return _endPoint; } set { _endPoint = value; OnPropertyChanged("EndPoint"); } } } 

支持双向绑定的基类:

 public class PropertyChangedBase:INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { Application.Current.Dispatcher.BeginInvoke((Action) (() => { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); })); } } 

结果:

在此处输入图像描述

  • 决议独立。 尝试调整窗口大小并亲自查看。
  • 代码真的很简单。 后面的大多数代码实际上是支持示例的样板(生成随机值等)。
  • 没有“所有者抽奖”,没有P / Invoke。 只是简单,简单的属性和INotifyPropertyChanged
  • WPF规则。 只需将我的代码复制并粘贴到File -> New Project -> WPF Application然后自己查看结果。

就像是 :

 foreach (DataGridViewRow row in dataGrid.Rows) { var cellValue = row.Cells["field"].Value; if (cellValue != null && cellValue.ToString() == "something") { dataGrid.Rows[row.Index].Selected = true; try { dataGrid.FirstDisplayedScrollingRowIndex = row.Index - 4; } catch (Exception execc) { dataGrid.FirstDisplayedScrollingRowIndex = row.Index; } } } 

这个?

然后使用相同的其他网格我想