WINUI3/UWP中如何设置DataGrid行鼠标悬停时背景透明?
在WINUI3的Community Toolkit DataGrid中设置行鼠标悬停背景为透明
推荐方案:通过XAML样式修改视觉状态
无需编写后台代码,直接修改DataGridRow的样式覆盖鼠标悬停(PointerOver)状态的背景,这是最符合WINUI设计模式的方式,还能避免反射带来的版本兼容性问题:
<Page.Resources> <!-- 引用Community Toolkit命名空间 --> <xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"/> <Style TargetType="controls:DataGridRow"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="controls:DataGridRow"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <!-- 鼠标悬停状态:设置背景为透明 --> <VisualState x:Name="PointerOver"> <VisualState.Setters> <Setter Target="RootGrid.Background" Value="Transparent"/> </VisualState.Setters> </VisualState> <!-- 可选:同时修改选中行的背景为透明 --> <VisualState x:Name="Selected"> <VisualState.Setters> <Setter Target="RootGrid.Background" Value="Transparent"/> </VisualState.Setters> </VisualState> <VisualState x:Name="SelectedUnfocused"> <VisualState.Setters> <Setter Target="RootGrid.Background" Value="Transparent"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"> <ContentPresenter Content="{TemplateBinding Content}"/> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Page.Resources>
代码方式(修正版)
如果坚持用后台代码实现,需要修正原代码的核心问题,确保只修改当前悬停行的背景,并正确处理状态恢复:
using CommunityToolkit.WinUI.UI.Controls; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Controls; public DataGridControl() { this.Loaded += DataGridControl_Loaded; } private void DataGridControl_Loaded(object sender, RoutedEventArgs e) { if (sender is not DataGrid dataGrid) return; // 监听行容器生成事件,确保新添加的行也能绑定事件 dataGrid.ItemContainerGenerator.ItemsChanged += ItemContainerGenerator_ItemsChanged; // 初始化已存在的行事件绑定 BindRowEvents(dataGrid); } private void ItemContainerGenerator_ItemsChanged(object? sender, ItemsChangedEventArgs e) { if (sender is ItemContainerGenerator generator && generator.ContainerFromIndex(0) is DataGridRow row) { var dataGrid = row.FindParent<DataGrid>(); BindRowEvents(dataGrid); } } private void BindRowEvents(DataGrid dataGrid) { foreach (var row in dataGrid.FindDescendants().OfType<DataGridRow>()) { // 避免重复绑定事件 row.PointerEntered -= Row_PointerEntered; row.PointerEntered += Row_PointerEntered; row.PointerExited -= Row_PointerExited; row.PointerExited += Row_PointerExited; } } private void Row_PointerEntered(object sender, PointerRoutedEventArgs e) { if (sender is DataGridRow row && !row.IsSelected) { row.Background = new SolidColorBrush(Windows.UI.Colors.Transparent); } } private void Row_PointerExited(object sender, PointerRoutedEventArgs e) { if (sender is DataGridRow row && !row.IsSelected) { // 恢复为DataGrid的背景色,或自定义默认背景 row.Background = this.Background; } }
原代码的问题说明
- 监听整个DataGrid的
PointerEntered事件会导致鼠标进入时所有行背景被修改,而非当前悬停的行 - 错误使用反射访问
IsSelected,该属性是DataGridRow的公开成员,可直接调用 - 缺少
PointerExited事件处理,鼠标离开行后无法恢复默认背景
内容的提问来源于stack exchange,提问作者Ragavan
相关产品推荐
相关产品推荐

