我有一个DataGrid
,在每个DataGridRow
我都有行详细信息,其中包含几个控件。
我想要的是,如果在行详细信息中点击了任何内容,则:
- 不选择行,或更准确地说,选择
- 更改现有的DataGrid
选项。
我正在考虑在行为中处理PreviewMouseDown和MouseDown事件,以某种方式使DataGrid跳过选择过程,但不确定如何继续。
最终我将在详细信息中包含TabControl以及更多信息,因此我也不希望TabItem单击以更改DataGrid的现有选择。
是否有办法在Grid“DetailsContainer”级别启动PreviewMouseDown的隧道,并在Grid“DetailsContainer”级别停止冒充MouseDown
<DataGrid Name="dgAudit"
CanUserReorderColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
IsReadOnly="True"
ItemsSource="{Binding GEOM_ASSET_OC_LIST}"
VirtualizingPanel.ScrollUnit="Pixel"
RowDetailsVisibilityMode="Visible"
>
<i:Interaction.Behaviors>
<behaviors:DataGridBehaviors />
</i:Interaction.Behaviors>
<DataGrid.Columns>
<DataGridTextColumn Header="Asset ID" Binding="{Binding ASSET_ID}" Width="200" />
<DataGridTextColumn Header="Asset Type" Binding="{Binding ASSET_TYPE}" Width="200" />
<DataGridTextColumn Header="Last Update By" Binding="{Binding LAST_UPDATE_BY}" Width="150" />
<DataGridTextColumn Header="Last Update Date" Binding="{Binding LAST_UPDATE_DATETIME, StringFormat=\{0:dd.MM.yy HH:mm:ss tt\}}" Width="150" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Grid Name="DetailsContainer">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Name Text="{Binding Notes}" Width="400" HorizontalAlignment="Left" TextWrapping="Wrap"/>
<Button Content="Button" Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
快速模拟一个空行为
public class DataGridBehaviors : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.MouseDown += DataGrid_MouseDown;
this.AssociatedObject.PreviewMouseDown += DataGrid_PreviewMouseDown;
}
protected override void OnDetaching()
{
this.AssociatedObject.PreviewMouseDown -= DataGrid_PreviewMouseDown;
this.AssociatedObject.MouseDown -= DataGrid_MouseDown;
base.OnDetaching();
}
private void DataGrid_MouseDown(object sender, MouseButtonEventArgs e)
{
}
private void DataGrid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
DependencyObject obj = (DependencyObject)e.OriginalSource;
DataGridDetailsPresenter RowsDetails = FindParent<DataGridDetailsPresenter>(obj);
if (RowsDetails != null)
{
//Skip over selection, maybe temporarily removed native selection handler???
}
}
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
private static T GetVisualChild<T>(DependencyObject 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;
}
}
答案 0 :(得分:1)
不幸的是,使用当前的WPF DataGrid
实现,无法实现您想要的目标。
DataGridDetailsPresenter
使用MouseLeftButtonDownEvent
API为EventManager
路由事件注册class event handler:
EventManager.RegisterClassHandler(
typeof(DataGridDetailsPresenter),
MouseLeftButtonDownEvent,
new MouseButtonEventHandler(OnAnyMouseLeftButtonDownThunk),
true);
请注意,最后一个参数设置为true
。它是一个标志,指示听众是否想要听到已经处理过的事件。在这种情况下,即使您在任何级别将RoutedEventArgs.Handled
属性设置为true
,也会调用内部DataGridDetailsPresenter
的事件处理程序。
此事件处理程序负责关注DataRow
您单击其中的详细信息视图。你肯定知道,在WPF中,类事件处理程序在实例事件处理程序之前调用。因此,左键单击详细信息行的演示者时,首先会发生的事情是聚焦包含的行(实际上是该行的第一个单元格)。
另请注意,此行为也可以管理RowPresenter
内部虚拟项目的实现,因此禁用它可能会导致不必要的GUI副作用。
您可以将容器IsHitTestVisible
的{{1}}属性设置为Grid
,这将禁用自动行选择行为。但很明显,你根本无法处理行详细信息中的任何点击。
答案 1 :(得分:0)
我发现了另一种可能的解决方法。在Canvas
内创建一个小的DataGridRowHeader
,然后在下一个子容器设置ClipsToBounds
到false
中创建。然后它可以没有标题,但也可以点击它而不影响DataGrid
当前选择。它与行详细信息的IsExpanded
绑定,并查看该部分。
警告的一个词是,如果行详细信息包含大量数据,并且代码如下所示,则可能效率非常低,加载时间和滚动延迟。取决于是否使用virtualization
。此数据将与行同时加载,并且可能效率非常低,而控件位于RowDetailsTemplate
时,按需加载。可能最好通过User Control
或动态地严格控制此数据的加载。
此外,您可能需要收听DataGrid
LayoutUpdated
事件来调整详细控件的宽度。
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<Grid>
<Expander Template="{StaticResource StretchyExpanderTemp}"
OverridesDefaultStyle="True"
Header=""
HorizontalAlignment="Right"
VerticalAlignment="Top"
Expanded="Expander_Expanded" Collapsed="Expander_Collapsed"
IsExpanded="{Binding DataContext.IsExpanded, RelativeSource={RelativeSource AncestorType=DataGridRowHeader}}" />
<Canvas Background="BlueViolet"
Width="5"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Height="5">
<TabControl Name="tcAA"
TabStripPlacement="Left"
Margin="20,18,0,0"
Height="185"
Width="500"
VerticalAlignment="Top"
HorizontalAlignment="Left"
ItemsSource="{Binding DataContext.AAUDIT, RelativeSource={RelativeSource AncestorType=DataGridRowHeader}}"
SelectedIndex="0"
ClipToBounds="False"
Visibility="{Binding DataContext.IsExpanded, RelativeSource={RelativeSource AncestorType=DataGridRowHeader}, Converter={StaticResource bool2VisibilityConverter}}"
>
...
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding DISPLAY_NAME}" />
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
...
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Canvas>
</Grid>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Grid Height="185" >
</Grid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>