I want to make button background of which will become darker or lighter accroding to parameters. So i make this style:
<Style x:Key="ButtonFlatStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{StaticResource ButtonFlatForegroundBrush}" />
<Setter Property="FontSize" Value="{StaticResource CommonFontSize}" />
<Setter Property="FontFamily" Value="{StaticResource CommonFontFamily}" />
<Setter Property="Padding" Value="10,5,10,5" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border"
Margin="0"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background">
<Setter.Value>
<Binding Converter="{StaticResource BleachBrushConverter}"
Path="Background"
RelativeSource="{RelativeSource TemplatedParent}">
<Binding.ConverterParameter>
<system:Double>-0.5</system:Double>
</Binding.ConverterParameter>
</Binding>
</Setter.Value>
</Setter>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<Binding Converter="{StaticResource BleachBrushConverter}"
Path="Background"
RelativeSource="{RelativeSource TemplatedParent}">
<Binding.ConverterParameter>
<system:Double>0.5</system:Double>
</Binding.ConverterParameter>
</Binding>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I have converter:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var brush = (SolidColorBrush) value;
if (brush == null) return null;
var brightnessFactor = float.Parse(parameter.ToString());
var originalColour = brush.Color;
var bleachOrDarkness = brightnessFactor > 0 ? Color.FromRgb(255, 255, 255) : Color.FromRgb(0, 0, 0);
var adjustedColour = Lerp(originalColour, bleachOrDarkness, Math.Abs(brightnessFactor));
var newBrush = new SolidColorBrush(adjustedColour);
return newBrush;
}
When i click on button everything goes fine. But when mouse over event is firing button starts to blink and converter isn't calling. How to make it work?
And i use this style on button:
<Style x:Key="ButonFlatStyleGray"
BasedOn="{StaticResource ButtonFlatStyle}"
TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource ButtonGreyBackgroundBrush}" />
</Style>
add this
TargetName="Border"
to the IsMouseOver trigger and it works.
Second the first Trigger element is not closed.
Related
I know there are many posts dealing with this topic, but none that address my specific need. I want to define an override to the default style of the WPF Textbox ContextMenu. My application is global with user defined multi-language. That means all the literals in my app are really buttons and the user can enable a setting which allows a button click to display a dialog to enter the text for different languages. This works throughout my app including other ContextMenus. However, my solution for the Textbox context menu does everything right but will not close when the button is pressed. How can I get the buttons in the MenuItem style/template to close the Context Menu? Here is the style for the ContextMenu.
<Style x:Key="MyContextMenuStyle" TargetType="{x:Type ContextMenu}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Background" Value="{DynamicResource MyPopupBackgroundBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource MyBorderBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border x:Name="Border" Background="{TemplateBinding Background}" BorderThickness="1"
CornerRadius="6" BorderBrush="{TemplateBinding BorderBrush}">
<ScrollViewer x:Name="ScrollViewer" VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Hidden" Margin="4,4,4,4">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MyMenuItemStyle" TargetType="{x:Type ctls:MyMenuItem}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="StaysOpenOnClick" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="#FF494949"/>
<Setter Property="ButtonImageSource" Value="{StaticResource EditBlue}" />
<Setter Property="MaxImageSize" Value="20" />
<Setter Property="ButtonText" Value="Text" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ctls:MyMenuItem}">
<Grid Margin="0,2,0,0">
<ctls:MyBasicButton Style="{StaticResource MyImageAndTextButtonStyle}"
HorizontalAlignment="Left" FontSize="16"
ButtonName="{TemplateBinding ButtonName}"
CollectionKey="{TemplateBinding CollectionKey}"
Background="Transparent" BorderThickness="0"
Content="{TemplateBinding ButtonText}"
CanUseAlternateText="{TemplateBinding CanUseAlternateText}"
Image="{TemplateBinding ButtonImageSource}"
MaxImageSize="{TemplateBinding MaxImageSize}"
Command="{Binding Path=Command, RelativeSource={RelativeSource TemplatedParent}}">
</ctls:MyBasicButton>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is the resource for the ContextMenu template.
<system:String x:Key="CopyString">Copy</system:String>
<system:String x:Key="CutString">Cut</system:String>
<system:String x:Key="PasteString">Paste</system:String>
<ContextMenu x:Key="CutCopyPasteContextMenu" Style="{StaticResource MyContextMenuStyle}">
<ctls:MyMenuItem Style="{StaticResource MyMenuItemStyle}"
Command="ApplicationCommands.Cut" InputGestureText=""
StaysOpenOnClick="False"
ButtonImageSource="{StaticResource CutBlue}"
ButtonText="{Binding Source={StaticResource CutString}, Converter={StaticResource StringToMenuItemText}}">
</ctls:MyMenuItem>
<ctls:MyMenuItem Style="{StaticResource MyMenuItemStyle}"
Command="ApplicationCommands.Copy" InputGestureText=""
StaysOpenOnClick="False"
ButtonImageSource="{StaticResource CopyBlue}"
ButtonText="{Binding Source={StaticResource CopyString}, Converter={StaticResource StringToMenuItemText}}">
</ctls:MyMenuItem>
<ctls:MyMenuItem Style="{StaticResource MyMenuItemStyle}"
Command="ApplicationCommands.Paste" InputGestureText=""
StaysOpenOnClick="False"
ButtonImageSource="{StaticResource PasteBlue}"
ButtonText="{Binding Source={StaticResource PasteString}, Converter={StaticResource StringToMenuItemText}}">
</ctls:MyMenuItem>
</ContextMenu>
I have a custom MenuItem control with dependency properties that support binding between my custom Button control and the MenuItem. Here is that code.
public class MyMenuItem : MenuItem
{
public string ButtonName
{
get { return (string)base.GetValue(ButtonNameProperty); }
set { SetValue(ButtonNameProperty, value); }
}
public static readonly DependencyProperty ButtonNameProperty =
DependencyProperty.Register("ButtonName", typeof(string), typeof(MyMenuItem));
public string ButtonText
{
get { return (string)base.GetValue(ButtonTextProperty); }
set { SetValue(ButtonTextProperty, value); }
}
public static readonly DependencyProperty ButtonTextProperty =
DependencyProperty.Register("ButtonText", typeof(string), typeof(MyMenuItem));
public ImageSource ButtonImageSource
{
get { return GetValue(ButtonImageSourceProperty) as ImageSource; }
set { SetValue(ButtonImageSourceProperty, value); }
}
public static readonly DependencyProperty ButtonImageSourceProperty =
DependencyProperty.Register("ButtonImageSource", typeof(ImageSource), typeof(MyMenuItem));
public double MaxImageSize
{
get { return (double)base.GetValue(MaxImageSizeProperty); }
set { base.SetValue(MaxImageSizeProperty, value); }
}
public static readonly DependencyProperty MaxImageSizeProperty =
DependencyProperty.Register("MaxImageSize", typeof(double), typeof(MyMenuItem));
public string CollectionKey
{
get { return (string)base.GetValue(CollectionKeyProperty); }
set { base.SetValue(CollectionKeyProperty, value); }
}
public static readonly DependencyProperty CollectionKeyProperty =
DependencyProperty.Register("CollectionKey", typeof(string), typeof(MyMenuItem));
public bool CanUseAlternateText
{
get { return (bool)GetValue(CanUseAlternateTextProperty); }
set { SetValue(CanUseAlternateTextProperty, value); }
}
public static readonly DependencyProperty CanUseAlternateTextProperty =
DependencyProperty.Register("CanUseAlternateText", typeof(bool), typeof(MyMenuItem));
}
Finally, Here is the style for my Textbox using my custom ContextMenu named CutCopyPasteContextMenu.
<Style x:Key="MyTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Background" Value="{DynamicResource MyDataLabelBackgroundBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource MyTextBrush}"/>
<Setter Property="CaretBrush" Value="{DynamicResource MyTextBrush}"/>
<Setter Property="SelectionBrush" Value="{DynamicResource MySelectedBrush}"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontFamily" Value="{DynamicResource MyMainFont}" />
<Setter Property="Height" Value="28"/>
<Setter Property="Padding" Value="0,0,4,0"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource MyBorderBrush}"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="Continue"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="IsReadOnly" Value="False"/>
<Setter Property="ToolTipService.InitialShowDelay" Value="2000"/>
<Setter Property="ToolTipService.BetweenShowDelay" Value="0"/>
<Setter Property="ToolTipService.ShowDuration" Value="60000"/>
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
<Setter Property="ContextMenu" Value="{StaticResource CutCopyPasteContextMenu}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" CornerRadius="4"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false"
Margin="4,-1,0,0"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="{DynamicResource MyDisabledBackgroundBrush}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="true"/>
<Condition Property="IsReadOnly" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource MyBorderHighlightBrush}"/>
</MultiTrigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource MyBorderHighlightBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
Here is what the ContextMenu looks like when the app is run. All the menu item functions work correctly and I am allowed to define the dynamic language text for the menu item buttons as I designed.
Can someone please tell me why the ContextMenu will not close? I think it might have something to do with my Button control absorbing the click event of the MenuItem but I am just guessing.
I am trying to change the color of a checkmark of a checkbox in a WPF List View. I got the following XAML Code from another post. Unfortuantely I am not familar enough with the whole framework to understand where exacatly I need to add that in my ListView. Is anyone able to give me some hint. Many thanks in adavance.
<Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="ScrollViewer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Grid>
<Path x:Name="Equis" Opacity="0" Stroke="Red" Fill="Red" Stretch="UniformToFill" StrokeThickness="20" Data="M 30,100 L 80,140 L 160,60" Margin="0,0,2,2" />
<ContentPresenter Margin="4" HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="Equis" Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="Equis" Property="Opacity" Value="0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here the XAML of the checkbox in the GridViewColumn (works fine)
<GridViewColumn Header="HeaderName" Width="35">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="CheckBoxName" IsChecked="{Binding Object}" HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
You only need the ControlTemplate part of the Style that you show. You need to give it a key with x:Key="MyCheckBoxTemplate". Then you can apply it to the CheckBox in your own CellTemplate with Template="{StaticResource MyCheckBoxTemplate}".
A full worked example is below. In this I changed the sample ControlTemplate in your question because it draws a rather nasty big red splodge when the CheckBox is selected. I made it draw a much smaller checkmark in red:
XAML:
<Window x:Class="WpfApp11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp11"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ControlTemplate TargetType="CheckBox" x:Key="MyCheckBoxTemplate">
<StackPanel Orientation="Horizontal">
<Path x:Name="Equis"
Stroke="Red"
StrokeThickness="3"
Height="17" Width="19" Stretch="None"
Margin="0,0,2,2"
Opacity="1"
>
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="3,10">
<LineSegment Point="8,14" />
<LineSegment Point="16,6" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<ContentPresenter Margin="4" HorizontalAlignment="Left" VerticalAlignment="Top" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="Equis" Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="Equis" Property="Opacity" Value="0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<ListView Margin="5" ItemsSource="{Binding Products}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Checked" DisplayMemberBinding="{Binding IsChecked}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding ShortName}" />
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="HeaderName" Width="35">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="CheckBoxName" Template="{StaticResource MyCheckBoxTemplate}"
IsChecked="{Binding IsChecked}" HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Window>
C#:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace WpfApp11
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CreateProducts();
DataContext = this;
}
public ObservableCollection<Product> Products { get; set; }
private void CreateProducts()
{
Products = new ObservableCollection<Product>
{
new Product{ShortName="My First Product", ID = 1},
new Product{ShortName="My Second Product", ID = 2, IsChecked= true},
new Product{ShortName="My Third Product", ID = 3},
new Product{ShortName="My Fourth Product", ID = 4, IsChecked = true},
new Product{ShortName="My Fifth Product", ID = 5}
};
}
}
public class Product : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string shortName;
public string ShortName
{
get { return shortName; }
set
{
shortName = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(ShortName)));
}
}
private int id;
public int ID
{
get { return id; }
set
{
id = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(ID)));
}
}
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(IsChecked)));
}
}
}
}
You need to re-template the entire control. Take a look at this example:
<CheckBox x:Name="CheckBoxName" IsChecked="{Binding Object}" HorizontalAlignment="Center">
<CheckBox.Resources>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="OptionMark.Static.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="OptionMark.Static.Border" Color="#FF707070"/>
<Style x:Key="OptionMarkFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="14,0,0,0" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="OptionMark.MouseOver.Background" Color="#FFF3F9FF"/>
<SolidColorBrush x:Key="OptionMark.MouseOver.Border" Color="#FF5593FF"/>
<SolidColorBrush x:Key="OptionMark.MouseOver.Glyph" Color="Red"/>
<SolidColorBrush x:Key="OptionMark.Disabled.Background" Color="#FFE6E6E6"/>
<SolidColorBrush x:Key="OptionMark.Disabled.Border" Color="#FFBCBCBC"/>
<SolidColorBrush x:Key="OptionMark.Disabled.Glyph" Color="#FF707070"/>
<SolidColorBrush x:Key="OptionMark.Pressed.Background" Color="#FFD9ECFF"/>
<SolidColorBrush x:Key="OptionMark.Pressed.Border" Color="#FF3C77DD"/>
<SolidColorBrush x:Key="OptionMark.Pressed.Glyph" Color="Red"/>
<SolidColorBrush x:Key="OptionMark.Static.Glyph" Color="Red"/>
</CheckBox.Resources>
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource OptionMark.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource OptionMark.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="checkBoxBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid">
<Path x:Name="optionMark" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Fill="{StaticResource OptionMark.Static.Glyph}" Margin="1" Opacity="0" Stretch="None"/>
<Rectangle x:Name="indeterminateMark" Fill="{StaticResource OptionMark.Static.Glyph}" Margin="2" Opacity="0"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="true">
<Setter Property="FocusVisualStyle" Value="{StaticResource OptionMarkFocusVisual}"/>
<Setter Property="Padding" Value="4,-1,0,0"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.MouseOver.Border}"/>
<Setter Property="Fill" TargetName="optionMark" Value="{StaticResource OptionMark.MouseOver.Glyph}"/>
<Setter Property="Fill" TargetName="indeterminateMark" Value="{StaticResource OptionMark.MouseOver.Glyph}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Disabled.Border}"/>
<Setter Property="Fill" TargetName="optionMark" Value="{StaticResource OptionMark.Disabled.Glyph}"/>
<Setter Property="Fill" TargetName="indeterminateMark" Value="{StaticResource OptionMark.Disabled.Glyph}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="checkBoxBorder" Value="{StaticResource OptionMark.Pressed.Border}"/>
<Setter Property="Fill" TargetName="optionMark" Value="{StaticResource OptionMark.Pressed.Glyph}"/>
<Setter Property="Fill" TargetName="indeterminateMark" Value="{StaticResource OptionMark.Pressed.Glyph}"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Opacity" TargetName="optionMark" Value="1"/>
<Setter Property="Opacity" TargetName="indeterminateMark" Value="0"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="Opacity" TargetName="optionMark" Value="0"/>
<Setter Property="Opacity" TargetName="indeterminateMark" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
The colour of the checkmark is defined by the OptionMark.MouseOver.Glyph, OptionMark.Pressed.Glyph and OptionMark.Static.Glyph resources. You can the Color of these to whatever you want.
I have the email text block with validation
<TextBox x:Name="email" Style="{StaticResource emaliStyle}" Grid.Column="2" Grid.Row="2">
<TextBox.Text>
<Binding Mode="TwoWay" Path="Email" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<DataErrorValidationRule ValidatesOnTargetUpdated="False"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Style TargetType="TextBox" x:Key="emaliStyle">
<Setter Property="Width" Value="220"/>
<Setter Property="Height" Value="30"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Padding" Value="6,1,1,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="10"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter x:Name="LoginValidation" Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Bottom" Foreground="Maroon" FontSize="8pt"
Text="{Binding ElementName=email, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
</TextBlock>
<AdornedElementPlaceholder Name="email" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="DarkRed" />
<Setter Property="BorderThickness" Value="2" />
</Trigger>
</Style.Triggers>
</Style>
the validation work and show me the message which I write in viewModel( it doesn't matter)
next step it blocks the button if the field is invalid.
my button and style for it
<Button x:Name="SignInButton"
Style="{StaticResource SignInButton}"
Command="{Binding SignInCommand}"
CommandParameter="{Binding ElementName=This}"
Content="Sign In"/>
<Style TargetType="Button" x:Key="SignInButton">
<Setter Property="Background" Value="MidnightBlue"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" CornerRadius="10">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Height="20" Margin="26,10"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers >
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=email}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LimeGreen"/>
</Trigger>
</Style.Triggers>
</Style>
I write the Multitrigger(later add other textbox fields) to disable my button, but it isn't work.
I try write all with element name Email doesn't help. What i miss?
because the error message will show and the field border mark red, bu isn't disable
Your BlockButton() method should return false whenever you want to disable the Button that is bound to the SignInCommand. There is no reason to set the IsEnabled property in a style when you bind to a command.
For the status of the command and the Button to get refeshed, you should raise the CanExecuteChanged event for the command whenever the validation status changes. Most ICommand implementations include a RaiseCanExecuteChanged() method or similar that lets you do this:
private bool _isEmailValid;
private bool BlockButton()
{
return _isEmailValid && IsAppDeveloper == false && IsEndUser == false;
}
public string this[string columnName]
{
get
{
string error = String.Empty;
switch (columnName)
{
case "Email":
string s = ValidateModelProperty(Email, columnName);
_isEmailValid = string.IsNullOrEmpty(s);
SignInCommand.RaiseCanExecuteChanged();
return s;
}
return error;
}
}
private string ValidateModelProperty(object value, string propertyName)
{
ICollection<ValidationResult> validationResults = new List<ValidationResult>();
ValidationContext validationContext = new ValidationContext(this, null, null) { MemberName = propertyName };
if (!Validator.TryValidateProperty(value, validationContext, validationResults))
foreach (ValidationResult validationResult in validationResults)
return validationResult.ErrorMessage;
return null;
}
this is my button code
public class MetroButton : Button
{
public static readonly DependencyProperty MoseOverBrushProperty;
public static readonly DependencyProperty PressedBrushProperty;
public MetroButton():base()
{
var resource = new ResourceDictionary
{
Source = new Uri("/Parking.Component.Ui;component/Styles/ButtonMetro.xaml",
UriKind.RelativeOrAbsolute)
};
Style = resource["ButtonMetro"] as Style;
//SetResourceReference(StyleProperty, Style);
}
static MetroButton()
{
MoseOverBrushProperty = DependencyProperty.Register("MoseOverBrush", typeof(Brush), typeof(MetroButton));
PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(MetroButton));
}
public Brush MoseOverBrush
{
get { return (Brush)base.GetValue(MoseOverBrushProperty); }
set { base.SetValue(MoseOverBrushProperty, value); }
}
public Brush PressedBrush
{
get { return (Brush)base.GetValue(PressedBrushProperty); }
set { base.SetValue(PressedBrushProperty, value); }
}
}
and I use this style for my button
<Style x:Key="ButtonMetro" TargetType="{ x:Type LochalUI:MetroButton}">
<Setter Property="Foreground" Value="White" />
<Setter Property="MoseOverBrush" Value="#FF3F62FD"/>
<Setter Property="PressedBrush" Value="#FF000099"/>
<Setter Property="Background" Value="#FF6B9AFF"/>
<Setter Property="FontSize" Value="15" />
<Setter Property="FontFamily" Value="B Yekan" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type LochalUI:MetroButton}">
<Border x:Name="border" CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding Path=MoseOverBrush , RelativeSource={RelativeSource Self}}" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{Binding Path=PressedBrush , RelativeSource={RelativeSource Self}}" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
but the problem is there when i put color for my button background like below code:
<UI:MetroButton HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="132" Height="107" Background="#FF09CD00" >
<Grid>
<Label Content="تنظیمات" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="5,5,5,12" Foreground="White" Margin="5"/>
</Grid>
</UI:MetroButton>
the IsMouseOver changer color and IsPressed Triggers not work.
(I don't want use static resource in my setters)
Changing other properties has no effect just changing background made this problem.
I found the answer problem was in 2 place:
first one when we use trigger in
<ControlTemplate.Triggers/>
you have sure you set your setter set property on the currect object
and the secend one is in the binding we have change
Value="{Binding Path=MoseOverBrush , RelativeSource={RelativeSource Self}}"
to
Value="{Binding Path=MoseOverBrush , RelativeSource={RelativeSource TemplatedParent}}"
because MoseOverBrush is parrent property not the ControlTemplate property
I am making an Expander style, and I noticed that when the border around the Expander's ToggleButton goes from 0 to a non-zero value - "0,0,1,1", in this case - it is resized slightly, to shrink inside the border:
Not exactly app-breaking... But annoying that I can't fix it. How can I circumvent this? I need the Border in the ToggleButton's style to be 0 when the Expander is collapsed (since Expander has its own border that would make it look like a doubly-thick border) and non-zero when expanded (since I want the button to be separated by a border from the rest of the content).
ToggleButton style:
<Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="Bd" Background="{StaticResource MutedColorBrush}" BorderBrush="{StaticResource Expander.Border}" Padding="{TemplateBinding Padding}" CornerRadius="0" Height="22" Width="22">
<Grid Background="Transparent" SnapsToDevicePixels="False" Margin="0">
<ui:ColorableImage x:Name="img" Margin="0" Padding="2" Background="{StaticResource MutedColorBrush}" Color="Black" Height="{Binding Path=Height, RelativeSource={RelativeSource AncestorType={x:Type Border}}}" Width="{Binding Path=Width, RelativeSource={RelativeSource AncestorType={x:Type Border}}}" Source="Assets/Images/filter.png" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="false"/>
<ContentPresenter HorizontalAlignment="Center" Margin="12,0,12,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="BorderThickness" TargetName="Bd" Value="0,0,1,1" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{StaticResource MainColorBrush}"/>
<Setter Property="Background" TargetName="img" Value="{StaticResource MainColorBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Color" TargetName="img" Value="White"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Expander style:
<Style TargetType="{x:Type Expander}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="#F0F0F0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="BorderBrush" Value="{StaticResource Expander.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" SnapsToDevicePixels="true">
<DockPanel>
<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="0" MinWidth="0" MinHeight="0" Padding="0" Style="{StaticResource ExpanderDownHeaderStyle}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" VerticalAlignment="Top" Width="Auto" Height="Auto"/>
<ContentPresenter x:Name="ExpandSite" DockPanel.Dock="Bottom" Focusable="false" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5,0,5,10" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="true">
<Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
<Setter Property="Height" Value="Auto"/>
<Setter Property="Height" TargetName="ExpandSite" Value="Auto"/>
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
</Trigger>
<Trigger Property="ExpandDirection" Value="Up">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
</Trigger>
<Trigger Property="ExpandDirection" Value="Left">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Possibly related - the ColorableImage control:
ColorableImage.xaml (x:Name="This"):
<Grid>
<Image x:Name="originalImage" Visibility="Hidden" Stretch="{Binding ElementName=This, Path=Stretch}" Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualHeight}" Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}"/>
<Image x:Name="displayedImage" Visibility="Visible" Stretch="{Binding ElementName=This, Path=Stretch}" Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualHeight}" Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}" />
</Grid>
ColorableImage.xaml.cs:
public partial class ColorableImage : UserControl
{
// This is so that SourcePropertyChanged will not execute when ColorPropertyChanged does. ColorPropertyChanged changes Source,
// so SourcePropertyChanged is called in turn. This will change originalImage to the newly colored Source, which is incorrect.
// "Wrapping" the statement that changes the binding in ColorPropertyChanged with this boolean and making it a condition in
// SourcePropertyChanged makes SourcePropertyChanged executre only when Source is directly changed, whether through C# or XAML.
private static bool changedByColor = false;
public ColorableImage()
{
InitializeComponent();
}
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(ColorableImage), new FrameworkPropertyMetadata(ColorPropertyChanged));
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(ColorableImage), new FrameworkPropertyMetadata(SourcePropertyChanged));
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public static readonly DependencyProperty StretchProperty = DependencyProperty.Register("Stretch", typeof(Stretch), typeof(ColorableImage), new FrameworkPropertyMetadata(Stretch.Uniform));
public Stretch Stretch
{
get { return (Stretch)GetValue(StretchProperty); }
set
{
SetValue(StretchProperty, value);
this.originalImage.Stretch = value;
this.displayedImage.Stretch = value;
}
}
private static void ColorPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ColorableImage cimg = (ColorableImage)sender;
Binding binding = new Binding("Source")
{
ElementName = "originalImage",
Converter = new HighlightImageConverter(),
ConverterParameter = cimg.Color,
Mode = BindingMode.OneWay
};
changedByColor = true;
cimg.displayedImage.SetBinding(Image.SourceProperty, binding);
changedByColor = false;
}
private static void SourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (!changedByColor)
{
ColorableImage cimg = (ColorableImage)sender;
cimg.originalImage.Source = cimg.Source;
cimg.displayedImage.Source = cimg.Source;
// Note: #00000000 is the value for the "null color"
if (cimg.Color != null && !cimg.Color.ToString().Equals("#00000000"))
{
// Color the new image (this is necessary if the user sets the source after the color; the color would be lost, otherwise)
ColorPropertyChanged(sender, e);
}
}
}
}
You can probably avoid that problem by setting the BorderBrush to transparent, instead of setting the BorderThickness to 0.
You might possibly have to add an extra container...
I don't feel like testing this, since the question is old and #Sheridan wrote that he had trouble making it work.