gpt4 book ai didi

c# - 如何在两个 DataGridView 控件之间画线

转载 作者:行者123 更新时间:2023-11-30 20:58:31 25 4
gpt4 key购买 nike

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

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

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

感谢任何帮助并提前致谢
最好的问候
谢丽丝

最佳答案

好的。我将此作为答案发布,因为 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");
}
}
}

支持两种方式绑定(bind)的基类:

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

  • 独立于分辨率。尝试调整窗口大小并亲自查看。
  • 代码真的非常简单。背后的大部分代码实际上是支持示例的样板(生成随机值等)。
  • 没有“owner draw”,没有 P/Invoke。只是简单、简单的属性和 INotifyPropertyChanged
  • WPF 规则。只需将我的代码复制并粘贴到 File -> New Project -> WPF Application 中,然后亲自查看结果。

关于c# - 如何在两个 DataGridView 控件之间画线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16061001/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com