DataGridTextColumn style with wrap and tooltip - c#

In my C# / WPF application, I have a Datagrid with several DataGridTextColumn column using both text wrapping and a tooltip.
I could write each column like this (and this works fine):
<DataGridTextColumn Header="Name" Binding="{Binding Name}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip" Value="Some tooltip text" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
But I would like to define a common style that can set both the wrapping and the tooltip text, knowing that the tooltip text will be different for each column. The purpose is to avoid code redundancy and make it clearer.
So far, here's my style:
<Window.Resources>
<Style x:Key="WrapStyle" TargetType="{x:Type DataGridCell}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}" TextWrapping="Wrap">
<TextBox.ToolTip>
<ToolTip>
<ToolTip.Content>
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tooltip}" />
</ToolTip.Content>
</ToolTip>
</TextBox.ToolTip>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Window.Resources>
And my column:
<DataGridTextColumn Header="Name" Binding="{Binding Name}" CellStyle="{StaticResource WrapStyle}" />
The problem is that I can't specify a tooltip to pass to the style. Is there a way to do it without writing 5 lines of DataGridTextColumn.CellStyle for each column?
Thanks

Modify the style to -
<Window.Resources>
<Style x:Key="WrapStyle" TargetType="DataGridCell">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}" TextWrapping="Wrap">
<TextBox.ToolTip>
<ToolTip>
<ToolTip.Content>
<TextBlock Text="{Binding Path=Tooltip}"></TextBlock>
</ToolTip.Content>
</ToolTip>
</TextBox.ToolTip>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Window.Resources>

Related

How can I change background behind border (ListView.ItemTemplete->datatemplete) when I hover or click?

My problem is when I click or hover in ListViewItem which also show the silver background:
enter image description here
this is my code xaml:
<ListView
Margin="0,30,0,0"
Height="600"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Name="ListViewFC" ItemsSource="{Binding ListWords, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<Border
Width="340"
x:Name="Border"
Height="80"
Background="Pink"
CornerRadius="15"
BorderThickness="1"
>
<Grid>
<TextBlock
VerticalAlignment="Center"
x:Name="txtContent"
Foreground="Black"
Text="{Binding Question1,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
TextWrapping="NoWrap"
Margin="30 0 0 0"
FontSize="15"
/>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListViewItem}}, Path=IsSelected}" Value="True">
<Setter TargetName="Border" Property="Background" Value="White" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want that When I hover or click It don't show the silver background.
pls, help me .Thanks.
Add this inside your ListView:
<ListView.Resources>
<Style BasedOn="{StaticResource TextBlockStyle}" TargetType="{x:Type TextBlock}" />
<Style BasedOn="{StaticResource ListViewItemStyle}" TargetType="{x:Type ListViewItem}" />
</ListView.Resources>
Then add this outside of your ListView (this displays a background of gold on hover):
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gold" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
The default ControlTemplate of the ListView contains a Border with Padding of 2X. Hence you have to change its template something like this
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>

Filtering a ComboBox with a GroupStyle

I have a Telerik ComboBox which has a GroupStyle applied to it. I want to have it so that when the items are filtered, the group items disappear if they have no children items, and it continues up the hierarchy.
So, this is the initial setup:
Current:
Desired:
For reference:
GroupItem Style
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Header="{Binding Path=Name}">
<ItemsPresenter Margin="20,0,0,0" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=Name}"
Value="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
RadComboBox
<telerik:RadComboBox
Grid.Column="1"
DisplayMemberPath="Name"
IsEditable="True"
IsFilteringEnabled="True"
ItemsSource="{Binding Path=Analyzers}"
KeyboardNavigation.TabNavigation="Local"
OpenDropDownOnFocus="True"
SelectedItem="{Binding Path=Analyzer, Mode=OneWayToSource}"
SelectedValue="{Binding Path=AnalyzerId, Converter={utilities:NullToZeroValueConverter}}"
SelectedValuePath="Id"
Style="{StaticResource ResourceKey=RadComboBoxStyle.CanDisable}"
TabIndex="2">
<telerik:RadComboBox.ItemContainerStyle>
<Style
BasedOn="{StaticResource ResourceKey=RadComboBoxItemStyle}"
TargetType="telerik:RadComboBoxItem">
<Setter Property="ToolTip" Value="{Binding Path=Description}" />
</Style>
</telerik:RadComboBox.ItemContainerStyle>
<telerik:RadComboBox.GroupStyle>
<GroupStyle />
</telerik:RadComboBox.GroupStyle>
</telerik:RadComboBox>
I found the following (related) example on the Telerik forums.
Example

How to implement special behavior for grid cells only for one column?

I have the next grid:
<DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock AutomationProperties.AutomationId="CustomerID1" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type l:Customer}">
<TextBlock Text="{Binding FirstName}"
AutomationProperties.AutomationId="FirstNameID" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock AutomationProperties.AutomationId="CustomerID2" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type l:Customer}">
<TextBlock Text="{Binding LastName}" AutomationProperties.AutomationId="LastNameID" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="Unselected"
Handler="UnselectedHandler" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
I have a specific column with specific styles for all cells in this column:
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock AutomationProperties.AutomationId="CustomerID1" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type l:Customer}">
<TextBlock Text="{Binding FirstName}"
AutomationProperties.AutomationId="FirstNameID" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Also I have the overall styles for all cells in the grid:
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="Unselected"
Handler="ExpressionUnselectedHandler" />
</Style>
</DataGrid.CellStyle>
But UnselectedHandler doesn't handle this event.
How can I use specific and default styles for all cells at the same time?
You are overriding the DataGrid.CellStyle with the DataGridTemplateColumn.CellStyle.
Move the style in the DataGrid.CellStyle to the DataGrid.Resources:
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="Unselected" Handler="UnselectedHandler" />
</Style>
</DataGrid.Resources>
But it still won't work because the DataGridTemplateColumn.CellStyle is still overriding it so you need to add to the style: BasedOn="{StaticResource {x:Type DataGridCell}}". This tells it to use the already defined style (in Grid.Resources) but add the following to it.
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
And of course, update the other template column's style too.

How to keep the functionality of Enabled = False, whilst keeping the styles of Enabled = True?

I have a DataGrid that looks like this:
Here's my current code:
<DataGrid x:Name="DataGrid" HorizontalAlignment="Center" VerticalAlignment="Center"
ColumnWidth="100" ColumnHeaderHeight="50" RowHeight="50" RowHeaderWidth="115" Padding="5"
BorderBrush="#FF646464" FontSize="18" FontFamily="Segoe UI"
CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="False" CanUserResizeRows="False"
Focusable="False" IsEnabled="False" IsReadOnly="True">
<DataGrid.Background>
<SolidColorBrush Color="#FFFFFFC8"/>
</DataGrid.Background>
<DataGrid.Columns>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellStyle}" Binding="{Binding In}" Header="In"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellStyle}" Binding="{Binding Out}" Header="Out"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellStyle}" Binding="{Binding Hours}" Header="Hours"/>
</DataGrid.Columns>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="#FFFFFFC8"/>
<Setter Property="BorderBrush" Value="DarkSlateGray"/>
<Setter Property="BorderThickness" Value="1, 2"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="5"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.RowBackground>
<SolidColorBrush Color="Transparent"/>
</DataGrid.RowBackground>
<DataGrid.RowHeaderStyle>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Background" Value="#FFFFFFC8"/>
<Setter Property="BorderBrush" Value="DarkSlateGray"/>
<Setter Property="BorderThickness" Value="2, 1"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Padding" Value="5"/>
</Style>
</DataGrid.RowHeaderStyle>
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}, Path=Item.Day}"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
I'd like to keep the DataGrid disabled, functionality-wise, but I'd like to keep the text black (rather than grey). How can I achieve this?
My DataGridCellStyle is within the <Window.Resources>:
<Style x:Key="DataGridCellStyle" TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
No need to mess with Styles, just set the DataGrid's IsHitTestVisible to False.
You can then also remove CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="False" CanUserResizeRows="False" Focusable="False":
<DataGrid x:Name="DataGrid" HorizontalAlignment="Center" VerticalAlignment="Center"
ColumnWidth="100" ColumnHeaderHeight="50" RowHeight="50" RowHeaderWidth="115" Padding="5"
BorderBrush="#FF646464" FontSize="18" FontFamily="Segoe UI"
IsHitTestVisible="False">
....
You could try to override the default disabled brushes in your datagrid by putting the color with the same key that the controls use on IsEnable=False in the resources.
<DataGrid.Resources>
<SolidColorBrush
x:Key="{x:Static SystemColors.GrayTextBrushKey}"
Color="{x:Static SystemColors.ControlTextColor}" />
</DataGrid.Resources>
P.S. I did not check the default cell template of the datagrid, I just assumed it uses GrayTextBrushKey, so check that first.

Use an image for a menu option in WPF

I use the following XAML to achieve a menu using radio buttons:
<Grid.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Foreground" Value="Gold" />
</DataTrigger>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Foreground" Value="Gold" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<StackPanel Margin="25,74,644,78" Background="{x:Null}">
<RadioButton Content="1. Do something." Click="RadioButton1_Click" FontSize="16" Margin="5"/>
<RadioButton Content="2. Do something else." Click="RadioButton2_Click" FontSize="16" Margin="5"/>
</StackPanel>
This works fine but I want to include an image as a menu option instead of text. (The image is for 'Home' and it will have a normal image and a hover over image)
Here is what I want to achieve:
How do I do this?
You can define another style for displaying Radio Button as an Image based on the existing style posted in question, just need slight changes in ControlTemplate's content part. Following is an example of such a Style and the usage :
<StackPanel Orientation="Horizontal" Background="Black">
<StackPanel.Resources>
<Style x:Key="PictSTyle" TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Image Width="50" Height="50">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="home_default.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type RadioButton}}}" Value="True">
<Setter Property="Source" Value="home_hovered.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<RadioButton Margin="5" Style="{StaticResource ResourceKey=PictSTyle}"/>
</StackPanel>
To give a menu item an image:
<MenuItem>
<MenuItem.Icon>
<Image Source=""/>
</MenuItem.Icon>
</MenuItem>
for your trigger just change the MenuItem's icon to the "highlighted one", when the user hovers over the menu item (IsMouseOver), by changing the Icon's image source.
Put an image element as the "Content" property for your radio button
<RadioButton Click=HomRadioButtonClick>
<RadioButton.Content>
<Image Source=""/>
</RadioButton.Content>
</RadioButton>
You'll need some extra logic for the hover behavior, but that should at least get the image in your menu.

Categories