One IValueConverter for all properties set in style - wpf

Is there a way to set a IValueConverter for a textbox when styling it?
The converter are used to hide zeros and showing placeholder values for empty values.
I would like to use the converter without knowing the name of the property of the bound object, so all bindings are using my converter, Can I do it?
<Style TargetType="{x:Type TextBox}">
<Setter Property="Height" Value="20"/>
<Setter Property="Margin" Value="0,0,0,6"/>
<Setter Property="Text">
<Setter.Value>
<Binding RelativeSource="{RelativeSource Self}" Converter="{textBoxTest:FormatIntAndDoubleValueConverter}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderThickness" Value="2"></Setter>
</Trigger>
</Style.Triggers>
</Style>

Related

How to set the trigger when the value does not equal to a specified value in WPF?

i would like to change the background of a ListBox to red if the SelectedIndex of ListBox greater than -1. but in xaml i only can use "=".
<ListBox.Style>
<Style TargetType="ListBox">
<Style.Triggers>
<Trigger Property="SelectedIndex" Value="-1">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
What i want is:
<ListBox.Style>
<Style TargetType="ListBox">
<Style.Triggers>
<Trigger Property="SelectedIndex" Value>"-1">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
Is it possible to do this in xaml?
Do it the other way round:
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Background" Value="Red"/>
<Style.Triggers>
<Trigger Property="SelectedIndex" Value="-1">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>

Datatrigger Change ImageBrush source

Currently am working on a reversi game and this is the ControlTemplate for a Stone on the board , Am using a DataTrigger to see who the Owner is for the Stone to set the button to the appropriate Image , But when I use TargetName on the setter (To the imagebrush wich is imga). I get an Error "Cannot find the Trigger target 'imga'. (The target must appear before any Setters, Triggers, or Conditions that use it.) "
but since I declared this brush before my setters this seems really strange to me. this code is in the app.xaml resources.
Thanks in advance
this is the relevant part of the button
<Style x:Key="0" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Height" Value="48"/>
<Setter Property="Width" Value="48" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Ellipse>
<Ellipse.Fill x:Uid="filler">
<ImageBrush x:Name="imga" ImageSource="afbeeldingen/vuur.jpg"/>
</Ellipse.Fill>
</Ellipse>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E59400" />
</Trigger>
<DataTrigger Binding="{Binding Owner.Value.ArrayIndex}" Value="0">
<DataTrigger.Setters>
<Setter TargetName="imga" Property="ImageSource" Value="afbeeldingen/vuur.jpg" />
</DataTrigger.Setters>
</DataTrigger>
imga is not a part of your Template, it is a resource, so you cannot change its properties from a trigger. What you have to do is change the Fill property from you Ellipse instead. You would have Something like this :
<ControlTemplate TargetType="{x:Type Button}">
<Ellipse x:Name="myEllipse">
<Ellipse.Fill x:Uid="filler">
<ImageBrush x:Name="imga" ImageSource="afbeeldingen/vuur.jpg"/>
</Ellipse.Fill>
</Ellipse>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E59400" />
</Trigger>
<DataTrigger Binding="{Binding Owner.Value.ArrayIndex}" Value="0">
<DataTrigger.Setters>
<Setter TargetName="myEllipse" Property="Fill">
<Setter.Value>
<ImageBrush x:Name="imga" ImageSource="afbeeldingen/vuur.jpg"/>
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>

WPF ListView & Converter

I have a ListView with a GridViewColumn that has an image in it, it uses a converter to convert a bool to a ImageSource. It was working perfectly for months and now it suddenly just shows a red dot instead of my image.
Converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((bool)value)
return new BitmapImage(new Uri(#"/Dionysus.Styling;component/Images/Actions-dialog-ok-apply-icon.png", UriKind.RelativeOrAbsolute));
else return
null;
}
Xaml:
<GridViewColumn Header="">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=IsDelayedOrPreferred, Converter={StaticResource DelayConverter}, Mode=TwoWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Result:
Has anyone seen this behaviour before or know what might have changed. The only recent changes that I made was upgrading to VS 2013 but all other ListViews with Converters
are still working as expected.
Style:
<Style TargetType="{x:Type ListView}">
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="AlternationCount" Value="2"/>
<Setter Property="Background" Value="WhiteSmoke"/>
<EventSetter Event="Loaded" Handler="ListView_Loaded"/>
</Style>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Margin" Value="1,0"/>
</Style>
<Style TargetType="{x:Type ListViewItem}" x:Key="ListViewStyle">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="WhiteSmoke"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="White"></Setter>
</Trigger>
<DataTrigger Binding="{Binding IsFirst}" Value="True">
<Setter Property="Background" Value="LightGreen"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding IsLastUnpaid}" Value="True">
<Setter Property="Background" Value="LightSalmon"></Setter>
</DataTrigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FF41B1E1"></Setter>
</Trigger>
</Style.Triggers>
<Setter Property="Height" Value="20" />
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
UPDATE:
I recently changed from a ListView to a DataGrid and then I see a little exclamation mark as if there is data validation errors on the DataGrid.
Any ideas?

DataTrigger not working on CheckBox

I have the following DataTrigger in a WPF form:
<CheckBox IsChecked="{Binding ConcentratorViewModel.Integrated}">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Margin" Value="0,10,0,0"/>
<Setter Property="Width" Value="20"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<!--<Setter Property="IsEnabled" Value="False"/>-->
<!--<Setter Property="IsChecked" Value="False"/>-->
<Style.Triggers>
<DataTrigger Binding="{Binding ConcentratorViewModel.Manufacturer}" Value="ZIV">
<Setter Property="Background" Value="Red"/>
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
<DataTrigger Binding="{Binding ConcentratorViewModel.Manufacturer}" Value="Landis+Gyr">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
The CheckBox must be Checked or Unchecked depending on the selected manufacturer. I added a converter to see the value on the trigger and it's correct. I've also added the Background property and it changes correctly, but the IsChecked doesn't work.
Well you need to move the IsChecked Binding inside the Style. Setting it directly on the Checkbox gives it precedence and the Trigger's cannot change that value.
So something like:
<CheckBox>
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Margin"
Value="0,10,0,0" />
<Setter Property="Width"
Value="20" />
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="IsChecked"
Value="{Binding ConcentratorViewModel.Integrated}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ConcentratorViewModel.Manufacturer}"
Value="ZIV">
<Setter Property="Background"
Value="Red" />
<Setter Property="IsChecked"
Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding ConcentratorViewModel.Manufacturer}"
Value="Landis+Gyr">
<Setter Property="IsChecked"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Note:
Remember by doing this, your Binding only applies when the DataTrigger's do not evaluate to "True". Thus if your Manufacturer property is "ZIV" or "Landis+Gyr" then your Integrated property is not going to see any CheckBox updates even with a TwoWay binding as it just isn't being used.

Defining a control template for a rectangle in XAML

In my current project, I have this XAML file where I define the visual style that must be applied to different types of custom widgets.
For example, the style for a 'DirectLineButton' (a custom class that inherits from WPF's Button) is as follows:
<Style x:Key="DirectLineButtonTemplate" TargetType="{x:Type View:DirectLineButton}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="MinHeight" Value="23"/>
<Setter Property="MinWidth" Value="75"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="MyBorder"
CornerRadius="2"
BorderThickness="2"
Background="Gold"
BorderBrush="Gray">
<ContentPresenter Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineAvailable">
<Setter TargetName="MyBorder" Property="Background" Value="Gold"/>
</Trigger>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineIdle">
<Setter TargetName="MyBorder" Property="Background" Value="Silver"/>
</Trigger>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineBusy">
<Setter TargetName="MyBorder" Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineCalled">
<Setter TargetName="MyBorder" Property="Background" Value="LightBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now, I need to replicate this idea by defining the style for a Rectangle. Unfortunately, WPF flags an error message when I try to define a ControlTemplate for a rectangle, can you suggest a workaround for this? See the code below of what I'm trying to attempt:
<Style x:Key="MyRectangleTemplate" TargetType="{x:Type Rectangle}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="MinHeight" Value="23"/>
<Setter Property="MinWidth" Value="75"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Rectangle}">
<Border x:Name="MyBorder"
CornerRadius="2"
BorderThickness="2"
Background="Gold"
BorderBrush="Gray">
<ContentPresenter Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineAvailable">
<Setter TargetName="MyBorder" Property="Background" Value="Gold"/>
</Trigger>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineIdle">
<Setter TargetName="MyBorder" Property="Background" Value="Silver"/>
</Trigger>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineBusy">
<Setter TargetName="MyBorder" Property="Background" Value="Green"/>
</Trigger>
<Trigger Property="View:DirectLineButton.State" Value="DirectLineCalled">
<Setter TargetName="MyBorder" Property="Background" Value="LightBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks in advance!
Hi you will have to do it with Border only.Controls that inherits FrameworkElement only can have Template . But Rectangle , Line etc are lighter versions they inherits only UIElement not FrameworkElement.I hope this will help. Conclusion: Rectange do not have Template property
You can't define a control template for a Rectangle, since it's not a control, but a Shape. You can only define a control template for classes derived from Control.
You should
1) use a Style (not a ControlTemplate) to have rounded borders.
2) Use a Trigger inside your style.
The following Xaml should get you closer from your goal :
<Style x:Key="MyRectangleStyle" TargetType="{x:Type Rectangle}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="MinHeight" Value="23"/>
<Setter Property="MinWidth" Value="75"/>
<Setter Property="Fill" Value="Blue"/>
<Setter Property="RadiusX" Value="2" />
<Setter Property="RadiusY" Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding DirectLineState}"
Value="{x:Static l:DLS.Available}">
<Setter Property="Fill" Value="Gold"/>
</DataTrigger>
<DataTrigger Binding="{Binding DirectLineState}"
Value="{x:Static l:DLS.Idle}" >
<Setter Property="Fill" Value="Silver"/>
</DataTrigger >
<DataTrigger Binding="{Binding DirectLineState}"
Value="{x:Static l:DLS.Available}">
<Setter Property="Fill" Value="Green"/>
</DataTrigger >
<DataTrigger Binding="{Binding DirectLineState}"
Value="{x:Static l:DLS.Called}">
<Setter Property="Fill" Value="LightBlue"/>
</DataTrigger >
</Style.Triggers>
</Style>
(notice that :
1) i changed the key for "MyRectangleStyle".
2) If you want this Style to be the default Style, do not give it a Key, but just a TargetType...
3) ...OR set the Key to "{x:Type Rectangle}". msdn seems to prefer that way.
btw : shouldn't you be using DataTriggers on public properties instead of Triggers ? but i don't know the whole architecture of your application. )
Rq : for the code above to work, you need :
1) a public proprety called DirectLineState raising NotifyPropertyChanged on change.
2) an enum called DLS defined in a separate file (like a class) in your project
3) you need "l" to be your project NameSpace.
<xmlns:l="clr-namespace:MyProjectNameSpace" >
4) Assign Style and set proper DataContext for the Rectangle

Resources