2013-04-17 197 views
2

我在窗體窗體上有兩個網格,當用戶單擊第一個網格單元時,我需要顯示從一個網格到另一個網格的單元格之間的線條映射,用滾動條表示當用戶移動垂直滾動條時,行位置將根據單元格位置而改變。如何在兩個DataGridView控件之間繪製線條

請使用下面的鏈接查看圖片以獲取更多說明。

http://s8.postimg.org/49s7i2lvp/Mapping.png

任何幫助表示讚賞,並在此先感謝
問候
SHAILESH

+0

我已經在示例WPF應用程序中實現了這一點。我不知道在WinForms中是否有可能。 winforms是一種古老的技術,並不能真正支持這種交互性。如果你對WPF示例感興趣,請告訴我。 –

+0

請給我WPF樣本,以便我能理解.. – mike

回答

0

喜歡的東西:

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; 
     } 
    } 
} 

呢?

然後使用其它柵格相同的I假設

+0

雖然這是有點作弊,但它不會爲你做任何行,只要使用這個,你可以使第一個網格上的位置與第二個網格相同。但我想它不是你的後 – lemunk

+0

可能投擲行的顏色代碼?或者它是否需要繪製一條線? – lemunk

4

確定。我張貼這個作爲答案,因爲OP要求它。

這是我的WPF採取的是:背後

<Window x:Class="MiscSamples.DataGridConnectors" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="DataGridConnectors" Height="300" Width="300"> 
    <Grid x:Name="Root"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 

     <ItemsControl ItemsSource="{Binding VisibleConnectors}" Grid.ColumnSpan="3"> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <Canvas IsItemsHost="True"/> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <Line X1="{Binding StartPoint.X}" 
          Y1="{Binding StartPoint.Y}" 
          X2="{Binding EndPoint.X}" 
          Y2="{Binding EndPoint.Y}" 
          Stroke="Black" 
          StrokeThickness="2"/> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 

     <DataGrid ItemsSource="{Binding Items1}" x:Name="DG1" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Binding="{Binding Path=.}"/> 
      </DataGrid.Columns> 
     </DataGrid> 

     <DataGrid ItemsSource="{Binding Items2}" x:Name="DG2" AutoGenerateColumns="False" Grid.Column="2"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Binding="{Binding Path=.}"/> 
      </DataGrid.Columns> 
     </DataGrid> 

     <StackPanel Grid.Column="1"> 
      <Button Content="Sequential" Click="Sequential_Click"/> 
      <Button Content="Random" Click="Random_Click"/> 
     </StackPanel> 
    </Grid> 
</Window> 

代碼:

public partial class DataGridConnectors : Window 
    { 
     public List<string> Items1 { get; set; } 

     public List<string> Items2 { get; set; } 

     public List<DataItemConnector> Connectors { get; set; } 

     private ObservableCollection<DataItemConnector> _visibleConnectors; 
     public ObservableCollection<DataItemConnector> VisibleConnectors 
     { 
      get { return _visibleConnectors ?? (_visibleConnectors = new ObservableCollection<DataItemConnector>()); } 
     } 

     public DataGridConnectors() 
     { 
      Connectors = new List<DataItemConnector>(); 

      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<ScrollViewer>(DG1).FirstOrDefault(); 
      var scrollviewer2 = FindDescendent<ScrollViewer>(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<FrameworkElement> GetVisibleContainers(IEnumerable<object> source, ItemContainerGenerator generator) 
     { 
      return source.Select(generator.ContainerFromItem).Where(x => x != null).OfType<FrameworkElement>().ToList(); 
     } 

     public static List<T> FindDescendent<T>(DependencyObject element) where T : DependencyObject 
     { 
      var f = new List<T>(); 
      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<T>(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)); 
       })); 
     } 
    } 

結果:

enter image description here

  • 分辨率無關。嘗試調整窗口大小並親自查看。代碼真的很簡單。大部分背後的代碼實際上是支持該示例的樣板(生成隨機值等)。
  • 沒有「所有者抽籤」,沒有P/Invoke。只是簡單,簡單的屬性和INotifyPropertyChanged
  • WPF規則。只需將我的代碼複製並粘貼到File -> New Project -> WPF Application中即可自行查看結果。
相關問題