【问题标题】:WPF DataGrid horizontal scrollbar issueWPF DataGrid水平滚动条问题
【发布时间】:2013-01-30 05:20:54
【问题描述】:

我有以下数据网格:

<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 设置为固定值无济于事。有人可以建议我一个解决方案吗?

【问题讨论】:

    标签: c# wpf xaml datagrid scrollbar


    【解决方案1】:

    试试这个:

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

    【讨论】:

    • 是的,它可以工作,同样是 Horizo​​ntalScrollBarVisibility="Disabled"。但我需要滚动条在需要时可见。如果列设置了 MinWidth 怎么办?
    【解决方案2】:

    我发现的一种解决方法是设置按钮的宽度,该按钮位于行和列的交叉点(数据网格的左上角)。当第一行添加到数据网格时,此按钮会出现在可视树中。我了解了这个按钮here

    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 { }
        }
      }
    }
    

    这确实解决了原来的问题,但引入了一个新问题:验证错误红色框现在从它们指示错误的文本框移开。

    【讨论】:

      【解决方案3】:

      另一个更适合我的解决方法是:

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

      【讨论】:

        猜你喜欢
        • 2023-03-22
        • 1970-01-01
        • 2012-06-27
        • 2014-12-08
        • 1970-01-01
        • 2011-07-29
        • 1970-01-01
        • 1970-01-01
        • 2012-11-07
        相关资源
        最近更新 更多