WPF 数据网格水平滚动条问题
本文关键字:滚动条 问题 水平 网格 数据 数据网 WPF | 更新日期: 2023-09-27 17:56:41
我有以下数据网格:
<DataGrid x:Name="myDataGrid"
RowHeaderWidth="{Binding RelativeSource={RelativeSource Self},
Path=RowHeight}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="*"
Binding="{Binding Name}"/>
<DataGridTextColumn Header="Age" Width="1.2*"
Binding="{Binding Age}"/>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Content="Add" Click="Button_Click"
Width="100"/>
private void Button_Click(object sender, RoutedEventArgs e)
{
var person = new Person()
{
Name = "Aaa",
Age = 27
};
myDataGrid.Items.Add(person);
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
问题是添加新行时出现水平滚动条,这是不必要的。删除 RowHeaderWidth 属性将解决问题,但我需要它来显示验证错误。将 RowHeaderWidth 设置为固定值将无济于事。有人可以好心地建议我一个独奏吗?
试试这个:
<DataGrid x:Name="myDataGrid"
RowHeaderWidth="{Binding RelativeSource={RelativeSource Self},
Path=RowHeight}" ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="*"
Binding="{Binding Name}"/>
<DataGridTextColumn Header="Age" Width="*"
Binding="{Binding Age}"/>
</DataGrid.Columns>
</DataGrid>
我发现的一种解决方法是设置按钮的宽度,该按钮位于行和列的交集(数据网格的左上角)。将第一行添加到数据网格时,此按钮将显示在可视化树中。我在这里了解了这个按钮。
public MainWindow()
{
InitializeComponent();
myDataGrid.ItemContainerGenerator.StatusChanged += onItemContainerGeneratorStatusChanged;
}
private void onItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
if (((ItemContainerGenerator)sender).Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
Button btn = GetVisualChild<Button>(myDataGrid);
if (btn != null)
{
btn.Width = myDataGrid.RowHeaderActualWidth;
}
}
}
public T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null) child = GetVisualChild<T>(v);
if (child != null) break;
}
return child;
}
但是,如果我将DataGrid.RowDetailsTemplate和DataGrid.SelectedItem设置为新添加的行,则它不起作用。所以我尝试了以下方法:
private void onItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
if (((ItemContainerGenerator)sender).Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
ScrollViewer sv = GetVisualChild<ScrollViewer>(myDataGrid);
if (sv != null)
{
AutomationPeer automationPeer = FrameworkElementAutomationPeer.FromElement(sv);
if (automationPeer == null)
automationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(sv);
IScrollProvider provider = automationPeer.GetPattern(PatternInterface.Scroll) as IScrollProvider;
try { provider.Scroll(ScrollAmount.SmallIncrement, ScrollAmount.NoAmount); }
catch { }
try { provider.Scroll(ScrollAmount.SmallDecrement, ScrollAmount.NoAmount); }
catch { }
}
}
}
这确实解决了原始问题,但引入了一个新问题:验证错误红色框现在从文本框中移出,它们指示其错误。
另一个对我更好的解决方法是:
private void fixScrollBarBug()
{
ScrollBar scrollBar = GetChildByName<ScrollBar>(myDataGrid, "PART_HorizontalScrollBar");
if (scrollBar != null)
{
if (VisualTreeHelper.GetChildrenCount(scrollBar) > 0)
{
Grid grid = (Grid)VisualTreeHelper.GetChild(scrollBar, 0);
if (VisualTreeHelper.GetChildrenCount(grid) == 3)
{
try
{
RepeatButton leftButton = (RepeatButton)VisualTreeHelper.GetChild(grid, 0);
RepeatButton rightButton = (RepeatButton)VisualTreeHelper.GetChild(grid, 2);
AutomationPeer automationPeer = FrameworkElementAutomationPeer.FromElement(rightButton);
if (automationPeer == null)
automationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(rightButton);
IInvokeProvider provider = automationPeer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
provider.Invoke();
automationPeer = FrameworkElementAutomationPeer.FromElement(leftButton);
if (automationPeer == null)
automationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(leftButton);
provider = automationPeer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
provider.Invoke();
}
catch { }
}
}
}
}
在添加第一行后调用上述方法,解决了问题:
myDataGrid.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(
delegate
{
fixScrollBarBug();
}));