ConverterParameter Usage - wpf

I have a basic question regarding the usage of ConverterParameter. In the sense - I can always create a collection of types in my viewmodel and pass it to the converter during Binding.
And then in my convert method - I can do multiple if check statements and return accordingly
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
}
So the question is what exactly are the scenarios of using a ConverterParameter which just justifies it usage.
Please note - I am not asking how to use a ConverterParameter - i have done that - more interested when to use it

Here's some of the cases where I used Converter parameter
I have a converter used by many user controls each user control
represents specific class type. I used converter parameter to hold
the class type so I can control the conversion behavior based on the
parameter type.
I have a converter that convert date to string. I used converter
parameter to define if It's Departure date or arrival date to return
single string in the required format

Related

How is the string "Red" in Background="Red" converted to SolidColorBrush?

I want to understand how WPF converts the string value (Red) to the corresponding SolidColorBrush in the case below?
How can we do the same with our custom DependencyProperty?
<Button Background="Red" />
The conversion from string to Brush is performed by a BrushConverter instance, a TypeConverter which is registered like this:
[System.ComponentModel.TypeConverter(typeof(System.Windows.Media.BrushConverter))]
public abstract class Brush : ...
It will automatically be used for any property of type Brush.
Assuming you have a dependency property like
public static readonly DependencyProperty MyBrushProperty =
DependencyProperty.Register(
nameof(MyBrush),
typeof(Brush),
typeof(MyButton));
public Brush MyBrush
{
get { return (Brush)GetValue(MyBrushProperty); }
set { SetValue(MyBrushProperty, value); }
}
the following would work out of the box:
<local:MyButton MyBrush="Red" />
In case the question is about a custom property type - instead of a custom property of type Brush - see the other answer :-)
This is done using type converters, see TypeConverters and XAML.
This topic introduces the purpose of type conversion from string as a general XAML language feature. In the .NET Framework, the TypeConverter class serves a particular purpose as part of the implementation for a managed custom class that can be used as a property value in XAML attribute usage. If you write a custom class, and you want instances of your class to be usable as XAML settable attribute values, you might need to apply a TypeConverterAttribute to your class, write a custom TypeConverter class, or both.
A XAML processor needs two pieces of information in order to process an attribute value. The first piece of information is the value type of the property that is being set. Any string that defines an attribute value and that is processed in XAML must ultimately be converted or resolved to a value of that type. [...]
If the value is neither a parser-understood primitive nor an enumeration, then the type in question must be able to provide an instance of the type, or a value, based on a converted string. This is done by indicating a type converter class. The type converter is effectively a helper class for providing values of another class, both for the XAML scenario and also potentially for code calls in .NET code.
WPF has a few built-in type converters like in case of a Brush, the BrushConverter. You can see how the brush converter is implemented in .NET e.g. in the reference source or on GitHub for .NET Core.
As you can see from the documentation of Brush, it specifies an attribute for the converter.
[System.ComponentModel.TypeConverter(typeof(System.Windows.Media.BrushConverter))]
[System.Windows.Localizability(System.Windows.LocalizationCategory.None, Readability=System.Windows.Readability.Unreadable)]
public abstract class Brush : System.Windows.Media.Animation.Animatable, IFormattable
You do not create a type converter for a dependency property, but its underlying type, like Brush. The documenation shows in detail how to create type converters for custom types. In essence:
Create custom type converter that dervies from TypeConverter.
public sealed class MyCustomTypeConverter : TypeConverter
{
// ...conversion methods.
}
Implement the following methods.
CanConvertTo
CanConvertFrom
ConvertTo
ConvertFrom
Finally, apply the TypeConverterAttribute to your custom type.
In order for your custom type converter to be used as the acting type converter for a custom class by a XAML processor, you must apply the TypeConverterAttribute to your class definition. The ConverterTypeName that you specify through the attribute must be the type name of your custom type converter. With this attribute applied, when a XAML processor handles values where the property type uses your custom class type, it can input strings and return object instances.
[TypeConverter(typeof(MyCustomTypeConverter ))]
public class YourCustomType
{
// ...code of your custom type.
}
Following these steps, the XAML parser will automatically be able to convert strings to your type.
The BrushConverter, mentioned above, is a good example of a TypeConverter implementation to start from.

IValueConverter uses the wrong culture with DateTime

Hi the below code is used to convert the DateTime format to current thread culture format
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DateTimeOffset?)
{
var dto = (DateTimeOffset?)value;
return dto.Value.ToString("t", culture);
}
return null;
}
But the DateTimeFormat in culture parameter is not updating to the current system datetime format, instead it uses the fixed format like HH:mm tt for short time.
The workarond for this is to set the language from the current thread as below, which we have done in App.Xaml but still DateTimeFormat will have the default format.
// fixes culture-specific binding formatting. See this link: WPF Binding StringFormat Short Date String
this.Language = System.Windows.Markup.XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.IetfLanguageTag);
I have gone through some blogs on this and looks like its a bug in WPF. Some guys suggest not to rely on culture for DateTime as DateTimePicker should give a selected date formatted to the local thread culture. This works fine if we remove the culture parameter in ToString().
Please provide your suggestions or solution for this :)
Maybe you need to set the language also on the WPF controls
(also in App.xaml.cs)
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

wpf converters with different decimal number

I have a lot of numbers to deal with from my UI. I want some of them to be no decimal places, some to be 2 decimals, and others to be however they are entered (3 or 4 decimal places).
I have a converter named DoubleToStringConverter like this:
[ValueConversion(typeof(double), typeof(string))]
public class DoubleToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? null : ((double)value).ToString("#,0.##########");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
double retValue;
if (double.TryParse(value as string, out retValue))
{
return retValue;
}
return DependencyProperty.UnsetValue;
}
}
Is there a way to write just one converter to achieve this? It seems there is no way to have a parameterized converter. The StringFormat in xaml seems to conver string to other type of data. It does not allow to display a substring from xaml.
I can only think of making IntegerToStringConverter, Double2ToStringConverter, Double3ToStringConverter, etc. But I'd like to see whether there is a more efficient way.
You can pass the number of decimal points to use as the parameter, which can then be specified in XAML via ConverterParameter within the binding.
That being said, for formatting numbers, you don't actually need a converter at all. Bindings support StringFormat directly, which can be used to do the formatting entirely in XAML:
<TextBox Text="{Binding Path=TheDoubleValue, StringFormat=0:N2} />

Is it Possible to Bind two Different resource values in the same textbox using Silverlight

i have two values firstname and lastname i want to display them together as firsname.lastname
how to right the binding path so that i can get both values is it possible to do such things??
There's not a direct way to do what you're asking.
Create a third property that returns the formatted value and fire a PropertyChanged event for it when either firstname or lastname change.
I would use 2 text boxes inside stack panel, o create a data template
A converter could be a good option here
for example it would make sense that you have a Person object in this case. For your textbox bind to the person object and pass it through a converter. the converter could take the values and return your combined string
something like the following
// this would be your convert function inside your converter that implements the IValueConverter interface
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Person p = value as p;
if (p != null)
{
return string.Format("{0},{1}", p.LastName,p.FirstName);
}
return string.Empty; //or you could show an error maybe...
}

WPF how to bind two observable collections of different but related types using a value converter?

I have a custom control with an observable collection(DP) holding a certain type objects. I want to bind it to another observable collection holding a different type objects in my VM. How do I do this?
Should I even be doing something like this?
Edit. Ofcourse the binding should work when elements in the collections are modified on either side.
Meleak's comment is correct, you should somehow transform one collection into another and sync them. Here is how I did it last time:
View (I've named it MyControl below) has property Items of type IEnumerable<Target>
DataContext has property Items of type IEnumerable<Source>
class CollectionsConverter : IValueConverter
{
public object Convert(object value, ...)
{
var source = (ObservableCollection<Source>)value;
var target = new ObservableCollection<Target>(source.Select(/* Convert items somehow /);
// subscribe to both target's and source's 'CollectionChanged' events
// and propagate them back and forth to another collection.
// Propagated events should have converted items of course
return target;
}
...
}
Then in XAML:
<MyControl Items="{Binding Items, Converter=CollectionsConverter}" />
Regarding converting each item - it can be either generic code which will dynamically determine how to convert Source to Target and vice versa or it should be a code which will know which exact types it will convert and how to convert them.
ValueConverters don't work the way you're describing, you have to create a new collection by-hand.
This doesn't answer your question directly, but in ReactiveUI (http://www.reactiveui.net), this scenario is quite easy:
var derivedColl = someCollection.CreateDerivedCollection(x => new SomeOtherClass(x));
Use your custom Converter class implementing IValueConverter
public class ObserverTypeConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//return your dependency type from here
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//return your view model type from here, this will get fired if your binding is two way
}
}

Resources