I am trying to figure out the best way to create a style/trigger to set foreground to Red, when value is < 0. what is the best way to do this? I'm assuming DataTrigger, but how can I check for negative value, do i have to create my own IValueConverter?
If you are not using an MVVM model (where you may have a ForegroundColor property), then the easiest thing to do is to create a new IValueConverter, binding your background to your value.
In MyWindow.xaml:
<Window ...
xmlns:local="clr-namespace:MyLocalNamespace">
<Window.Resources>
<local:ValueToForegroundColorConverter x:Key="valueToForeground" />
<Window.Resources>
<TextBlock Text="{Binding MyValue}"
Foreground="{Binding MyValue, Converter={StaticResource valueToForeground}}" />
</Window>
ValueToForegroundColorConverter.cs
using System;
using System.Windows.Media;
using System.Windows.Data;
namespace MyLocalNamespace
{
class ValueToForegroundColorConverter: IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
SolidColorBrush brush = new SolidColorBrush(Colors.Black);
Double doubleValue = 0.0;
Double.TryParse(value.ToString(), out doubleValue);
if (doubleValue < 0)
brush = new SolidColorBrush(Colors.Red);
return brush;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}
You should have your view specific information in your ViewModel. But you can get rid of the Style specific information in the ViewModel.
Hence create a property in the ViewModel which would return a bool value
public bool IsMyValueNegative { get { return (MyValue < 0); } }
And use it in a DataTrigger so that you can eliminate the ValueConverter and its boxing/unboxing.
<TextBlock Text="{Binding MyValue}">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMyValueNegative}" Value="True">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
For Amsakanna's solution I had to add a class name to the Property Setter:
<Setter Property="TextBlock.Foreground" Value="Red" />
Related
I have a DataTemplate with a Path in a ResourceDictionary and I want to change the Fill color for the Path (would choose between two colors) depending on a bool property from the viewmodel.
<DataTemplate x:Key="FileIcon">
<Path Data="M20.8573547,8.0085467..." Fill="#F0F1F3" Width="30" Height="30"/>
</DataTemplate>
I presume, I need to use some converter but not sure how to write the XAML code for it. Something like this?
<Path Fill="{Binding MyBoolProperty, RelativeSource={RelativeSource FindAncestor, AncestorType=Path}, Converter={StaticResource BoolToColorConverter}}"/>
The Path isn't an ancestor of itself. If the viewmodel is the Path's DataContext, a conventional binding should suffice:
<Path
Fill="{Binding MyBoolProperty, Converter={StaticResource BoolToColorHiddenConverter}}"
/>
You could also skip the converter and use a Style trigger. Note that the default Fill is no longer set as an attribute in this version; if it is, then it'll override anything the Style does.
<Path
Data="M20.8573547,8.0085467..."
Width="30"
Height="30"
>
<Path.Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="#F0F1F3" />
<Style.Triggers>
<DataTrigger
Binding="{Binding MyBoolProperty}"
Value="True"
>
<Setter Property="Fill" Value="FluorescentBeige" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
If you want to use a converter, you can follow this example code for making one:
1. Make a new class
2. Use the following namespaces:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
3. Inherit and implement the IValueConverter Interface
4. In the Convert function, evaluate the value parameter and return the corresponding color you want
Example Code
class BoolToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value == true)
{
// return the color you want
}
else
{
// return the color you want
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
How to create a grid with a templated RowHeader, ColumnHeader, and Cells?
The ViewModel can have a list of objects for RowHeader item display, a list of objects for ColumnHeader item display. Basically think of it like a matrix display.
Probably a ControlTemplate needs to be written, but running out of ideas. There's not much of a documentation on this functionality.
Any Ideas?
You can create a style for a DataGridColumnHeader or a DataGridRowHeader and set the ContentTemplate to a DataTemplate which allows the Header property to be bound. For this you need an IValueConverter which enables the binding.
The headers are in the Controls.Primitives namespace:
xmlns:dp="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
Style:
<Style TargetType="dp:DataGridColumnHeader" >
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{Binding Converter={StaticResource vcBC}}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Converter:
public class BindingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType().Name == "Binding")
{
ContentControl cc = new ContentControl();
cc.SetBinding(ContentControl.ContentProperty, value as Binding);
return cc;
}
else return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Converter instance:
<yourassembly:BindingConverter x:Key="vcBC"/>
I have multibinding on Image control. I bind two properties one is type of bool(IsLogged) and one is typeof Uri (ProfilePhoto).
XAML:
<Image.Source >
<MultiBinding Converter="{StaticResource avatarConverter}">
<Binding Path="ProfilePhoto"></Binding>
<Binding Path="StatusInfo.IsLogged"></Binding>
</MultiBinding>
</Image.Source>
</Image>
I create converter, which convert BitmapImage to gray scale if property IsLogged is false.
It look like this:
public class AvatarConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var image = values[0] as BitmapImage;
string s = values[1].ToString();
bool isLogged = System.Convert.ToBoolean(s);
if (!isLogged)
{
try
{
if (image != null)
{
var grayBitmapSource = new FormatConvertedBitmap();
grayBitmapSource.BeginInit();
grayBitmapSource.Source = image;
grayBitmapSource.DestinationFormat = PixelFormats.Gray32Float;
grayBitmapSource.EndInit();
return grayBitmapSource;
}
return null;
}
catch (Exception ex)
{
throw ex;
}
}
return image;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
It works good if only I bind on image source property type fo BitmapImage, but I need bind property type of Uri.
I have a fear of the creation variable BitmapImage in converter and as source use Uri.
An return this variable as Source of image. I think this is not ideal way. Maybe I am wrong.
What is your opinion
Some elegant solution?
Although you can do it with a converter, there is a much better option: using a shader effect. You'll find an implementation of a GreyscaleEffect on this page.
<Style x:Key="grayedIfNotLogged" TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding StatusInfo.IsLogged}" Value="False">
<Setter Property="Effect">
<Setter.Value>
<fx:GrayscaleEffect />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
...
<Image Source="..." Style="{StaticResource grayedIfNotLogged}" />
I have a class having a Boolean member and I want to populate a Wpf ListBox with a collection of my class.
I want the background of the listboxitem to a different color if my boolean property is false. Is it possible with XAML ? What is the best way to do that ?
class Mi
{
public bool mybool{get;set;}
}
...
List<Mi> mycollection;// the datacontext
You could use a DataTrigger:
<DataTemplate DataType="{x:Type my:Mi}">
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter PropertyName="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding mybool}" Value="True">
<Setter PropertyName="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
<Grid.Style>
... your ListBoxItem contents here ...
</Grid>
</DataTemplate>
Here's a quick general converter for booleans that allows you to specify a value for true and something different for false for properties of any type.
[ValueConversion(typeof(bool), typeof(object))]
public class BooleanValueConverter : IValueConverter
{
public object FalseValue { get; set; }
public object TrueValue { get; set; }
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (bool)value ? this.TrueValue : this.FalseValue;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return object.Equals(this.TrueValue, value) ? true : false;
}
#endregion
}
Use it like so.
<SolidColorBrush x:Key="TrueBrush" Color="Green" />
<SolidColorBrush x:Key="FalseBrush" Color="Red" />
<local:BooleanValueConverter x:Key="BooleanBackground"
TrueValue="{StaticResource TrueBrush}"
FalseValue="{StaticResource FalseBrush}" />
...
Background="{Binding Path=Some.PropertyPath.Ending.With.A.Boolean,
Converter={StaticResource BooleanBackground}}" />
You could achieve this with a DataTemplateSelector, having two templates with differing backgrounds.
A better way would probably be to bind the the background property to your boolean and use an IValueConverter which would return an appropriate colour.
Background="{Binding Path=mybool, Converter={StaticResource boolToBackgroundConverter}}"
My point is this. For test i need when user check chk1 the chk2 element changed the property IsEnabled to False, but i can't do reference to chk2 element.
This is Style XAML.
<Style x:Key="styleCheckBox" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
</Style.Triggers>
</Style
Call to Style..
<StackPanel>
<CheckBox x:Name="chk1" Content="CheckBox1" Style="{StaticResource styleCheckBox}"/>
<CheckBox x:Name="chk2" Content="CheckBox2"/>
</StackPanel>
You cannot set TargetProperty in Style Trigger. This basically means that you should create a custom control derived from StackPanel which contains two checkboxes and these checkboxes are exposed as properties. Then you'll be able to define a style for that control (not the CheckBox) and set the properties you want.
Much easier way (if only needed for testing) would be this:
<StackPanel>
<StackPanel.Resources>
<local:InverseBoolConverter x:Key="InverseBoolConverter"/>
</StackPanel.Resources>
<CheckBox x:Name="chk1" Content="CheckBox1"/>
<CheckBox x:Name="chk2" Content="CheckBox2" IsEnabled="{Binding ElementName=chk1, Path=IsChecked, Converter={StaticResource InverseBoolConverter}}"/>
</StackPanel>
Where InverseBoolConverter is defined as follows:
[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBoolConverter: IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if(value is bool)
return !(bool)value;
else
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if(value is bool)
return !(bool)value;
else
return null;
}
}