I want a GridSplitter to be visible only when the user has the mouse over it. For that I'm setting a DataTrigger in its style. But I can't figure out what it's wrong because I don't get the desired behavior. It just stays the same.
<GridSplitter
ResizeDirection="Columns"
ResizeBehavior="BasedOnAlignment"
Grid.Column="1"
Grid.Row="0"
Grid.RowSpan="2"
Width="8"
Height="Auto"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
Background="AliceBlue"
Margin="-3 0 0 0">
<GridSplitter.Style>
<Style TargetType="{x:Type GridSplitter}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</GridSplitter.Style>
</GridSplitter>
Do you see something wrong? Does GridSplitter must be styled in a different way?
I figured it out, Triggers must be used instead of DataTriggers:
<GridSplitter.Style>
<Style TargetType="{x:Type GridSplitter}">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="AliceBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</GridSplitter.Style>
By the way, I think that if I set the Visibility to Hidden I can't target the GridSplitter, so I switch its Background instead.
Related
I have seen some articles that show how to use AlternationIndex with ListBoxes or ListViews, but I had spent a few hours trying to get alternating background colors on the base ItemsControl class and nothing seems to work. All ListBox samples I saw use ListBoxItem as the target type for the style that sets the background based onAlternationIndex - like this one from MSDN:
<Grid>
<Grid.Resources>
<Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="ListBox.AlternationIndex" Value="1">
<Setter Property="Background" Value="CornflowerBlue"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="ListBox.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Navy"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListBox AlternationCount="3" ItemsSource="{StaticResource data}"
ItemContainerStyle="{StaticResource alternatingWithTriggers}">
</ListBox>
</Grid>
I want to use the ItemsControl because I do not want the selection functionality and I think restyling a ListBox to hide it might not be the best choice.
This is one of the things I was trying:
<DataTemplate DataType="{x:Type vm:ObservableCollectionItem}">
<Grid>
<!-- some content here -->
</Grid>
</DataTemplate>
<!-- ... -->
<ItemsControl
ItemsSource="{Binding ObservableCollectionItems}"
AlternationCount="2"
>
<ItemsControl.ItemContainerStyle>
<Style>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Grid.Background" Value="Red"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Grid.Background" Value="Blue"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
The problem I saw was that the visual tree has a list of ContentPresenters that have ItemsControl.AlternationIndex alternate between 0 and 1, but the Grid in each ContentPresenter has ItemsControl.AlternationIndex set to 0.
There is probably something obvious I am missing...
The ItemContainerStyle is applied to the elements generated by the ItemsControl: ContentPresenter. The ContentPresenter will in turn contain whatever you put in your ItemTemplate. In the case of a ListBox, the ItemContainerStyle is applied to the generated ListBoxItem.
The AlternationCount is, based on what you posted, only available on these generated items. You cannot use the ItemContainerStyle to set the Grid's background, because the Grid is unknown to that Style.
The following would be ideal, but unfortunately ContentPresenter has no background property. It would work for a ListBox (with ListBoxItems) however.
<ItemsControl
ItemsSource="{Binding ObservableCollectionItems}"
AlternationCount="2">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="Red"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="Blue"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
So you end up writing a style for the grid which binds to the AlternationIndex of your parent ContentPresenter.
<DataTemplate DataType="{x:Type vm:ObservableCollectionItem}">
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="0">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}" Value="1">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
</DataTemplate>
hm... After about 2 hours of playing around, I finally found the solution that simply works:
<ItemsControl ItemsSource="{Binding}" AlternationCount="2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent" x:Name="__PART_GRID"></Grid>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter TargetName="__PART_GRID" Property="Background" Value="Red"/>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter TargetName="__PART_GRID" Property="Background" Value="Blue"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I hope this answer helps others to save some time.
Or, as I found on another post, and it works great for me...
You can simply use a binding...
{Binding
RelativeSource={RelativeSource Mode=TemplatedParent},
Path=(ItemsControl.AlternationIndex)}
NB: remember to add AlterationCount="100" on your ItemsControl
I don't know how any of the prior answers are legit. I couldn't make any of them work (didn't try Jacobi's though). Anyways, I found the path to enlightenment here: http://www.dotnetcurry.com/wpf/1211/wpf-items-control-advanced-topic, which lead me to adding the following in the xaml.cs code-behind:
public sealed class CustomItemsControl : ItemsControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new ContentControl();
}
}
and this in the xaml itself
<local:CustomItemsControl AlternationCount="2"
ItemsSource="{Binding Cells, Mode=OneWay}">
<local:CustomItemsControl.ItemContainerStyle>
<Style TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Background="{TemplateBinding Background}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="WhiteSmoke"/>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
</Style>
</local:CustomItemsControl.ItemContainerStyle>
</local:CustomItemsControl>
This was so damn hard to find a working solution to that I'm actually angry
If you don't want to use the DataTemplate approach, you can create a custom control that uses a ContentControl as the item container, therefore allowing you to specify a background color.
Class:
public class ItemsControlAlternating : ItemsControl
{
static ItemsControlAlternating()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ItemsControlAlternating),
new FrameworkPropertyMetadata(typeof(ItemsControlAlternating)));
}
protected override DependencyObject GetContainerForItemOverride()
{
return new ContentControl();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is ContentControl;
}
}
Resource Dictionary:
<Style TargetType="{x:Type c:ItemsControlAlternating}">
<Setter Property="AlternationCount" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:ItemsControlAlternating}">
<ItemsPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="Gray"/>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
I got this TextBlock:
<TextBlock Foreground="Red"/>
And there is an implicit style for TextBlock with style trigger that
asks "if the foreground is {StaticResource BrushTextBlockAlertForeground}
then set the background to black."
(BrushTextBlockAlertForeground is Red, of course).
<Trigger Property="Foreground" Value="{StaticResource BrushTextBlockAlertForeground}">
<Setter Property="Background" Value="Black"/>
</Trigger>
This trigger condition fails!
If static resource resolved on loading, so why this trigger fails?
Shouldn't the XAML loader put there Red in the trigger condition? or it puts some expression instead?
Is there any chance that happening because the "Value" property of trigger condition isn't dependency property?
Only when I write
<Trigger Property="Foreground" Value="Red">
<Setter Property="Background" Value="Black"/>
</Trigger>
It works.
If I put static resource from outside (look below), it doesn't work in any case. Like that:
<TextBlock Foreground="{StaticResource BrushTextBlockAlertForeground}"/>
I would love to know the reason behind, because I want to write reusable color, instead of putting "red" in many places. "Tomorrow" someone will try to make that reusable and will encounter the behavior I experiencing.
Ensure, TextBlocks you test and StyleTrigger use both(!) the same brush Red or from StaticResource. TextBlock with foreground Red and StyleTrigger with StaticResource and vice versa will not work, because the values Brushes.Red and from StaticResource aren't equal. See A: How to Compare SolidColorBrushes?
<StackPanel>
<!--this doesn't work-->
<StackPanel.Resources>
<SolidColorBrush x:Key="forebr" Color="Red"/>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Foreground" Value="{StaticResource forebr}">
<Setter Property="Background" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Foreground="Red" Text=" Test trigger 0"></TextBlock>
</StackPanel>
<StackPanel>
<!--this doesn't work-->
<StackPanel.Resources>
<SolidColorBrush x:Key="forebr" Color="Red"/>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Foreground" Value="Red">
<Setter Property="Background" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Foreground="{StaticResource forebr}" Text=" Test trigger 1"></TextBlock>
</StackPanel>
<StackPanel>
<!--this works-->
<StackPanel.Resources>
<SolidColorBrush x:Key="forebr" Color="Red"/>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Foreground" Value="{StaticResource forebr}">
<Setter Property="Background" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Foreground="{StaticResource forebr}" Text=" Test trigger 2"></TextBlock>
</StackPanel>
<StackPanel>
<!--this works-->
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Foreground" Value="Red">
<Setter Property="Background" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Foreground="Red" Text=" Test trigger 3"></TextBlock>
</StackPanel>
I'm working on a WPF application. I have a button, which contains a Grid with a TextBlock and a Path element, as following:
<Button x:Name="btn" Margin="1">
<Button.Content>
<Grid Style="{DynamicResource button_special_hover}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="15*" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="tx" TextWrapping="Wrap" Text="{DynamicResource MenuString}" Grid.Column="2" />
<Path x:Name="path" Stretch="Fill" Fill="{DynamicResource MarkerBrush}" Data="M 65.3334,41.3334C 65.3334,45.0133 62.3467,48 58.6667" Grid.Column="0" />
</Grid>
</Button.Content>
What I want to achieve is that once I hover the grid inside the button with my mouse, I want the foreground of the text inside the textblock to turn into white and the fill color for the path element to turn into white too.
What I've tried to do is declare a style for the grid as following: (button_special_hover)
<Style x:Key="button_special_hover" TargetType="{x:Type Grid}">
<Setter Property="Background" Value="Transparent"/>
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Path}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Fill" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
I don't get what I want. Once I hover over the grid, nothing happens. Only when I hover the Textblock inside the grid, the text turns into White. Once I hover the Path, nothing happens.
How can I achieve that once I hover the grid both the textblock foreground and the Path Fill turn into White? Thanks!
Your problem is that you specified the fill on the path element.
NOTE: I 'fixed' the Data by added ",41.3334" to it.
<Path x:Name="path" Stretch="Fill" Fill="{DynamicResource MarkerBrush}" Data="M 65.3334,41.3334C 65.3334,45.0133 62.3467,48 58.6667,41.3334" Grid.Column="0" />
When you do that, you can't override it. If you specified it in the style instead then you'd get the results you want.
Remove Fill from Path:
<Path x:Name="path" Stretch="Fill" Data="M 65.3334,41.3334C 65.3334,45.0133 62.3467,48 58.6667,41.3334" Grid.Column="0" />
and add Fill to the style:
<Style x:Key="button_special_hover" TargetType="{x:Type Grid}">
<Setter Property="Background" Value="Transparent"/>
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Path}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Fill" Value="White"/>
</DataTrigger>
</Style.Triggers>
<!-- "All I did was add this line below" -->
<Setter Property="Fill" Value="{DynamicResource MarkerBrush}"/>
</Style>
</Style.Resources>
</Style>
I have the following Column in my datagrid :
<DataGridTemplateColumn CanUserReorder="False" CanUserResize="True" Header="">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate />
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource DatagridCellHyperlinkStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Padding="{TemplateBinding Padding}" VerticalAlignment="Center">
<TextBlock Width="Auto" Height="Auto" TextTrimming="CharacterEllipsis">
<Hyperlink>
<InlineUIContainer TextDecorations="{Binding Path=TextDecorations, RelativeSource={RelativeSource AncestorType=TextBlock}}" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=TextBlock}}">
<ContentPresenter Width="Auto" Height="Auto" Content="{Binding DataContext.Value, RelativeSource={RelativeSource AncestorType=DataGridRow}}"/>
</InlineUIContainer>
<Hyperlink.Style>
<Style TargetType="Hyperlink" BasedOn="{StaticResource HyperlinkStyle}">
<EventSetter Event="Hyperlink.Click" Handler="Click" />
</Style>
</Hyperlink.Style>
</Hyperlink>
</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
The hyperlink works perfectly (with my style also) but the text trimming doesn't work. How can I change my code to make it work ?
The 2 styles attached :
<Style x:Key="DatagridCellHyperlinkStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="5" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="FontSize" Value="14" />
<Setter Property="FontFamily" Value="Helvetica" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Foreground" Value="{StaticResource CouleurBouton}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource ResourceKey=CouleurBouton}"/>
<Setter Property="Foreground" Value="{StaticResource ResourceKey=CouleurFond}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource ResourceKey=CouleurBouton}"/>
<Setter Property="Foreground" Value="{StaticResource ResourceKey=CouleurFond}" />
</Trigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" Value="True">
<Setter Property="Background" Value="{StaticResource ResourceKey=CouleurBoutonHover}"/>
<Setter Property="Foreground" Value="{StaticResource ResourceKey=CouleurTexteBoutonHover}" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="HyperlinkStyle" TargetType="{x:Type Hyperlink}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{DynamicResource CouleurBoutonPressed}" />
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="{DynamicResource CouleurBouton}" />
<Setter Property="TextBlock.TextDecorations" Value="{x:Null}" />
</Style>
Thank you !
You have nothing that will restrict the TextBlock.Width, so the text in it will never wrap, or be trimmed. To fix this problem, you just need to set some kind of Width restriction on it... you could try something like this:
<ControlTemplate>
<Border Padding="{TemplateBinding Padding}" VerticalAlignment="Center">
<TextBlock MaxWidth="250" TextTrimming="CharacterEllipsis">
...
Well, for WPF engine to understand that the trimming is needed it should see that the control cannot be put into the space available. If the control can be resized(AutoSize) it will just increase its dimensions without any trimming.
From MSDN:
Gets or sets the text trimming behavior to employ when content
overflows the content area.
And I can't see anything in your template that suggests that the space limit will be encountered.
So try to set width limit, either on Column, or on the TextBlock. Or restrict the resize in some other way.
<TextBlock Width="Auto" Height="Auto"
MaxWidth="100"
MinWidth="30"
TextTrimming="CharacterEllipsis">
I need to change my Button background (as SolidColorBrush for example) only when it is not enabled (IsEnabled == false). How can I do?
Have I to modify the Button Style using the XAML or can I do this work programmatically? What is the correct XAML code, to change only the Background when it is not enabled?
I tried the following XAML code but it has no effect:
<Button>
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Red"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
You can change the background by editing the template. You'll find the default template for Button here.
In the trigger for IsEnabled you can simply add something like this:
<Setter Property="Background" Value="{StaticResource DisabledBackgroundBrush}"/>
EDIT:
Try this instead then;
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Overlay" CornerRadius="2">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Overlay" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<Button Content="Button" IsEnabled="False"/>
</StackPanel>
Just change it to suit your needs.
You can use a Style trigger:
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Image.Source" Value="pack://application:,,,/disabled.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>