2

我在窗口窗体上有两个网格,当用户单击第一个网格单元格时,我需要通过单元格之间的线从一个网格到另一个网格显示映射,并且此功能适用于滚动条,这意味着行位置将根据单元格位置而改变当用户移动垂直滚动条时。

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

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

感谢您提供任何帮助,并在此先感谢您 向Shailesh 致以最诚挚的
问候

4

2 回答 2

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

结果:

在此处输入图像描述

  • 分辨率独立。尝试调整窗口大小并亲自查看。
  • 代码真的很简单。后面的大部分代码实际上是支持示例的样板文件(生成随机值等)。
  • 没有“所有者抽奖”,没有 P/Invoke。只是简单,简单的属性和INotifyPropertyChanged.
  • WPF 规则。只需将我的代码复制并粘贴到 a 中File -> New Project -> WPF Application,然后自己查看结果。
于 2013-04-18T16:00:00.473 回答
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;
        }
    }
}

这个?

然后对我想的另一个网格使用相同的

于 2013-04-17T13:24:45.303 回答