wpf converters with different decimal number - wpf

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} />

Related

Converter return value not used

I am trying to convert a value on my view model to the type that a control needs. I have an IValueConverter implementation that is being called. It is returning a valid value. However, the value that is returned to the control is not what's returned by the converter.
NOTE Below is a rough example, though not exactly my scenario. I can't post my code as it belongs to the company. Also, I've been unable to replicate the problem. The same scenario in another application works fine.
My converter:
public class TupleCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var members = (IEnumerable<Tuple<string, string>>) value;
var retVal = new ObservableCollection<string>(members.SelectMany(t => new[] {t.Item1, t.Item2}));
return retVal;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And in the XAML:
<ItemsControl ItemsSource="{Binding ValuePairs, Converter={StaticResource MyTupleCollectionConverter}}"/>
When I debug, putting a break point at the return of the converter, I see that it's converting correctly with values, but then I get nothing in the control. Running Snoop, it says that the ItemsSource property is set to null.

How do I bind a DataGrid Width to a converter?

I want to include the size of the VerticalScrollbar when i define the width of a DataGrid.
So far i wrote a Converter:
[ValueConversion(typeof(double), typeof(double))]
public class VerticalScrollbarConverter : IValueConverter
{
#region IValueConverter Member
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double)
return (double)value + SystemParameters.VerticalScrollBarWidth;
else
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
I included my converter in the xaml namespace with:
xmlns:Core="clr-namespace:Core;assembly=SMS_Core"
And I defined the converter as a (window) resource:
<Window.Resources>
<Core:VerticalScrollbarConverter x:Key="VerticalScrollbarConverter"/>
</Window.Resources>
Since all of my DataGrid.Columns have a fixed Value I know the value that i need to pass.
How do I tell my GridView Width property in xaml to use the converter?
I know that my question is pretty basic. As you can tell I am very new to WPF.
Thanks in advance for every hint. If you need some more info or context just ask away.
The comment from sa_ddam213 didn't exactly solve the problem. But it sure did push me into the right direction.
To pass the value automatically I had to do the following:
I created a property in the window class called TotalColumnWidth. Returning this:
myDataGrid.Columns.Sum(c => c.ActualWidth);
The xaml is the following:
Width="{Binding ElementName=_Root, Path=TotalColumnWidth, Converter={StaticResource ResourceKey=VerticalScrollbarConverter}}"
Using the converter mentioned above.

Writing conditional statements in XAML code

I have this listBox that gets populated, each item can be either male or female depending on the 'SEX' property that is binded to the listBox. (Could be either 'M' for male and 'F' for female)...
For each item i would like to display either a male or female symbol based on the list items SEX property.
for instance if "{Binding SEX}" equals 'M':
<Image Source="../Images/male48.png" Visibility="Visible" />
and if "{Binding SEX}" equals 'F':
<Image Source="../Images/female48.png" Visibility="Visible" />
How exactly would I go about getting this to work?
A common approach to this problem is to create a value converter, this converts the value returned by a binding into some other value that relates to the property of a UI control.
You can create a converter that takes the sex and maps it to an image source:
public class SexToSourceConverter : IValueConverter
{
public object Convert(object value, string typeName, object parameter, string language)
{
string url = ((string)value == "M") ? "../Images/male48.png" : "../Images/female48.png";
return new BitmapImage(new Uri(url , UriKind.Relative));
}
public object ConvertBack(object value, string typeName, object parameter, string language)
{
throw new NotImplementedException();
}
}
Using it in your XAML as follows:
<Image Source="{Binding Path=Sex, Converter={StaticResource SexToSourceConverter }" />
If someone is interested in how this could work, I've made a solution based on ColinE's answer. First, you've to create a new class which contain the conditions you'll like to add to the XAML code:
public class MyNiceConverterName : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
// Your conditions here!
return value_you_want_to_return; // E.g., a string, an integer and so on
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException(); // Leave this like here, don't worry
}
}
Call the class whatever you want (right now it's called MyNiceConverterName) and implement the Convert() method with the conditions you'd like to add to the XAML file. Remember to cast the object value to the type you're using (e.g., (int)value if it's an integer).
This is almost done! But not yet, first declare the converter in your XAML as a resource. You can paste this code below the namespaces declaration:
<Control.Resources>
<converter:MyNiceConverterName xmlns:converter="clr-namespace:My_Namespace" x:Key="MyNiceConverterName" />
</Control.Resources>
You've to declare the namespace where you defined the class (i.e., remove My_Namespace with yours') and also rename MyNiceConverterName to your class name. The key will be the name defined to reference the converter within the XAML document, here I've used the same class name but you can freely change it.
Finally, it's time to use the converter. Put this and you're done:
{Binding variable_with_value, Converter={StaticResource MyNiceConverterName}}
Remember to change variable_with_value with the one you'd like to use within your binding.
I hope it helps!
Either use a binding converter or use two triggers.
For Siverlight this is the correct IValueConverter link, I am not sure if triggers are supported.

ComboBox of Types with a ValueConverter and Custom Attributes

I'm using MVVM, in case it makes a difference.
My MainWindowViewModel has two DependencyProperties, TheList, and TheSelectedItem. TheList is a List<Type>, TheSelectedItem is a Type.
The MainWindow has a ComboBox. When the MainWindowViewModel loads it grabs a list of all the classes in the assembly that implement IMyInterface and sets TheList to this.
Each of these classes has a custom attribute applied called DisplayName, which has one parameter, that will be used to show a user-friendly name for the class instead of the name the application knows about for the class.
I've also got a ValueConverter for the express purpose of converting these types into the display names.
public class TypeToDisplayName : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType.Name == "IEnumerable")
{
List<string> returnList = new List<string>();
if (value is List<Type>)
{
foreach (Type t in value as List<Type>)
{
returnList.Add(ReflectionHelper.GetDisplayName(t));
}
}
return returnList;
}
else
{
throw new NotSupportedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return typeof(BasicTemplate);
}
}
So, what I wind up with is a ComboBox with a list of names in it that the user should be able to understand. Awesome! This is just what I want!
Next step: I bind the SelectedItem property of my ComboBox to my TheSelectedItem property in my ViewModel.
Here's the problem: When I make a selection, I get a little red box around my ComboBox and the TheSelectedItem property on my ViewModel never gets set.
I'm pretty sure it's because of a type mismatch (the items in the ComboBox appear to be strings now, and TheSelectedItem is of type Type--also, when I change TheSelectedItem to a string instead of a Type, it works). But I don't know where I need to start coding to convert the (hopefully unique) DisplayName that's in the ComboBox back to a Type object.
Thanks in advance for any help. I'm pretty stumped on this one.
If I understand your question correctly then you use that Converter on the ItemsSource for the ComboBox? In that case I think you can let the ItemsSource be like it is and instead just Convert each type when they are presented like this.
<ComboBox ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=typeName, Converter={StaticResource TypeToDisplayNameConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
And then just convert each type in the Converter.
public class TypeToDisplayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Type t = (Type)value;
return ReflectionHelper.GetDisplayName(t);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
Make sure you have IsSynchronizedWithCurrentItem set to true on the ComboBox. Check this out...

WPF: Binding Hierarchy

I have defined a default binding in my style.
For example I have configured the visibility binding of my button so that it must not be visible if the relative command can not execute.
This is my default binding behavior.
Apart from my default behavior, every view can customize the buttons it uses with another visibility binding.
I want to combine the two bindings so that if any of two say "it's not visible" it will be not visible!
In other words, is it possibile to create a binding behavior hierarchy? Thanks!
use a MultiBinding to wire up all the different bindings in XAML, and write your own IMultiValueConverter that prioritises / ands / ors each value as you like. You can't use a MultiBinding without an IMultiValueConverter (or a StringFormat, but that's no use to you)
Note that PriorityBinding is NOT what you are looking for here.
here's a valueConverter you can use:
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleansAndToVisibilityMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Func<bool, bool, bool> aggregator = (x, y) => x && y;
bool aggregate = values.Cast<bool>().Aggregate(aggregator);
return aggregate ? Visibility.Visible : Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
No, sorry, not possible in XAML.
You CAN do this combination in code, though. You can write a BindingConverter for this.

Resources