Silverlight Value Converter - silverlight

I have a Value Converter running for an incoming string value from the database, to set the appropriate icon for a gender. The value coming in must be either M or F, and either one will display a male or female icon respectively. The Binding is working to some extent, in that the picture appears, but it is only displaying one set of icons for either value.
The value converter code is as follows:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var gender = (string)value;
Uri uri;
uri = gender == "F" ?
new Uri("../Resources/Icons/female_user.png", UriKind.Relative) :
new Uri("../Resources/Icons/male_user.png", UriKind.Relative);
return uri;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
and the XAML is as follows
<Image Margin="8" Width="35" Height="35"
VerticalAlignment="Top" HorizontalAlignment="Center"
Source="{Binding Gender, Converter={StaticResource genderConverter}}" />
The resource is cited in the usercontrol.resources and all is properly bound I assume. So why does the converter persistently return only one value?

Try this...
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var gender = (string)value;
Uri uri;
uri = gender == "F" ?
new Uri("../Resources/Icons/female_user.png", UriKind.Relative) :
new Uri("../Resources/Icons/male_user.png", UriKind.Relative);
BitmapImage img_Gender = new BitmapImage(uri);
return img_Gender;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}

All I needed was a gender.Trim() to get rid of all white spaces.
var gender = value.ToString();
try
{
return gender.Trim() == "F" ? "../Resources/Icons/male_user.png" : "../Resources/Icons/female_user.png";
}
catch (Exception)
{
return "";
}
Thats took care of it all, and it works. Thanks for the answers and "doh!" possibilites though.

Related

Why is WPF/XAML adding 3 "Mocks" objects to my IEnumerable collection in my ViewModel?

I have a property defined in my ViewModel as such:
public IEnumerable<SubsystemFilterState> CurrentFilterStates { get; private set; }
That I want to display in my view. I've done the binding to a Label and provided a converter:
XAML:
<Label Style="{StaticResource LabelFilterIndicator}"
Content="{Binding CurrentFilterStates,
Converter={StaticResource FilterConverter},
Mode=OneWay}" />
Converter:
public class FilterIndicatorConverter
: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
var indicator = "No Filter Selected";
if (value != null)
{
IEnumerable<SubsystemFilterState> states = (IEnumerable<SubsystemFilterState>)value;
indicator = states.Count() > 1
?
"Multiple Systems"
:
states.First().Acronym.ToString();
}
return indicator;
}
catch (Exception ex)
{
return ex.Message;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
This works fine at run-time. At design-time, it's throwing an exception which is displayed in my label. Here's the exception:
Unable to cast object of type
'System.Collections.ObjectModel.ObservableCollection1[Mocks.Models_SubsystemFilterState_14_1174211]'
to type
'System.Collections.Generic.IEnumerable1[Models.SubsystemFilterState]'.
I can't figure out where this magical ObservableCollection is coming from. I don't have a Mocks namespace and have never mocked any value into that property. I changed the code in my converter to the following, to find out where they're coming from:
Quick and/or dirty:
public class FilterIndicatorConverter
: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
var indicator = "";
if (value != null)
{
foreach (dynamic test in value as IEnumerable)
{
Type type = test.GetType();
indicator += string.Format("Start{0}" +
"AssemblyQualifiedName: {0}{6}{1}{0}" +
"Namespace: {0}{6}{2}{0}" +
"Assembly: {0}{6}{3}{0}" +
"BaseType: {0}{6}{4}{0}" +
"FullName: {0}{6}{5}{0}{0}",
"\n",
type.AssemblyQualifiedName,
type.Namespace,
type.Assembly,
type.BaseType,
type.FullName,
" ");
}
}
return indicator;
}
catch (Exception ex)
{
return ex.Message;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Which displays this:
It looks like Visual Studio is adding these in at design time but why does it not match the type of my property? Can I turn this off? What is the DesignTools namespace?

DatePicker databinding sets default value to 1/1/0001 WPF c# for a Not-Nullable date

This is an "extension" question to the 1/1/0001 question:
Original Question
The original Q. Solution -
To set the DateTime field to be nullable (DateTime?) solves this problem.
What is the solution when the underlying field must be NOT NULL ?
(In that case, the binding cause the DataGrid column Date Time Picker to set it's self to 01/01/0001)
The Actual Entity in my case is generate by Entity Framework 6.
correct me if I am wrong. You fill your not-null-field with 01/01/0001 to indicate that it's null. (not recommended)
One solution is to define a converter. something like this :
public class NotNullDateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var aDateTime = value as DateTime;
if (aDateTime != null && aDateTime == .... )
return null
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you can define a static field to a converter to use it later in xaml.
public static NotNullDateConverter NotNullDateConverter = new NotNullDateConverter();
Then you use this convert inside your xaml for binding:
SelectedDate="{Binding Path=DueDate, Converter={x:Static local:SomeClass.NotNullDateConverter}}"
I had the exact same problem, so I wrote a converter that could weed out non-dates.
//Just weeds out non-dates. Format should be set with StringFormat on the binding
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime date = (DateTime)value;
if (date != null && date.Year != 1)
{
return date;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I use it like so:
<DataTemplate.Resources>
<logic:DateConverter x:Key="DateConverter"/>
</DataTemplate.Resources>
<TextBlock Text="{Binding LastUpdateTime, StringFormat={}{0:MM/dd/yyyy H:mm:ss}, Converter={StaticResource DateConverter}}"/>

How do I convert a Color to a Brush in XAML?

I want to convert a System.Windows.Media.Color value to a System.Windows.Media.Brush. The color value is databound to a Rectangle object's Fill property. The Fill property takes a Brush object, so I need an IValueConverter object to perform the conversion.
Is there a built-in converter in WPF or do I need to create my own? How do I go about creating my own if it becomes necessary?
I know I am really late to the party, but you don't need a converter for this.
You could do
<Rectangle>
<Rectangle.Fill>
<SolidColorBrush Color="{Binding YourColorProperty}" />
</Rectangle.Fill>
</Rectangle>
It seems that you have to create your own converter. Here a simple example to start:
public class ColorToSolidColorBrushValueConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (null == value) {
return null;
}
// For a more sophisticated converter, check also the targetType and react accordingly..
if (value is Color) {
Color color = (Color)value;
return new SolidColorBrush(color);
}
// You can support here more source types if you wish
// For the example I throw an exception
Type type = value.GetType();
throw new InvalidOperationException("Unsupported type ["+type.Name+"]");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
// If necessary, here you can convert back. Check if which brush it is (if its one),
// get its Color-value and return it.
throw new NotImplementedException();
}
}
To use it, declare it in the resource-section.
<local:ColorToSolidColorBrushValueConverter x:Key="ColorToSolidColorBrush_ValueConverter"/>
And the use it in the binding as a static resource:
Fill="{Binding Path=xyz,Converter={StaticResource ColorToSolidColorBrush_ValueConverter}}"
I have not tested it. Make a comment if its not working.
A Converter is not needed here. You can define a Brush in XAML and use it. It would be better to define the Brush as a Resource so it can be used other places required.
XAML is as below:
<Window.Resources>
<SolidColorBrush Color="{Binding ColorProperty}" x:Key="ColorBrush" />
</Window.Resources>
<Rectangle Width="200" Height="200" Fill="{StaticResource ColorBrush}" />
I wanted to do this HCL's way rather than Jens' way because I have a lot of things bound to the Color, so there's less duplication and boiler-plate .Fill nodes.
However when trying to write it, ReSharper pointed me to the WPF Toolkit's implementation of the ColorToSolidColorBrushConverter. You need to include the following namespace declaration in the main Window/UserControl node:
xmlns:Toolkit="clr-namespace:Microsoft.Windows.Controls.Core.Converters;assembly=WPFToolkit.Extended"
Then a static resource in the Window/UserControl resources:
<Toolkit:ColorToSolidColorBrushConverter x:Key="colorToSolidColorBrushConverter" />
Then you can do it like HCL's answer:
<Rectangle Fill="{Binding Color, Converter={StaticResource colorToSolidColorBrushConverter}}" />
With some more enhancment to HCL answer, I tested it - it works.
public class ColorToSolidColorBrushValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (value is Color)
return new SolidColorBrush((Color)value);
throw new InvalidOperationException("Unsupported type [" + value.GetType().Name + "], ColorToSolidColorBrushValueConverter.Convert()");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (value is SolidColorBrush)
return ((SolidColorBrush)value).Color;
throw new InvalidOperationException("Unsupported type [" + value.GetType().Name + "], ColorToSolidColorBrushValueConverter.ConvertBack()");
}
}
Converter:
[ValueConversion(typeof(SolidColorBrush), typeof(Color))]
public class SolidBrushToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is SolidColorBrush)) return null;
var result = (SolidColorBrush)value;
return result.Color;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML:
//...
<converters:SolidBrushToColorConverter x:Key="SolidToColorConverter" />
//...
<Color>
<Binding Source="{StaticResource YourSolidColorBrush}"
Converter="{StaticResource SolidToColorConverter}">
</Binding>
</Color>
//...
In addition to HCLs answer: If you don't want to care if System.Windows.Media.Color is used or System.Drawing.Color you can use this converter, which accepts both:
public class ColorToSolidColorBrushValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case null:
return null;
case System.Windows.Media.Color color:
return new SolidColorBrush(color);
case System.Drawing.Color sdColor:
return new SolidColorBrush(System.Windows.Media.Color.FromArgb(sdColor.A, sdColor.R, sdColor.G, sdColor.B));
}
Type type = value.GetType();
throw new InvalidOperationException("Unsupported type [" + type.Name + "]");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Using Pattern matching there's no need for neither null checking and double casting:
public class ColorToSolidBrushValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Color color) return new SolidColorBrush(color);
throw new InvalidOperationException(nameof(color));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => new NotImplementedException();
}
Optional implementation for ConvertBack:
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is SolidColorBrush brush)
{
return brush.Color;
}
throw new InvalidOperationException(nameof(brush));
}

Set value to null in WPF binding

please take a look at the following line
<TextBox Text="{Binding Price}"/>
This Price property from above is a Decimal? (Nullable decimal).
I want that if user deletes the content of the textbox (i.e. enters empty string, it should automatcally update source with null (Nothing in VB).
Any ideas on how I can do it 'Xamly'?
I am using .NET 3.5 SP1 so it's very simple:
<TextBox Text="{Binding Price, TargetNullValue=''}"/>
Which stands for (thanks Gregor for your comment):
<TextBox Text="{Binding Price, TargetNullValue={x:Static sys:String.Empty}}"/>
sys is the imported xml namespace for System in mscorlib:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Hope that helped.
This value converter should do the trick :
public class StringToNullableDecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
decimal? d = (decimal?)value;
if (d.HasValue)
return d.Value.ToString(culture);
else
return String.Empty;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
string s = (string)value;
if (String.IsNullOrEmpty(s))
return null;
else
return (decimal?)decimal.Parse(s, culture);
}
}
Declare an instance of this converter in the ressources :
<Window.Resources>
<local:StringToNullableDecimalConverter x:Key="nullDecimalConv"/>
</Window.Resources>
And use it in your binding :
<TextBox Text="{Binding Price, Converter={StaticResource nullDecimalConv}}"/>
Note that TargetNullValue is not appropriate here : it is used to define which value should be used when the source of the binding is null. Here Price is not the source, it's a property of the source...
You can try using a ValueConverter (IValueConverter)
http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx
Of the back of my head here, something like:
public class DoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (double)value;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
var doubleValue = Convert.ToDouble(value);
return (doubleValue == 0 ? null : doubleValue);
}
}
(Might need some tweaking though)

Wpf Binding Stringformat to show only first character

Is there any way so that i can show only first character of a Bound string on a textblock..?
For eg;If i Bind 'Male', my textblock should only show 'M'.....
You might use a value converter to return a string prefix:
class PrefixValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string s = value.ToString();
int prefixLength;
if (!int.TryParse(parameter.ToString(), out prefixLength) ||
s.Length <= prefixLength)
{
return s;
}
return s.Substring(0, prefixLength);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
And in XAML:
<Window.Resources>
...
<local:PrefixValueConverter x:Key="PrefixValueConverter"/>
</Window.Resources>
...
...{Binding Path=TheProperty, Converter={StaticResource PrefixValueConverter},
ConverterParameter=1}...

Resources