在阅读了@techhero 的回答后,我有了一个疯狂的想法,我设法实现了(感谢Tao Ling's answer to this question)。它并不完美,但它可以解决问题。我基本上将 DataGrid 分成两部分,一个带有 X 列(带有变量 .ItemsSource),一个带有 Y 列,一个紧挨着另一个。
以下是相关代码:
XAML
<DataGrid Grid.Column="0"
x:Name="CoordinatesX"
LoadingRow="RowIndexX"
VerticalScrollBarVisibility="Disabled"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="X" x:Name="XColumn"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Column="1"
x:Name="CoordinatesY"
ItemsSource="{Binding DataContext.Points, ElementName=CableTab}"
LoadingRow="RowIndexY"
RowHeaderWidth="0"
ScrollViewer.ScrollChanged="ScrollChanged"
VerticalScrollBarVisibility="Visible"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Y"/>
</DataGrid.Columns>
</DataGrid>
.CS
private void RowIndexX(object sender, DataGridRowEventArgs e)
{
e.Row.Header = (e.Row.GetIndex() + 1).ToString();
}
private void RowIndexY(object sender, DataGridRowEventArgs e)
{
e.Row.Header = " ";
}
void ControlBindings()
{
var resultSections = NProjectProperties.Instance.ResultSections;
var cable = DataContext as NCable;
Binding binding;
if (EqualToResults.IsChecked == true)
{
CoordinatesX.ItemsSource = resultSections;
XColumn.IsReadOnly = true;
XColumn.Foreground = Brushes.DarkGray;
binding = new Binding();
}
else
{
CoordinatesX.ItemsSource = cable.Points;
XColumn.IsReadOnly = false;
XColumn.Foreground = Brushes.Black;
binding = new Binding("X");
}
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
XColumn.Binding = binding;
}
private void EqualToResultsChanged(object sender, RoutedEventArgs e)
{
ControlBindings();
}
private void ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var scroll1 = NU.GetDescendantByType(CoordinatesX, typeof(ScrollViewer)) as ScrollViewer;
var scroll2 = NU.GetDescendantByType(CoordinatesY, typeof(ScrollViewer)) as ScrollViewer;
scroll1.ScrollToVerticalOffset(scroll2.VerticalOffset);
}
public static class NU
{
public static Visual GetDescendantByType(Visual element, Type type)
{
if (element == null) return null;
if (element.GetType() == type) return element;
Visual foundElement = null;
if (element is FrameworkElement)
{
(element as FrameworkElement).ApplyTemplate();
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
foundElement = GetDescendantByType(visual, type);
if (foundElement != null)
break;
}
return foundElement;
}
}
ScrollViewer.ScrollChanged="ScrollChanged" 行允许 DataGrids 一起滚动。
但是,第一个 DataGrid 有一个行标题,由于某种原因,这会使行稍大一些。这意味着,如果第二个没有标题,它们就不会对齐。因此,第二个 DataGrid 被赋予了一个 LoadingRowY 函数,该函数返回一个自 RowHeaderWidth="0" 以来未出现的“”标头。然而,这确实会使行以与第一个 DataGrid 相同的比例绘制,并对齐它们。
可以看出,两个DataGrids之间的空间不是很漂亮和干净,应该改进,但我现在很满意。