I would like to create WPF converter that converts double number to "+" or "-" String based on the number Sign(positive or negative)
but I can't handle the converted back method because I don't have the number anymore.
The "+" and "-" signs bounded to a combobox at the xaml side
any ideas???
public class AmountToDebitCreditConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((value == null) || (System.Convert.ToDecimal(value) == 0))
return string.Empty;
return System.Convert.ToDecimal(value) > 0 ? "+" : "-";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
KeyValue kv = value as KeyValue;
if ((String)value == "+")
return 1;
else
return -1;
}
}
Here's my Xaml code
<igDP:UnboundField Name="ActualAdjustmentAmount" Label="PlusMinusKey" Converter={StaticResource signConverter} >
<igDP:Field.Settings>
<igDP:FieldSettings EditorType="{x:Type igEditors:XamComboEditor}" LabelWidth="40" CellWidth="40">
<igDP:FieldSettings.EditorStyle>
<Style TargetType="{x:Type igEditors:XamComboEditor}">
<Setter Property="ItemsSource" Value="{Binding Path=Flags, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
<Setter Property="FlowDirection" Value="LeftToRight"/>
<Setter Property="SelectedItem" Value="{Binding Path=ActualAdjustmentAmount }" />
</Style>
</igDP:FieldSettings.EditorStyle>
</igDP:FieldSettings>
</igDP:Field.Settings>
</igDP:UnboundField>
If the idea is not just to be able to use (and exploit) Converters, then I would rather suggest you to have a specific Sign property in your ViewModel and bind your view showing sign with that property.
It is probably best to do this sort of conversion in a view-model whenever possible.
Nonetheless, you've pinpointed the problem -- you no longer have the number after your conversion. The fact is that you don't need to return a string from your converter -- you can return any object that will return the desired string from its ToString() override, and that object can contain any other data and behaviour that you want.
Here is a converter that should accomplish what you're after, though I haven't actually tested this:
public class SignedDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new DisplaySignedDouble(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var d = value as DisplaySignedDouble;
return (d == null || !d.Value.HasValue)
? 0d
: d.Value.Value;
}
private class DisplaySignedDouble
{
public DisplaySignedDouble(object value)
{
Value = value is double ? (double) value : (double?) null;
}
public double? Value { get; private set; }
public override string ToString()
{
if (!Value.HasValue || Value.Value == 0d)
{
return string.Empty;
}
return Value.Value > 0 ? "+" : "-";
}
}
}
Related
I have a enum to string converter
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
MailSettingsStateEnum enumValue = (MailSettingsStateEnum)value;
// extension method on the enum, to return a string based on enum.
return enumValue.Description();
}
// ConvertBack not relevant here.
}
I am using this in wpf xaml easily as follows to set the Content property of a label.
<Label Content="{Binding MailSettingState, Converter={StaticResource
EnumConverterString}}"
BorderBrush="{Binding MailSettingState, Converter={StaticResource
EnumConverterBorderBrush}}" />
Now as you can see, I have another property BorderBrush. I also have to set this based on the same enum. And so I had to write another converter EnumConverterBorderBrush
So is there a way by which I have only one converter, and it return an object which has two properties and i can use these properties in the xaml? I can create the converter, its easy, but I dont know how to use it in xaml. Say the converter returned an object and has tow property called MessageString(of type string), and another BorderBrush of the type Brush, how do I use it the xaml?
You can switch the output based on the targetType you receive in your converter.
So you could do something like this:
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
var enumValue = (MailSettingsStateEnum)value;
switch(targetType)
{
case typeof(string)
return enumValue.Description();
case typeof(Brush)
return enumValue.GetBrush();
default:
throw new NotSupportedException("Type not supported")
}
}
// ConvertBack not relevant here.
}
Now you'll have one converter to rule them all!
converter should return object which match requested targetType. converter can return different values for input enum value depending on parameter. I think it is more flexible than relying on targetType only.
public class SpecEnumConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Enum)
{
if ((string) parameter == "brush")
return "Red"; // return brush here!
// if not pre-defined parameter (null or any other), return description
return (int) value; // return enum description here!
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
usage:
<Label Content="{Binding MailSettingState, Converter={StaticResource
EnumConverterSpec}}"
BorderBrush="{Binding MailSettingState, Converter={StaticResource
EnumConverterSpec}, ConverterParameter='brush'}" />
I already commented above, but here's the solution.
<Label DataContext="{Binding MailSettingState, Converter={converters:EnumConverter}}" Content="{Binding Label}" BorderBrush="{Binding BorderBrush}"/>
public class EnumConverter: MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var enumValue = (MailSettingsStateEnum) value;
return new ConvertedEnum { Label = enumValue.Description(),
BorderBrush = new BorderBrush()};
}
// ConvertBack not relevant here.
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
public class ConvertedEnum
{
public string Label {get; set;}
public BorderBrush {get; set;}
}
Separate converters still look prettier to me.
I want when visibility of "StckPnl1" is set to Collapsed, my property "IsBusyIndicatorShowing" of "BusyDeco1" is being set to true.
What's the simplest solution?
<ctrls:BusyDecorator x:Name="BusyDeco1" IsBusyIndicatorShowing="??" Style="{DynamicResource BusyDecorator1}"/>
<StackPanel x:Name="StckPnl1" Visibility="Collapsed">
Use a DataTrigger:
<ctrls:BusyDecorator>
<ctrls:BusyDecorator.Style>
<Style TargetType="{x:Type ctrls:BusyDecorator}" BasedOn="{DynamicResource BusyDecorator1}">
<Setter Property="IsBusyIndicatorShowing" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=StckPnl1, Path=Visibility}" Value="Collapsed">
<Setter Property="IsBusyIndicatorShowing" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</ctrls:BusyDecorator.Style>
</ctrls:BusyDecorator>
i use a converter for this stuff.
<ctrls:BusyDecorator x:Name="BusyDeco1"
IsBusyIndicatorShowing="{Binding ElementName=StckPnl1, Path=Visibility, Converter={StaticResource TrueIfNotVisibleConverter}}" Style="{DynamicResource BusyDecorator1}"/>
<StackPanel x:Name="StckPnl1" Visibility="Collapsed">
<Converter:BoolToVisibilityConverter x:Key="TrueIfVisibleConverter" Inverted="False" Not="False" />
<Converter:BoolToVisibilityConverter x:Key="TrueIfNotVisibleConverter" Inverted="False" Not="True" />
<Converter:BoolToVisibilityConverter x:Key="VisibleIfTrueConverter" Inverted="True" Not="False" />
<Converter:BoolToVisibilityConverter x:Key="VisibleIfNotTrueConverter" Inverted="True" Not="True" />
public class BoolToVisibilityConverter : IValueConverter
{
private bool inverted = false;
private bool not = false;
public bool Inverted
{
get { return inverted; }
set { inverted = value; }
}
public bool Not
{
get { return not; }
set { not = value; }
}
private object VisibilityToBool(object value)
{
if (!(value is Visibility))
return DependencyProperty.UnsetValue;
return (((Visibility)value) == Visibility.Visible) ^ Not;
}
private object BoolToVisibility(object value, object parameter)
{
if (!(value is bool))
return DependencyProperty.UnsetValue;
var hiddenodercollapsed = Visibility.Collapsed;
if (parameter != null && parameter.ToString().ToLower().Contains("hidden"))
hiddenodercollapsed = Visibility.Hidden;
return ((bool)value ^ Not) ? Visibility.Visible : hiddenodercollapsed;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Inverted ? BoolToVisibility(value, parameter) : VisibilityToBool(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Inverted ? VisibilityToBool(value) : BoolToVisibility(value, parameter);
}
}
I am trying to set a style, which is defined in the App.xaml, dynamically when loading a user control and it's just not applying the style for some reason (i.e. there is no error occurring, it's just not applying the style).
I'm sure it's because I've defined the binding wrong, but I'm unable to figure out what I need to do differently to get it to work.
App.xaml Style
The style I'm after is the RunningTitleBlock and it's comprised of a couple other styles that I've included in the below code sample.
<Style TargetType="Label">
<Setter Property="Margin" Value="4"/>
</Style>
<Style TargetType="Label"
BasedOn="{StaticResource {x:Type Label}}"
x:Key="HeaderBlock">
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style TargetType="Label"
BasedOn="{StaticResource ResourceKey=HeaderBlock}"
x:Key="TitleBlock">
<Setter Property="Foreground" Value="Black"/>
</Style>
<Style TargetType="Label"
BasedOn="{StaticResource ResourceKey=TitleBlock}"
x:Key="RunningTitleBlock">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0.0, 0.5"
EndPoint="1.0, 0.5">
<GradientStop Color="White" Offset="0.0"/>
<GradientStop Color="Green" Offset="1.0"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
Binding on the user control
I'm trying to get the Binding to bind to a value returned from a value converter.
Style="{DynamicResource ResourceKey={Binding Path=MonitoringType, Converter={StaticResource TSConverter}}}"
Code
MonitoringTypes Enum
public enum MonitoringTypes
{
Running,
Failed,
Paused,
Favorites,
}
User Control
Here what I'm trying to do is concatenate the string value of the MonitoringTypes enum value that's passed in with some well known text to build a style name that exists in the App.xaml. The value converter is being called and returning the correct value, but for some reason the style isn't applying.
/// <summary>
/// Interaction logic for MonitorWorkflow.xaml
/// </summary>
public partial class MonitorWorkflow : UserControl
{
public MonitorWorkflow(MonitoringTypes monitoringType)
{
InitializeComponent();
this.DataContext = new MonitorWorkflowViewModel { MonitoringType = monitoringType };
}
}
public class MonitorWorkflowViewModel
{
public MonitoringTypes MonitoringType { get; set; }
}
public class TitleStyleValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var type = (MonitoringTypes)value;
return string.Format("{0}TitleBlock", Enum.GetName(typeof(MonitoringTypes), type));
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Enum.Parse(typeof(MonitoringTypes), value.ToString().Substring(0, value.ToString().IndexOf("TitleBlock")));
}
}
My suggestion would be to skip the DynamicResource statement and using the Converter provide the Style directly.
Style="{Binding Path=MonitoringType, Converter={StaticResource TSConverter}}"
In TSConverter, you can return a Style rather than a string. Kind of like this:
public class TitleStyleValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
var type = (MonitoringTypes)value;
var styleToReturn = FindResource(
string.Format("{0}TitleBlock",
Enum.GetName(typeof(MonitoringTypes), type)));
if (styleToReturn != null)
return (Style)styleToReturn;
else
return null;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
// not sure if you need this anymore...
return Enum.Parse(typeof(MonitoringTypes), value.ToString().Substring(0,
value.ToString().IndexOf("TitleBlock")));
}
}
This is what I did but with the following code instead. I actually just answered my own question while you answered it as well. Good timing!
public class TitleStyleValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var type = (MonitoringTypes)value;
return App.Current.Resources[string.Format("{0}TitleBlock", Enum.GetName(typeof(MonitoringTypes), type))];
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Enum.Parse(typeof(MonitoringTypes), value.ToString().Substring(0, value.ToString().IndexOf("TitleBlock")));
}
}
public static Style DayModeButton = null;
void loadStyle()
{
Uri uri1 = new Uri("/Resources/ButtonStyle.xaml", UriKind.Relative);
ResourceDictionary resDict1 = Application.LoadComponent(uri1) as ResourceDictionary;
foreach (object obj in resDict1.Values) //Set explicit reference
if (obj is Style) DayModeButton = (Style)obj;
}
[ValueConversion(typeof(object), typeof(Style))]
public class GetStyleConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return DayModeButton ;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return 0;
}
}
I have the following radio button bound to the variable IsAllowed
<RadioButton Name="YesRadioButton" Margin="5,5,0,0" IsChecked="{Binding Path=IsAllowed, Mode=TwoWay}">Yes</RadioButton>
How can I make the No button to take the opposite value only using XAML ?
You do not need to. It will happen by default.
Just make sure that IsAllowed starts off as true, and the rest will take care of its self.
This is because when you click on the No button, it will automatically set the Yes button's checked value (that's how radio buttons work), so the change will happen automatically and you backing class will be updated.
EVEN BETTER: Just use a check box. Yes/no situations are what they are designed for.
There is no Xaml-only solution. You could bind No using a reverse bool Converter though.
<local:NotConverter x:Key="notConverter"/>
{Binding IsAllowed, Mode=TwoWay, Converter=notConverter}
public class NotConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Boolean result = false;
if (value is Boolean)
result = !((Boolean)value);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Boolean result = false;
if (value is Boolean)
result = !((Boolean)value);
return result;
}
}
You will have to write converter using IValueConverter. Here is an example how to do it WPF - Bind to Opposite Boolean Value Using a Converter
The above answer works but I wanted a converter that would apply to both Yes and No radio buttons and reflect the value of nullable booleans. So I made the alternative that takes advantage of converter parameters:
public class YesNoRadioButtonToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return CompareValueWithRequiredValueToBeChecked(value, parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return CompareValueWithRequiredValueToBeChecked(value, parameter);
}
private bool CompareValueWithRequiredValueToBeChecked(object value, object parameterValue)
{
bool? convertedValue = ConvertObjectToBool(value);
bool? convertedParameter = ConvertObjectToBool(parameterValue);
bool result = convertedValue == convertedParameter;
return result;
}
private bool? ConvertObjectToBool(object parameter)
{
string stringResult = parameter == null ? null : parameter.ToString();
bool? convertedResult;
bool convertResultTest = false;
if (stringResult != null && !bool.TryParse(stringResult, out convertResultTest))
{
throw new InvalidCastException(string.Format("Cannot convert {0} to a bool.", parameter));
}
convertedResult = stringResult == null ? (bool?)null : (bool?)convertResultTest;
return convertedResult;
}
}
Here is what the XAML looks like:
<converters:YesNoRadioButtonToBooleanConverter x:Key="yesNoToBool" />
<RadioButton Content="Yes" Name="radYes" GroupName="Group1" IsChecked="{Binding Path=boolProperty1, Mode=TwoWay, Converter={StaticResource yesNoToBool}, ConverterParameter=true}" />
<RadioButton Content="No" Name="radNo" GroupName="Group1" IsChecked="{Binding Path=boolProperty1, Mode=TwoWay, Converter={StaticResource yesNoToBool}, ConverterParameter=false}" />
I have:
public class Person
{
String name { get; set; }
String address { get; set; }
bool isMarried { get; set; }
}
My datagrid gets populated with a list of persons.
I want to have a custom column where icon-1.jpg is displayed when isMarried is true and icon-2.jpg is displayed when isMarried is false.
How do I do this in WPF ? Any ideas ?
I know how to do a custom column but I do not know how to assoc the two states of isMarried with icon-1.jpg and icon-2.jpg.
You could do this with a DataTrigger in your custom column:
<DataGridTemplateColumn Header="Married">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image x:Name="IMG" Source="married_image" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=isMarried}" Value="False">
<Setter Property="Source" Value="not_married_image" TargetName="IMG"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
You can use an IValueConveter to convert from a Boolean value to an Uri (Uri is what you need for image source).
public class MarriedConverter : IValueConverter
{
public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
{
if ((value == null) || !(value is bool))
return null;
bool isMarried = (bool)value;
if (isMarried)
return new Uri(#1);
else
return new Uri(#2);
}
public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}