Change true/false to a image - c#

i have a column in a datagrid that the content is True/false, how can i change this true/false(boolean) to a image, according to the text?
I'm using c# wpf.
Edit:
<dg:DataGridTemplateColumn MinWidth="70" Header=" Is Done2">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Name="imgIsDone" Source="../Resources/Activo.png"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsDone}" Value="False">
<Setter TargetName="imgIsDone" Property="Source" Value="../Resources/Inactivo.png"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>

public class BoolToImage : IValueConverter
{
public Image TrueImage { get; set; }
public Image FalseImage { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is bool))
{
return null;
}
bool b = (bool)value;
if (b)
{
return this.TrueImage;
}
else
{
return this.FalseImage;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then in your xaml, as a resource:
<local:BoolToImage TrueImage="{StaticResource Image}" FalseImage="{StaticResource FalseImage}" x:Key="BoolImageConverter"/>
Then in your binding:
ImageSource={Binding Path=BoolProp,Converter={StaticResource BoolImageConverter}}"

Use a DataGridTemplateColumn to supply a DataTemplate for the column that contains an Image, and use a value converter or a data trigger to set the image source based on the value of the column. Here is an example that uses a data trigger:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Name="MyImage" Source="TrueImage.png"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding BoolColumn}" Value="False">
<Setter TargetName="MyImage" Property="Source" Value="FalseImage.png"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

In case someone struggles getting the answer(from benPearce) running, i had to modify the converter to use ImageSource!
using System;
using System.Windows.Data;
using System.Windows.Media;
namespace ViewManager
{
public class BoolToImageConverter : IValueConverter
{
public ImageSource TrueImage { get; set; }
public ImageSource FalseImage { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is bool))
{
return null;
}
bool b = (bool)value;
if (b)
{
return this.TrueImage;
}
else
{
return this.FalseImage;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
usage with a resource
<local:BoolToImageConverter x:Key="BoolToImageConverter" FalseImage="{StaticResource UnLockedSource}" TrueImage="{StaticResource LockedSource}" />
...
<Button Grid.Column="2" Command="{Binding LockUnlockCommand}" >
<Image Source="{Binding IsLocked, Converter={StaticResource BoolToImageConverter}}" MinHeight="50" MinWidth="50" />
</Button>

Related

How to change the Width of a DataGridTemplateColumn without using a converter?

I have a DataGridTemplateColumn, whose Width I'd like to change based on the related boolean property.
Now I'm using a converter as shown in the code below in order to achieve my purpose.
<DataGridTemplateColumn Width="{Binding IsFull, Converter={StaticResource BooleanToColumnWidthConverter}}">
</DataGridTemplateColumn>
public class BooleanToColumnWidthConverter : IValueConverter
{
private static readonly DataGridLength NORMAL_WIDTH = new DataGridLength(10, DataGridLengthUnitType.Star);
private static readonly DataGridLength NARROWED_WIDTH = new DataGridLength(3, DataGridLengthUnitType.Star);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool)) { return DependencyProperty.UnsetValue; }
var isFull = (bool) value;
return isFull ? FULL_WIDTH : NARROWED_WIDTH;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
Is it possible to get the same result without using a converter, for example by defining something like a style or a template as shown in the following?
<!-- This does not compile. -->
<Style TargetType="DataGridTemplateColumn">
<Setter Property="Width" Value="10*"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsFull}" Value="False">
<Setter Property="Width" Value="3*"/>
</DataTrigger>
</Style.Triggers>
</Style>

WPF - Style bound to a property via ValueConverter not updating correctly

I have a Style converter defined as below:
public class StyleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is MyStatus && targetType == typeof(Style))
{
var status = (MyStatus)value;
switch (status)
{
case MyStatus.First:
return Application.Current.FindResource("firstStyle");
case MyStatus.Second:
return Application.Current.FindResource("secondStyle");
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
In App.xaml I've got some styles defined as below:
<Style x:Key="firstStyle" TargetType="Border">
<Setter Property="Background" Value="Yellow" />
</Style>
<Style x:Key="secondStyle" TargetType="Border">
<Setter Property="Background" Value="LightGreen" />
</Style>
And in Window.xaml:
<MyApp:StyleConverter x:Key="StyleConverter" />
<DataTemplate DataType="{x:Type MyApp:Item}">
<Border x:Name="ItemBorder"
Style="{Binding Path=Status, Mode=OneWay, Converter={StaticResource StyleConverter}}">
<!-- some content here -->
</Border>
</DataTemplate>
<ItemsControl x:Name="MyItems" />
Item:
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private MyStatus status;
public MyStatus Status {
get
{
return status;
}
set
{
status = value;
PropertyChanged(this, new PropertyChangedEventArgs("Status"));
}
}
}
I'm adding Item instances to ObservableCollection<Item> collection which is bound to MyItems (and MyStatus is a simple enum)
My problem is that the style is applied properly only for the first time and is not changing after I change the Status property of Item

DateTime need convert to string wpf

<DataGrid....
<DataGrid.Resources>
<DataTemplate DataType="{x:Type DateTime}">
<TextBlock Text="{Binding StringFormat={}{0:d}}" />
</DataTemplate>
</DataGrid.Resources>
...
<DataGridTemplateColumn Header="Время оплаты">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Center" Text="{Binding date_payment}" Width="Auto" Height="Auto" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
but this column have type DateTime...
i need convert this column on this type(string), because i need rename value row on this column, i use event LoadingRow so
DataRowView item = e.Row.Item as DataRowView;
DataRow row = item.Row;
var time = row[4];
if (Convert.ToString(time) == "01.01.0001 0:00:00")
{
row[4] = "No payment";
}
but its wrong, row no converting to string, please help
First of all, you have both a cell template and a data template. Pick one. Second, since you have a data template anyway there's no reason to create a converter, much less a code-behind event handler. You can keep all the relevant code and text strings (what if you need to localize?) nicely in one place with a trigger:
<DataTemplate TargetType="{x:Type DateTime}">
<TextBlock x:Name="text" Text="{Binding StringFormat={}{0:d}}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Static DateTime.MinValue}">
<Setter TargetName="text" Property="Text" Value="No payment"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
In case if it's Nullable value you could use
Binding="{Binding date_payment, TargetNullValue={}Дата отсутствует}"
In case if not, use IValueConverter where you will check for MinDate.
Here is an Example how to use converters, and converter for you
public class DateConverter:IValueConverter
{
private const string NoDate = "Дата отсутствует";
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is DateTime)
{
var date = (DateTime) value;
if(date==DateTime.MinValue)
return NoDate;
return date.ToString();
}
return NoDate;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You shoud use Converter for this:
public class MyConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value == DateTime.MinValue) {
return "No payment";
}
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
Than just add the converter to your binding.

WPF Trigger that would work if the value is equal or greater

I wrote an application in WPF that has a button and slider. I would like to create a trigger for the button, which would set the button's 'IsEnable' property to false when the slider value is greater than another value.
Right now I have:
<Style x:Key="zoomOutButton" TargetType="Button" BasedOn="{StaticResource ResourceKey=buttonStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentAltitude}" Value="24000">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
But I would like to set isEnable not when the value of CurrentAltitude equal 24000, but when it is equal or greater than 24000.
Any ideas?
You can achieve this using a converter:
public class IsEqualOrGreaterThanConverter : IValueConverter {
public static readonly IValueConverter Instance = new IsEqualOrGreaterThanConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
int intValue = (int) value;
int compareToValue = (int) parameter;
return intValue >= compareToValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
Then your trigger will look like this:
<Style x:Key="zoomOutButton" TargetType="Button" BasedOn="{StaticResource ResourceKey=buttonStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentAltitude, Converter={x:Static my:IsEqualOrGreaterThanConverter.Instance}, ConverterParameter=24000}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
A more generic converter, usable with any comparable type, could be :
public class IsGreaterOrEqualThanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
IComparable v = value as IComparable;
IComparable p = parameter as IComparable;
if (v == null || p == null)
throw new FormatException("to use this converter, value and parameter shall inherit from IComparable");
return (v.CompareTo(p) >= 0);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
But in this case, the ConverterParameter must be interpreted with the same type as the value transmitted to your Converter. For example, to compare an int property 'MyIntProperty' with the contant int value 1, in your XAML, you can use this syntax :
<UserControl x:Class="MyNamespace.MyControl"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:genconverters="clr-namespace:MyConverterNamespace;assembly=MyConvertersAssembly">
<Grid>
<Grid.Resources>
<genconverters:IsGreaterOrEqualThanConverter x:Key="IsEqualOrGreaterThanConverter"/>
<sys:Int32 x:Key="Int1">1</sys:Int32>
</Grid.Resources>
<ComboBox IsEnabled="{Binding MyIntProperty,
Converter={StaticResource IsEqualOrGreaterThanConverter},
ConverterParameter={StaticResource Int1}}"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"/>
</Grid>

Assign enum property in xaml using silverlight

I have a property of datattype enum : like
public BreakLevel Level
{
get { return level; }
set { level = value; }
}
And enum defined :
public enum BreakLevel
{
Warning, Fatal
}
I want bind the neum property to the visibility of my border , somewhat like this:
Visibility="{Binding BreakLevel.Fatal}"
so is it possible?
<Border CornerRadius="4" BorderThickness="1" BorderBrush="#DAE0E5"
Visibility="{Binding DataContext.IsError, Converter={StaticResource BoolToVisibilityConverter}, RelativeSource={RelativeSource TemplatedParent}}" >
Scott has a good answer to the actual question, however its always a good idea to ask yourself "How might I need code like this in the future? How can I avoid creating yet another class and instead re-use what I have already got?".
Here is a more general variation of Scott's solution:-
public class EnumToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (Enum.GetName(value.GetType(), value).Equals(parameter))
return Visibility.Visible;
else
return Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
Xaml:-
<TopLevelWindowOrControl.Resources>
<local:EnumToVisibilityConverter x:Key="EnumToVisibilityConverter" />
</TopLevelWindowOrControl.Resources>
<Border Visibility="{Binding Path=BreakLvlProperty, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter=Fatal" />
In this approach we can converter any enum to a Visibility value by using the ConverterParameter to specify the enum value (in string form) that constitute the "Visible" state.
Its tempting to take this further to allow more than one enum value to be equated to "Visible". However currently the code isn't much more complicated than Scott's more specific implementation. Hence this enhancement should be left until needed.
I think you can just create a BreakLevelToVisibilityConverter and bind just like the example you provided.
I'm assuming that the DataContext of your border is set to an instance of a class that has a property of type 'BreakLevel' (we'll call this property 'BreakLvlProperty').
The code below will then show the border if the value of BreakLvlProperty is BreakLevel.Fatal
Converter:
public class BreakLevelToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((BreakLevel)value == BreakLevel.Fatal)
return Visibility.Visible;
else
return Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
XAML:
<TopLevelWindowOrControl.Resources>
<local:BreakLevelToVisibilityConverter x:Key="BreakLevelToVisibilityConverter" />
</TopLevelWindowOrControl.Resources>
<Border Visibility="{Binding Path=BreakLvlProperty, Converter={StaticResource BreakLevelToVisibilityConverter}" />
public class EnumToVisibilityConvertor : IValueConverter
{
private bool chk;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((value != null) && (value is BreakLevel) && (targetType == typeof(Visibility)))
{
chk = ((((BreakLevel) value) == (BreakLevel) Enum.Parse(typeof (BreakLevel), parameter.ToString(), true)));
return (chk==true) ? Visibility.Visible : Visibility.Collapsed;
}
throw new InvalidOperationException("Invalid converter usage.");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
<Border CornerRadius="4" BorderThickness="1" BorderBrush="#DAE0E5"
Visibility="{Binding Path=Level, Converter={StaticResource enumToVisibilityConvertor},ConverterParameter=Fatal}" >
I know it's a bit old question but all of you focused on converters and there's much better (in my opinion) way of doing it without involving code-behind:
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<Grid>
<!-- Here is the border which will be shown if Object.Level has value Fatal -->
<Border x:Name="PART_Border"
Visibility="Collapsed"
BorderThickness="3" BorderBrush="Red"
CornerRadius="4">
</Border>
<TextBlock>Interiors of the border</TextBlock>
</Grid>
<ControlTemplate.Triggers>
<!-- This is the code which turns on border's visibility -->
<DataTrigger Binding="{Binding Level}" Value="{x:Static local:BreakLevel.Fatal}">
<Setter TargetName="PART_Border" Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
I assumed that in DataContext resists an object which has a property Level which is of your BreakLevel type.

Categories