如何画两个DataGridView的控件之间的线/秒 [英] How to Draw line/s between Two DataGridView Controls

查看:159
本文介绍了如何画两个DataGridView的控件之间的线/秒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有窗口的形式在两格,我需要从一个网格到其他网格显示通过细胞/ s的线映射时第一次网格用户点击也是这个功能带滚动条的工作意味着线的位置会根据变化当用户移动垂直滚​​动条中的单元格位置。



请使用以下链接查看图像的详细说明。



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



任何帮助表示赞赏和感谢提前

顺祝商祺

SHAILESH

解决方案

确定。 。林张贴这作为一个答案,因为OP自找的。

这是我的WPF采取如下:

 <窗​​口x:类=MiscSamples.DataGridConnectors
的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/presentation
的xmlns:X =htt​​p://schemas.microsoft.com/winfx/2006/xaml
标题=DataGridConnectorsHEIGHT =300WIDTH =300>
<电网X:NAME =根>
< Grid.ColumnDefinitions>
< ColumnDefinition />
< ColumnDefinition />
< ColumnDefinition />
< /Grid.ColumnDefinitions>

<的ItemsControl的ItemsSource ={结合VisibleConnectors}Grid.ColumnSpan =3>
< ItemsControl.ItemsPanel>
< ItemsPanelTemplate>
<帆布IsItemsHost =真/>
< / ItemsPanelTemplate>
< /ItemsControl.ItemsPanel>
< ItemsControl.ItemTemplate>
<&DataTemplate的GT;
<线X1 ={结合StartPoint.X}
Y1 ={结合StartPoint.Y}
X2 ={结合EndPoint.X}
Y2 ={结合EndPoint.Y}
行程=黑
StrokeThickness =2/>
< / DataTemplate中>
< /ItemsControl.ItemTemplate>
< / ItemsControl的>

<数据网格的ItemsSource ={结合Items1}X:NAME =DG1的AutoGenerateColumns =FALSE>
< D​​ataGrid.Columns>
< D​​ataGridTextColumn绑定={绑定路径=}/>
< /DataGrid.Columns>
< / DataGrid的>

<数据网格的ItemsSource ={结合Items2}X:NAME =DG2的AutoGenerateColumns =FALSEGrid.Column =2>
< D​​ataGrid.Columns>
< D​​ataGridTextColumn绑定={绑定路径=}/>
< /DataGrid.Columns>
< / DataGrid的>

将;的StackPanel Grid.Column =1>
<按钮内容=连续点击=Sequential_Click/>
<按钮内容=随机点击=Random_Click/>
< / StackPanel的>
< /网格和GT;
< /窗GT;

代码背后:

 公共部分类DataGridConnectors:窗口
{
公开名单<串GT; Items1 {搞定;组; }

公开名单<串GT; Items2 {搞定;组; }

公开名单< D​​ataItemConnector>连接器{搞定;组; }

私人的ObservableCollection< D​​ataItemConnector> _visibleConnectors;
公众的ObservableCollection< D​​ataItemConnector> VisibleConnectors
{
{返回_visibleConnectors? (_visibleConnectors =新的ObservableCollection< D​​ataItemConnector>()); }
}

公共DataGridConnectors()
{
连接=新的List< D​​ataItemConnector>();

的InitializeComponent();
加载+ = OnLoaded;

Items1 = Enumerable.Range(0,1000)。选择(X =>中的Item1 - + x.ToString())。了ToList();
Items2 = Enumerable.Range(0,1000)。选择(X =>中项目2 - + x.ToString())。了ToList();

的DataContext =这一点;
}

私人无效OnLoaded(对象发件人,RoutedEventArgs routedEventArgs)
{
VAR scrollviewer1 = FindDescendent<的ScrollViewer>(DG1).FirstOrDefault();
VAR scrollviewer2 = FindDescendent<&的ScrollViewer GT;(DG2).FirstOrDefault();

如果(!scrollviewer1 = NULL)
scrollviewer1.ScrollChanged + = scrollviewer_ScrollChanged;

如果(!scrollviewer2 = NULL)
scrollviewer2.ScrollChanged + = scrollviewer_ScrollChanged;
}

私人无效scrollviewer_ScrollChanged(对象发件人,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);

变种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(在VisibleConnectors VAR连接器)
{
VAR STARTROW = visiblerows1.FirstOrDefault(X => x.DataContext == connector.Start);
VAR endrow = visiblerows2.FirstOrDefault(X => x.DataContext == connector.End);

如果(STARTROW!= NULL)
connector.StartPoint = Point.Add(startrow.TransformToAncestor(根).Transform(新点(0,0)),
新向量(startrow.ActualWidth +5,(startrow.ActualHeight / 2)* - 1));

如果(endrow!= NULL)
connector.EndPoint = Point.Add(endrow.TransformToAncestor(根).Transform(新点(0,0)),
新载体(-5,(endrow.ActualHeight / 2)* -1));

}

}

私人静态列表<&FrameworkElement的GT; GetVisibleContainers(IEnumerable的<对象>源,ItemContainerGenerator发电机)
{
返回source.Select(generator.ContainerFromItem)。凡(X =>!x = NULL).OfType< FrameworkElement的>()了ToList。 ();
}

公共静态列表< T> FindDescendent< T>(DependencyObject的元素),其中T:DependencyObject的
{
变种F =新的List< T>();
的for(int i = 0; I< VisualTreeHelper.GetChildrenCount(元);我++)
{
VAR孩子= VisualTreeHelper.GetChild(单元,I);

如果(孩子T)
f.Add((T)的孩子);

f.AddRange(FindDescendent< T>(孩子));
}
返回F;
}

私人无效Sequential_Click(对象发件人,RoutedEventArgs E)
{
Connectors.Clear();
Enumerable.Range(0,1000)。选择(X =>新建DataItemConnector(){开始= Items1 [X],结束= Items2 [X]})
.ToList()
.ForEach(X => Connectors.Add(X));

scrollviewer_ScrollChanged(NULL,NULL);
}

私人无效Random_Click(对象发件人,RoutedEventArgs E)
{
Connectors.Clear();
变种随机=新的随机();

Enumerable.Range(500,random.Next(600,1000))
。选择(X =>新建DataItemConnector()
{
开始= Items1 [random.Next(0,999),
端= Items2 [random.Next(0,999)
})
.ToList()
.ForEach(连接器。加);


scrollviewer_ScrollChanged(NULL,NULL);
}
}



连接器:

 公共类DataItemConnector:PropertyChangedBase 
{
公共对象开始{搞定;组; }
公共对象最终获得{;组; }

私人点_startPoint;
公共点StartPoint可以
{
{返回_startPoint; }

{
_startPoint =价值;
OnPropertyChanged(StartPoint可以);
}
}

私人点_endPoint;
公共Point端点
{
{返回_endPoint; }

{
_endPoint =价值;
OnPropertyChanged(终结点);
}
}
}



基类来支持双向绑定:

 公共类PropertyChangedBase:INotifyPropertyChanged的
{
公共事件PropertyChangedEventHandler的PropertyChanged;

受保护的虚拟无效OnPropertyChanged(字符串propertyName的)
{
Application.Current.Dispatcher.BeginInvoke((动作)(()=>
{
PropertyChangedEventHandler处理器=的PropertyChanged;
如果(!=处理空值)处理器(这一点,新PropertyChangedEventArgs(propertyName的));
}));
}
}



结果:






  • 分辨率独立。尝试调整窗口的大小,看看它自己。

  • 中的代码是真的很简单。大部分的代码背后实际上是样板支持的例子(生成随机值等)。

  • 没有业主抽奖,没有的P / Invoke。只是简单的,简单的属性和 INotifyPropertyChanged的

  • WPF规则。只需复制并粘贴文件在我的代码 - >新建项目 - > WPF应用程序并查看结果自己。


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 works with scroll bar means line position will change according to the cell position when user moves vertical scroll bar.

please use below link to see image for more clarification.

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

Any help is appreciated and Thanks in advance
Best Regards
Shailesh

解决方案

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:

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

这篇关于如何画两个DataGridView的控件之间的线/秒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆