Doesn't disable the button if the textbox invalid - c#

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;
}

Related

WPF Textbox style for default ContextMenu using custom MenuItem control template and style with image and text buttons will not close

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.

How bind validation to RadioButton WPF

I have some problem with Radiobutton binding to show validation.
I create two RadioButtons
<StackPanel Grid.Column="2" Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Top" Margin="0,13,0,0">
<RadioButton IsChecked="{Binding EndUser, Mode=TwoWay}" Content="End User" />
<RadioButton IsChecked="{Binding AppDeveloper, Mode=TwoWay}" Margin="15,0,0,0" Content="App Developer"/>
</StackPanel>
for my logic I should take 1 name from 2.
I write the logic
[Required]
public string Role
{
get => role;
set
{
Set(ref role, value);
RaisePropertyChanged("EndUser");
RaisePropertyChanged("AppDeveloper");
}
}
public bool EndUser
{
get => Role.Contains("EndUser");
set => Role = "EndUser";
}
public bool AppDeveloper
{
get => Role.Contains("AppDeveloper");
set => Role = "AppDeveloper";
}
the problem is how show [Required] in a form, and if i choose 1 of them, the validation will be true (validation work right if it's need i show the validation code)
I find this Validation Rule for Radio buttons wpf ,but this example doesn't work for me, broke all logic(doesn't send to me anything) and doesn't mark my field.
how write the
<Binding.ValidationRules>
<DataErrorValidationRule />
</Binding.ValidationRules>
for radiobutton fields like in TextBox and mark it red?
my button which disable if the fields is not valid
<Button x:Name="SignInButton" Command="{Binding SignInCommand}" Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Content="Sign In" >
<Button.Style>
<Style TargetType="{x:Type Button}">
<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="23" Margin="24,5,24,4"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=Password}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=Login}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=Role}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF280895"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
in MultiDataTrigger i write the rule, if Validation.HasError for the field the button is disable
You could for example put a Border around the RadioButtons and use a Style with a DataTrigger that binds to the Role property:
<Border Grid.Column="2" Grid.Row="1" BorderBrush="Red" Margin="0,13,0,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<RadioButton IsChecked="{Binding EndUser, Mode=TwoWay}" Content="End User" />
<RadioButton IsChecked="{Binding AppDeveloper, Mode=TwoWay}" Margin="15,0,0,0" Content="App Developer"/>
</StackPanel>
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding Role}" Value="{x:Null}">
<Setter Property="BorderThickness" Value="1" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
You should then make the setter of the Role private and make sure to raise the PropertyChanged event for the involved properties:
private string role;
[Required]
public string Role
{
get => role;
private set
{
role = value;
RaisePropertyChanged("Role");
}
}
public bool EndUser
{
get => Role == "EndUser";
set
{
Role = "EndUser";
RaisePropertyChanged("EndUser");
RaisePropertyChanged("AppDeveloper");
}
}
public bool AppDeveloper
{
get => Role == "AppDeveloper";
set
{
Role = "AppDeveloper";
RaisePropertyChanged("AppDeveloper");
RaisePropertyChanged("EndUser");
}
}

After change wpf button IsMouseOver trigger color not work

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

Converter not calling when using in IsMouseOver trigger

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.

Setting a border around an Expander button resizes it slightly

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.

Categories