鼠标滚动在带有 wpf 数据网格和其他 UI 元素的滚动查看器中不起作用
我试图弄清楚如何让鼠标滚动在带有滚动查看器和数据网格的 wpf 窗口上工作。 WPF 和 C# 代码如下
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Border Name="DataGridBorder" BorderThickness="2" Margin="1" CornerRadius="4" BorderBrush="#FF080757">
<dg:DataGrid AutoGenerateColumns="False" Name="ValuesDataGrid"
BorderThickness="0" CanUserResizeColumns="True" FontWeight="Bold" HorizontalScrollBarVisibility="Auto"
CanUserReorderColumns="False" IsReadOnly="True" IsTextSearchEnabled="True" AlternationCount="2"
SelectionMode="Extended" GridLinesVisibility="All"
HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserSortColumns="False"
RowDetailsVisibilityMode="Collapsed" SelectedIndex="0"
RowStyle="{StaticResource CognitiDataGridRowStyle}"
>
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Title" >
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=Name}" FontWeight="Normal" />
</StackPanel>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
</Border>
</Grid>
<Button Grid.Row="1" Height="90" >hello world</Button>
</Grid>
</ScrollViewer>
,C# 代码如下
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
initialize();
}
public void initialize()
{
ObservableCollection<MyObject> testList = new ObservableCollection<MyObject>();
for (int i = 0; i < 20; i++)
{
MyObject my = new MyObject("jack " + i);
testList.Add(my);
}
ValuesDataGrid.ItemsSource = testList;
}
}
public class MyObject
{
public string Name { get; set; }
public MyObject(string name)
{
Name = name;
}
}
我面临的问题是,当使用鼠标滚动时,它在按钮上方时工作正常,但一旦我将鼠标指针移到网格上,尝试滚动,没有任何反应。我可以直接移动滚动查看器的滚动条。我仍然是一个 wpf 新手,因此任何关于如何让鼠标滚动在数据网格上工作的帮助将不胜感激。我猜应该有一个非常简单的解决方案,但我还没能弄清楚
I am trying to figure out how to get the mouse scroll working on a wpf window with a scrollviewer and a datagrid within it. The WPF and C# code is below
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Border Name="DataGridBorder" BorderThickness="2" Margin="1" CornerRadius="4" BorderBrush="#FF080757">
<dg:DataGrid AutoGenerateColumns="False" Name="ValuesDataGrid"
BorderThickness="0" CanUserResizeColumns="True" FontWeight="Bold" HorizontalScrollBarVisibility="Auto"
CanUserReorderColumns="False" IsReadOnly="True" IsTextSearchEnabled="True" AlternationCount="2"
SelectionMode="Extended" GridLinesVisibility="All"
HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserSortColumns="False"
RowDetailsVisibilityMode="Collapsed" SelectedIndex="0"
RowStyle="{StaticResource CognitiDataGridRowStyle}"
>
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Title" >
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=Name}" FontWeight="Normal" />
</StackPanel>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
</Border>
</Grid>
<Button Grid.Row="1" Height="90" >hello world</Button>
</Grid>
</ScrollViewer>
and the C# code is as follows
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
initialize();
}
public void initialize()
{
ObservableCollection<MyObject> testList = new ObservableCollection<MyObject>();
for (int i = 0; i < 20; i++)
{
MyObject my = new MyObject("jack " + i);
testList.Add(my);
}
ValuesDataGrid.ItemsSource = testList;
}
}
public class MyObject
{
public string Name { get; set; }
public MyObject(string name)
{
Name = name;
}
}
The problem i am facing is that when using the mouse to scroll, it works fine when it is over the button but as soon as i move the mouse pointer over the grid and try to scroll, nothing happens. I am able to move the scrollbar of the scrollviewer directly though. I am still a wpf novice so any help on how to get the mouse scroll to work over the datagrid would be appreciated. I am guessing there should be a pretty easy solution for this but I havent been able to figure it out
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
我认为戴夫的解决方案是一个很好的解决方案。不过,我提出的一项建议是在滚动查看器而不是数据网格上捕获 PreviewMouseWheel 事件。如果不这样做,您可能会注意到根据您是在数据网格还是滚动条本身上滚动而产生的一些细微差异。原因是当鼠标悬停在滚动条上时,scrollviewer 将处理滚动,而当鼠标悬停在数据网格上时,datagrid 事件将处理滚动。例如,鼠标滚轮在数据网格上滚动可能会比在滚动条上滚动时使您在列表中走得更远。如果您在滚动查看器预览事件中捕获它,则所有滚动时都将使用相同的测量值。另外,如果您以这种方式捕获它,则不需要命名滚动查看器元素,因为您不需要对该对象的引用,因为您只需对传递到滚动查看器 PreviewMouseWheel 事件中的发送者对象进行类型转换。最后,我建议在事件结束时标记处理的事件,除非您出于某种原因需要在层次结构中更靠下的元素中捕获它。下面的例子:
I think Dave's solution is a good one. However, one recommendation I'd make is to catch the PreviewMouseWheel event on the scrollviewer instead of on the datagrid. If you don't, you might notice some minor differences based on whether you're scrolling over the datagrid or the scroll bar itself. The reasoning is that the scrollviewer will be handling scrolling when the mouse is hovered over the scrollbar, and the datagrid event will handle the scrolling when over the datagrid. For instance, one mouse wheel scroll over the datagrid might bring you farther down your list then it would when over the scroll bar. If you catch it on scrollviewer preview event, all will use the same measurement when scrolling. Also, if you catch it this way, you won't need to name the scrollviewer element, as you won't need a reference to the object since you can just type cast the sender object passed into the scrollviewer PreviewMouseWheel event. Lastly, I'd recommend marking the event handled at the end of the event, unless you need to catch it in an element further down the heirarchy for some reason. Example below:
我假设 DataGrid 不需要滚动 - 在 DataGrid 上设置 VerticalScrollBar="None"。
DataGrid 吞掉了鼠标滚动事件。
我发现是使用 PreviewMouseWheel 事件来滚动要滚动的容器。您需要命名滚动查看器才能更改垂直偏移。
I'm assuming the DataGrid does not need to scroll - Set the VerticalScrollBar="None" on the DataGrid.
The DataGrid swallows the mouse scroll event.
What I found is to use the PreviewMouseWheel event to scroll the container that you want to scroll. You will need to name the scrollviewer to change the Vertical offset.
Don B 的解决方案的一项改进是避免使用
ScrollToVerticalOffset
。VerticalOffset - Delta
会带来相当不和谐的体验。 ScrollViewer 花了很多心思让移动变得更加平滑。我认为它还会根据 dpi 和其他因素缩小增量...我发现最好捕获并处理
PreviewMouseWheelEvent
并将MouseWheelEvent
发送到预期的滚动查看器
。我的 Don B 解决方案版本如下所示。An improvement to Don B's solution is to avoid using
ScrollToVerticalOffset
.VerticalOffset - Delta
results in a pretty jarring experience. The ScrollViewer puts a lot of thought into making the movement smoother than that. I think it also scales the delta down based on dpi and other factors...I found it's better to catch and handle the
PreviewMouseWheelEvent
and send aMouseWheelEvent
to the intendedScrollViewer
. My version of Don B's solution looks like this.要启用触摸支持,您可能还需要在
DataGrid
上将ScrollViewer.PanningMode
设置为None
,并将相同的属性设置为VerticalFirst< /code> 或顶级
ScrollViewer
上的其他值示例
当然,也可以使用 Don B 的答案所示的
PreviewMouseWheel
事件来修复原来的鼠标滚动问题。或者,您可以简单地将以下附加属性设置为您的
ScrollViewer
Usage
其中 b: 是包含此行为的命名空间
这样您的应用程序就不需要任何代码隐藏纯粹是MVVM
To enable touch support you might also want to set
ScrollViewer.PanningMode
toNone
on yourDataGrid
and set the same property toVerticalFirst
or other value on your top levelScrollViewer
Example
Of course, also use the
PreviewMouseWheel
event as indicated by Don B's answers to fix the original mouse scrolling issue.Or, you can simply set the following Attached Property to your
ScrollViewer
Usage
Where b: is the namespace that contains this behavior
This way your no code-behind is needed and your app is purely MVVM
我尝试了 Don B 的解决方案,它很好地解决了当您没有其他内部可滚动控件时在数据网格上滚动的问题。
对于滚动查看器具有其他可滚动控件和数据网格作为子项的情况,则要求该事件不应在主滚动查看器的事件处理程序末尾标记为已处理,以便也可以在内部可滚动控件,但是这有一个副作用,即当滚动仅发生在内部可滚动控件上时,它也会发生在主滚动查看器上。
因此,我更新了戴夫的解决方案,其中滚动查看器的发现方式有所不同,因此无需知道滚动查看器的名称:
I tried Don B's solution and it's solves the issue with scrolling over a data grid pretty well for the cases when you don't have other inner scrollable controls.
For the case when the scroll viewer has as children other scrollable controls and a data grid, then that requires that the event shouldn't be marked as handled at the end of the event handler for the main scroll viewer so it could be catched also in the inner scrollable controls, however that has the side effect that when the scroll should occur only on the inner scrollable control, it will also occur on the main scroll viewer.
So I've updated Dave's solution with the difference for how the scroll viewer is found so it won't be necessary to know the name of the scroll viewer:
@fjch1997,我使用了你的解决方案,效果很好。
我发现只有一个问题。它与@Vadim Tofan 的评论有关:
我还尝试删除
e.Handled = true
语句,但效果并不好 - 两个卷轴同时移动。因此,最后我将一点事件处理程序方法增强为以下方法:现在,如果内部 ScrollViewer 存在,这可以防止外部滚动器滚动。
@fjch1997, I used your solution and it works pretty well.
There is only one problem which I found. It's connected with the comment of @Vadim Tofan:
I also tried to remove
e.Handled = true
statement, but then the effect is not nice - both scrolls are moved in the same time. So, finally I enhanced a little bit event handler method to the following one:This now prevents the outside scroller to scroll in case inner ScrollViewer exists.
伙计们,我已经看到了这里发布的大部分解决方案,基本上所有解决方案都是正确的,但我认为我们可以应用一种最简单、更优雅的语法。
假设我们不需要滚动我们的数据网格,而是我们想滚动我们的主窗口
“Dave”和“Vladim Tofan”答案
抱歉,英语不好。
Guys I`ve seen most of the solution posted over here and fundamentally all of them are right, but I think there is an easiest and more elegant syntax that we could apply.
Assuming that we don't need to scroll with our data grid and instead we would like to scroll with our MainWindow
fallowing "Dave" and "Vladim Tofan" answer
Sorry, for bad english.
下面是创建滚动 DataGrid 的 WPF 行为的更大示例。
首先定义以下基类,用于将框架元素与行为类及其行为实现粘合在一起。
这看起来有点复杂,但在将行为类与框架元素粘合在一起时,它简化了样板代码。在这种特殊情况下,我们不需要使用关联的命令。
我们的滚动查看器行为如下所示:
在 XAML 中,我们可以首先定义命名空间:
最后,我们准备通过在 XAML 中使用 WPF 行为来使用鼠标滚轮滚动。
..
我已经测试并验证了这种方法有效。对于使用 WPF 应用程序的开发人员来说,利用 WPF 行为可以将隐藏代码中的代码量保持在最少位,并忠实地遵循 MVVM 方法。
Here is a larger example of creating a WPF behavior that scrolls the DataGrid.
First define the following base class for gluing together framework element with behavior class and its behavior implementation.
This looks a bit more complex, but it simplifies boiler plate coding when it comes to gluing together the behavior class with the framework element. In this particular case we will not need to use an associated command.
Our scroll viewer behavior then looks like this:
In XAML we then can first define the namespaces:
Finally we are ready to use the mouse wheel scroll by using the WPF behavior in the XAML.
..
I have tested and verified that this approach works. For developers working with a WPF app, utilizing WPF behaviors keeps amount of code in code behind still to the minimum bits and staying faitfully to the MVVM approach.
Grid 有一个内置的 ScrollPanel,因此用 ScrollPanel 包裹它对我来说根本不起作用(使 Grid 具有固定高度是不可能的,因为我希望它能够与应用程序的其余部分一起很好地调整大小)。
我所做的是这里一些评价较高的解决方案的组合,但本质上的想法是摆脱 ScrollPanel 并将 DataGrid 的 PreviewMouseEvent 通过管道返回到实际处理滚动的父控件(在我的如果是网格)。
The Grid has a built in ScrollPanel so wrapping it with a ScrollPanel didn't work at all for me (making the Grid of fixed height was out of the question because I wanted it to resize nicely with the rest of the application).
What I did was a combination of a few of the higher rated solutions in here, but essentially the idea is to get rid of the ScrollPanel and just pipe the PreviewMouseEvent of the DataGrid back to the parent control that is actually handling the scrolling (in my case it was a Grid).
我发现了这个: http://wpfthoughts.blogspot.com/ 2014/05/datagrid-vertical-scrolling-issues.html 并认为我应该将其添加到此处。
“如果您的目标是 Framework 4.5,则 DataGrid 的内部 VirtualizingPanel 上有一个名为 ScrollUnit 的新依赖项对象,可以将其设置为 Item(默认值)或 Pixel。如果我们稍微修改一下 XAML,我们就可以看到它是如何工作的。”
I found this: http://wpfthoughts.blogspot.com/2014/05/datagrid-vertical-scrolling-issues.html and thought I should add it here.
"If you are targeting Framework 4.5 there is a new dependency object on the DataGrid's internal VirtualizingPanel called ScrollUnit that can be set to Item (the default) or Pixel. If we modify the XAML a little we can see how it works."
我知道已经有一段时间了,但我遇到了同样的问题并使用 DockPanel 解决了它。
出于某种原因,它可以像魅力一样处理鼠标滚轮事件。
I know it's been a while, but I met the same issue and solved it with DockPanel
For some reason this handles the mouse wheel events like a charm.
我发现 ScrollViewer 无法连接,这意味着如果它像您的情况一样连接,则网格在 ScrollViewer 标记下开始,并且在网格中我们有 DataGrid,并且在 DataGrid 中再次设置了 ScrollViewer 属性。 IE
I found that ScrollViewer can't be concatenated, which means if it is concatenated like in your case the Grid starts under the ScrollViewer tag and in the Grid we have DataGrid and in the DataGrid again the ScrollViewer property has been set. i.e.