#wpf
Вопрос:
У меня есть сетка данных с гребными колесами. Эти колесики отображаются в том, что я бы назвал первым столбцом сетки. Все столбцы «данные» имеют заголовок с именем столбца в нем. «Первый столбец», содержащий заголовок строки, не имеет такого «заголовка». Можно ли зафиксировать события щелчка в этом «заголовке»? Чтобы прояснить, что я имею в виду под «заголовком», вот изображение:
Редактировать:
Это мое DataGrid
определение, включая код из ответа @EldHasp
<DataGrid Name="TenantsGrid"
Style="{StaticResource DataGridStyle}"
d:ItemsSource="{Binding TenantGridDataSource}"
AutoGenerateColumns="False"
CanUserResizeRows="False"
SelectionMode="Single"
IsReadOnly="True"
SelectedItem="{Binding SelectedTenant}" Margin="10,0,11,10">
<FrameworkElement.Resources>
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
TargetType="{x:Type Button}"
BasedOn="{StaticResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}">
<EventSetter Event="Click" Handler="OnClickSelectAll"/>
</Style>
</FrameworkElement.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Nachname" Width="Auto" Binding="{Binding LastName}" CanUserSort="True"/>
<DataGridTextColumn Header="Vorname" Width="Auto" Binding="{Binding FirstName}" CanUserSort="True"/>
<DataGridTextColumn Header="eMail" Width="Auto" Binding="{Binding EMail}" CanUserSort="False"/>
<DataGridTextColumn Header="Telefon" Width="Auto" Binding="{Binding PhoneNumber}" CanUserSort="False"/>
<DataGridTextColumn Header="Notizen" Width="*" Binding="{Binding Notes}" CanUserSort="False"/>
<DataGridCheckBoxColumn Width="Auto" Binding="{Binding Flagged}" CanUserSort="False">
<DataGridCheckBoxColumn.Header>
<TextBlock Text="M" ToolTip="Markiert - Auf Notizen achten!" />
</DataGridCheckBoxColumn.Header>
</DataGridCheckBoxColumn>
<DataGridCheckBoxColumn Width="Auto" Binding="{Binding Blocked}" CanUserSort="False">
<DataGridCheckBoxColumn.Header>
<TextBlock Text="B" ToolTip="Blockiert - Keine weitere Buchung annehmen!" />
</DataGridCheckBoxColumn.Header>
</DataGridCheckBoxColumn>
</DataGrid.Columns>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="OnColumnHeaderClicked"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Flagged}" Value="True">
<Setter Property="Background" Value="#F1F5E4"/>
</DataTrigger>
<DataTrigger Binding="{Binding Blocked}" Value="True">
<Setter Property="Background" Value="#DDD5C3"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
DataGridStyle
является:
<Style x:Key="DataGridStyle" TargetType="DataGrid">
<Setter Property="RowHeaderStyle" Value="{DynamicResource GridRowHeaderStyle}"/>
</Style>
<Style x:Key="GridRowHeaderStyle" TargetType="DataGridRowHeader">
<Setter Property="Width" Value="20"/>
<Style.Triggers>
<Trigger Property="IsRowSelected" Value="True">
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="5 0"/>
<Setter Property="Content" Value="●"/>
</Trigger>
</Style.Triggers>
</Style>
Ответ №1:
Вот шаблон сетки данных по умолчанию:
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Border" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" SnapsToDevicePixels="True"/>
<Polygon x:Name="Arrow" Fill="Black" HorizontalAlignment="Right" Margin="8,8,3,3" Opacity="0.15" Points="0,10 10,10 10,0" Stretch="Uniform" VerticalAlignment="Bottom"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Fill" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" TargetName="Arrow" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGrid}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderBrush" Value="#FF688CAF"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false" Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1" Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" Grid.ColumnSpan="2" Grid.Row="1"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="2" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Grid.Row="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</Style.Triggers>
</Style>
Кнопка в левом верхнем углу (над заголовками строк) определена в этой строке:
<Button Command="{x:Static DataGrid.SelectAllCommand}" Focusable="false"
Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
Соответственно, вы можете добавить обработку следующими способами:
- Поскольку эта кнопка получает стиль с помощью DynamicResource, вы можете переопределить или дополнить этот стиль, установив в нем необходимый обработчик.
- Вы можете задать привязку команд для команды SelectedAll.
Пример, демонстрирующий оба пути:
<DataGrid>
<UIElement.CommandBindings>
<CommandBinding Command="{x:Static DataGrid.SelectAllCommand}"
CanExecute="OnSelectAllCanExecute"
Executed="OnSelectAllExecute"/>
</UIElement.CommandBindings>
<FrameworkElement.Resources>
<Style x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}"
TargetType="{x:Type Button}"
BasedOn="{StaticResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}">
<EventSetter Event="Click" Handler="OnClickSelectAll"/>
</Style>
</FrameworkElement.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Mode=OneWay}" Header="Letter"/>
</DataGrid.Columns>
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<TextBlock Text="123456"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
<DataGrid.ItemsSource>
<sys:String>123456</sys:String>
</DataGrid.ItemsSource>
</DataGrid>
private void OnSelectAllCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void OnSelectAllExecute(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The "Select all" command was invoked.");
}
private void OnClickSelectAll(object sender, RoutedEventArgs e)
{
MessageBox.Show("Was clicked "Select all".");
}
Комментарии:
1. Прежде всего: спасибо за подробный ответ! Я попробовал ваш образец, но он не сработал для меня. Я добавил
<FrameworkElement.Resources>...</FrameworkElement.Resources>
часть вашего примера в свою сетку (с кодом обработчика щелчков, конечно).2. Прежде чем опубликовать код, я протестировал его на WPF Framework Win10. Никаких проблем быть не должно. Я не тестировал его на Core, но я не думаю, что в этой части что-то изменилось. Напишите, на какой платформе вы тестируете этот код.
3. Я использую .NET 5 для своего решения
4. Я тестировал на Net5. Как я и ожидал, все работает точно так же. Возможно, вы допустили какую-то ошибку при копировании. Возьмите архив с моим тестовым кодом отсюда: drive.google.com/file/d/1Vq2GRG6Yqv_AUWOmG5Gbx4sKGQ1JdoCL/…