<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=test}"></DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid Template="{DynamicResource TemplateDataGridPrintAndExport}"/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
<DataGrid/>
我有一个像上面这样的数据网格。 Datgrid的行详细信息模板还包含数据网格。单击父级列时,将填充内部数据网格。我的问题是:如果行详细信息模板datagrid已完成并且用户鼠标悬停在其上,同时滚动父数据网格则滚动不起作用。用户应将鼠标悬停在主数据栏上以进行滚动。但是,它不是用户友好的。如何防止内部数据网格以这种方式运行?
答案 0 :(得分:5)
我通过尝试替代方案找到了灵魂:
<DataGrid ScrollViewer.CanContentScroll="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=test}"></DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid Template="{DynamicResource TemplateDataGridPrintAndExport}" IsReadOnly="True" ScrollViewer.CanContentScroll="False" IsEnabled="False"/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
<DataGrid/>
解决方案是将ScrollViewer.CanContentScroll="False"
属性赋予外部数据网格,将IsReadOnly="True" ScrollViewer.CanContentScroll="False" IsEnabled="False"
属性赋予内部数据网格。现在它顺利滚动并符合父数据网格。
答案 1 :(得分:3)
如果您使用的是.NET 4.5及更高版本,则可以在外部网格上使用VirtualizingPanel.ScrollUnit="Pixel"
,这将使您可以按像素而不是单位(项)滚动,因为在滚动时,这会导致相当奇怪的行为内部DataGrid,因为它开始跳来跳去。
然后,您可以使用内部DataGrid上的PreviewMouseWheel
事件将滚动事件传递给父级,因为它是由内部控件捕获的。
Xaml:
<DataGrid VirtualizingPanel.ScrollUnit="Pixel">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid PreviewMouseWheel="DataGrid_PreviewMouseWheel"/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
cs:
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
var parent = ((Control)sender).Parent as UIElement;
parent?.RaiseEvent(new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = MouseWheelEvent,
Source = sender
});
}
答案 2 :(得分:1)
我想提出两种替代解决方案,因为选择的一种具有严重的副作用。 Kaizen提到的其中之一-您失去了与嵌套DataGrid及其子控件进行交互的能力。第二个是控件在禁用状态下的外观变化。
在osmanraifgunes的解决方案中将IsReadOnly="True"
更改为IsHitTestVisible="False"
。这样可以解决外观方面的副作用,但是您仍然无法与内部控件进行交互(使用鼠标)。代码:
<DataGrid ScrollViewer.CanContentScroll="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=test}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
IsHitTestVisible="False"
ScrollViewer.CanContentScroll="False"
Template="{DynamicResource TemplateDataGridPrintAndExport}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
在PreviewMouseWheel
中的控件中捕获隧道RowDetailsTemplate
事件,并将其作为冒泡事件传递回父级。这将有效地使RowDetailsTemplate
中的控件仅对鼠标滚动不可见,并允许可视树中上方的控件按其意愿对其进行处理。
xaml:
<DataGrid ScrollViewer.CanContentScroll="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=test}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
PreviewMouseWheel="DataGrid_PreviewMouseWheel"
Template="{DynamicResource TemplateDataGridPrintAndExport}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
后面的代码:
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Handled)
{
return;
}
Control control = sender as Control;
if(control == null)
{
return;
}
e.Handled = true;
var wheelArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = MouseWheelEvent,
Source = control
};
var parent = control.Parent as UIElement;
parent?.RaiseEvent(wheelArgs);
}
答案 3 :(得分:1)
我使用了@Bartłomiej Popielarz的第二种方法来使其工作。
就我而言,control.Parent
总是返回null
。这就是为什么我将相应行更改为
var parent = VisualTreeHelper.GetParent(control) as UIElement;
我还创建了一个附加的属性来进行转发(更适合MVVM方法)。
public class FixScrollingBehaviorOn
{
public static readonly DependencyProperty ParentDataGridProperty = DependencyProperty.RegisterAttached("ParentDataGrid", typeof(DataGrid), typeof(FixScrollingBehaviorOn),
new FrameworkPropertyMetadata(default(DataGrid), OnParentDataGridPropertyChanged));
public static bool GetParentDataGrid(DependencyObject obj)
{
return (bool)obj.GetValue(ParentDataGridProperty);
}
public static void SetParentDataGrid(DependencyObject obj, bool value)
{
obj.SetValue(ParentDataGridProperty, value);
}
public static void OnParentDataGridPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null)
{
throw new ArgumentException("The dependency property can only be attached to a DataGrid", "sender");
}
if (e.NewValue is DataGrid parentGrid)
{
dataGrid.PreviewMouseWheel += HandlePreviewMouseWheel;
parentGrid.SetValue(ScrollViewer.CanContentScrollProperty, false);
}
else
{
dataGrid.PreviewMouseWheel -= HandlePreviewMouseWheel;
if (e.OldValue is DataGrid oldParentGrid)
{
oldParentGrid.SetValue(ScrollViewer.CanContentScrollProperty, ScrollViewer.CanContentScrollProperty.DefaultMetadata.DefaultValue);
}
}
}
private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Handled)
{
return;
}
var control = sender as DataGrid;
if (control == null)
{
return;
}
e.Handled = true;
var wheelArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent,
Source = control
};
var parent = VisualTreeHelper.GetParent(control) as UIElement;
parent?.RaiseEvent(wheelArgs);
}
请按照以下说明在内部DataGrid
上随意使用它。请注意,ScrollViewer.CanContentScrollProperty
是在AttachedProperty中设置的,可能不是每个人都喜欢的方法。
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=test}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
attachedProperties:FixScrollingBehaviorOn.ParentDataGrid="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
Template="{DynamicResource TemplateDataGridPrintAndExport}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
答案 4 :(得分:0)
Xaml:
<DataGrid ScrollViewer.CanContentScroll="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=test}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
PreviewMouseWheel="DataGrid_PreviewMouseWheel"
Template="{DynamicResource TemplateDataGridPrintAndExport}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
后面的代码:
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
DataGrid dg = new DataGrid();
if (sender is DataGrid)
{
dg = (DataGrid)sender;
}
dg.IsEnabled = false;
await Task.Delay(200);
dg.IsEnabled = true;
}