Change Button Background when is not enabled - c#

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>

Related

Changing the style of a border inside data template for the listbox item based on the alterationindex [duplicate]

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>

Button default style not applied if Triggers added

I defined a default style for all my application Buttons in App.xaml :
<Style TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="Border"
CornerRadius="2"
BorderThickness="1"
Background="{StaticResource WindowBorderColor}"
BorderBrush="{StaticResource WindowBorderColor}">
<ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource InactiveBackgroundColor}"/>
<Setter Property="Foreground" Value="{StaticResource InactiveForegroundColor}"/>
<Setter Property="Opacity" Value="0.5"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource HeaderButtonOverColor}"/>
<Setter Property="Foreground" Value="{StaticResource HeaderForeHighlightColor}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource HeaderButtonPressedColor}"/>
<Setter Property="Foreground" Value="{StaticResource WindowForeColor}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But when I want to add a Trigger to my Button, the default style is not taken in account anymore :
<Button Content="{x:Static p:Resources.Delete}" Click="DeleteMacro_Click" Margin="3" >
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding MacroLeft.Name, Mode=OneWay}" Value="">
<Setter Property="Button.IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I found that link, so I added TargetType="{x:Type Button}" in my WPF, but nothing changed.
Why is the default style not taken in account, and how can I solve that, without creating another specific style in my app.xaml?
You can make the styles defined in app.xaml as base in the following way
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
</Style>
</Button.Style>

Using Validation.HasError to override Tooltip template

Everywhere I've looked, I've found the standard solution to attach a ToolTip to a control whose Binding has Validation.HasError == true but nowhere shows how you might completely override the ToolTip's template so that you could, for example, still have your own custom theme which overrides the style for all ToolTips but when a control has that specific condition you can specify a template which has a red border, red see-through background and red text, for example.
The standard solution is:
<Style x:Key="{x:Type FrameworkElement}" TargetType="FrameworkElement">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
Does anyone know how to expand this to set the ToolTip background, border and text colour without overriding the base ToolTip control style? Bear in mind I've already specified this to create my own "theme" so I don't want to change it if possible.
Yes, you can do it like this:
<Style x:Key="{x:Type FrameworkElement}" TargetType="FrameworkElement">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Content="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}" Style="{StaticResource MyInheritedStyleForValidation}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Where MyInheritedStyleForValidation should probably override your theme style.
Set the DataContext of the ToolTip to the parent control:
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Foreground="White"
Background="Black"
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
Content="{Binding Path=(Validation.Errors)[0].ErrorContent}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
This fix the tooltip content.
<Style x:Key="{x:Type FrameworkElement}" TargetType="FrameworkElement">
<Setter Property="ToolTip" Value="{Binding GeneralTooltip}"/>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationTemplate}"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Style="{StaticResource WarningTooltip}"/>
</Setter.Value>
</Setter>
<Setter Property="Tag" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Style>
The tooltip template from his style:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<!--Display the text-->
<Label Background="Transparent"
BorderThickness="0"
VerticalAlignment="Center"
Grid.Column="1"
Content="{Binding Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Control}, AncestorLevel=2}}"
BorderBrush="Transparent"/>
</ControlTemplate>
</Setter.Value>
</Setter>

Textblock style toggle!

I have a style which underlines the textblock when it is mouseovered... How ever i need when it is clicked to change its font weight to bold(selected)..
any idea?
Code example of what dnr3 said, a templated ToggleButton
<Style x:Key="BoldWhenClickedTextBlock" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<TextBlock x:Name="c_toggleButtonTextBlock" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type ToggleButton}}, Path=Content}"/>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="True">
<Setter TargetName="c_toggleButtonTextBlock" Property="TextDecorations" Value="Underline"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter TargetName="c_toggleButtonTextBlock" Property="FontWeight" Value="Bold" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then the "TextBlock" ToggleButton can use this with
<ToggleButton Style="{StaticResource BoldWhenClickedTextBlock}" Content="My Text.."/>

different images for enable and disable states of a button in WPF

I want to change the image of the button in the code below based on its state i.e. use different image for enable and disable state.
<Button CommandParameter="Open" >
<StackPanel Orientation="Horizontal" >
<Image Source="../icons/big/open.png" Width="20" Height="20"></Image>
</StackPanel>
</Button>
Thank you.
You can use a style with triggers like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Orientation="Horizontal" >
<Image Name="PART_Image" Source="path to normal image" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Source" Value="path to mouse over image" TargetName="PART_Image"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Source" Value="path to pressed image" TargetName="PART_Image"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source" Value="path to disabled image" TargetName="PART_Image"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I used the following code to make images inside buttons to have half the opacity when the button is disabled and it works great!
<Style TargetType="Button">
<Style.Resources>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
Try using Style.Triggers see post wpf-style-trigger
Basically, create a style for the button which makes it display an image object in its content property, and then have a trigger which checks the buttons enabled state, and when it is TRUE have it be one image, and at all other times be the other image.

Categories

Resources