How to Draw line/s between Two DataGridView Controls

后端 未结 2 1750
日久生厌
日久生厌 2020-12-20 02:02

i have two grid on Window form , i need to show mapping by lines between cell/s from one grid to other grid when user click on first grid cell and also this functionality wo

相关标签:
2条回答
  • 2020-12-20 02:44

    Ok. Im posting this as an answer because the OP asked for it.

    This is my WPF take on that:

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

    Code Behind:

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

    Connector:

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

    Base class to support two way binding:

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

    Result:

    enter image description here

    • Resolution independent. Try resizing the window and see it for yourself.
    • The code is really really simple. Most of the code behind is actually boilerplate to support the example (generate random values, etc).
    • No "owner draw", No P/Invoke. Just simple, simple properties and INotifyPropertyChanged.
    • WPF rules. Just copy and paste my code in a File -> New Project -> WPF Application and see the results for yourself.
    0 讨论(0)
  • 2020-12-20 02:48

    Something like :

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

    this?

    then use the same for the other grid i suppose

    0 讨论(0)
提交回复
热议问题