Binding 2 textboxes with calculated ratio - wpf

I have a model that contains a HorsePower and a Kilowatt property
1 HP = 0.745 KW
I then have 2 textboxes where i want to update 'the other' with the calculated value.
eg: if i input '100' into the bound HP textbox, i want the KW textbox to update with '74,5'
and vise versa : 74,5 into KW -> updates HP to 100
one solution i figured, would be to bind to only 1 property, eg: HP and then use a value converter for the KW textbox (and then update KW on property changed)
is there another way to do this ?

You will need a binding converter like this:
public class MinusValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
return 100 - System.Convert.ToInt32(value);
}
catch (Exception)
{
return null;
}
}//END Convert
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}//END ConvertBack
}//END class ValueToCurrentConverter : IValueConverter
And XAML:
<TextBox Name="tbHorsepower" Text="8"/>
<TextBox Text="{Binding ElementName=tbHorsepower, Path=Text, Converter={StaticResource SubstractFrom100}}" IsReadOnly="True">
<TextBox.Resources>
<local1:MinusValueConverter x:Key="SubstractFrom100"/>
</TextBox.Resources>
</TextBox>
(Your textboxes will most likely look different)

Related

How to bind int to Visibility in WPF?

I have BudgetControlType Properties that has 1 .. 7 value
if(BudgetControlType ==1)
dataComboBox1.Visibility=Visibility.Visiblile;
dataComboBox2 to dataComboBox7 =Visibility.Hidden;
if(BudgetControlType ==2)
dataComboBox1.Visibility=Visibility.Visiblile;
dataComboBox2.Visibility=Visibility.Visiblile;
dataComboBox3 to dataComboBox7 =Visibility.Hidden;
and so on...
How to do this in xaml?
Here is another approach I have used in the past using WPFConverters.
<TabItem.Visibility>
<Binding Path="SomeObservableCollection.Count">
<Binding.Converter>
<converters:ConverterGroup>
<converters:ExpressionConverter Expression="{}{0} > 0" />
<BooleanToVisibilityConverter />
</converters:ConverterGroup>
</Binding.Converter>
</Binding>
</TabItem.Visibility>
The ConvertGroup allows for multiple converters to be run sequentially.
The ExpressionConverter lets you define an arbitrary expression. In my case I want the TabItem to be visible if the collection count is greater than zero. Being defined in xaml means escaping characters and a somewhat awkward syntax but it works well enough!
The BooleanToVisibilityConverter converts the boolean result from the expression to our desired visibility.
For Elham, BudgetControlType could be bound to as long as it implemented INotifyPropertyChanged. An equals expression is done like this (I'm returning true if the bound value equals 7):
<converters:ExpressionConverter Expression="{}{0} == 7" />
You can use 1,2,4,8,... and convert it to Visibility
for example if your int number is 6 (2+4) then Control with paramerter 2 and Control with parameter 4 is Visible!
public class IntToVisibilityConverter:IValueConverter
{
private int val;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int intParam = (int)parameter;
val = (int)value;
return ((intParam & val) != 0) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
And in xaml :
<ComboBox Visibility="{Binding Path=MyEnum,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=1}"/>
<ComboBox Visibility="{Binding Path=MyEnum,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=2}"/>
<ComboBox Visibility="{Binding Path=MyEnum,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=4}"/>
The best way I'd say would be to go with properties on your ViewModel, and bind to them.
example (you'll have to massage it a bit, but it's fairly simple from here) :
public Visibility dtcb1 { get; set; }
// all the rest till 7
// Somewhere in your logit / constructor :
dtcb1 = BudgetControlType == 1 ? Visible : Hidden;
// and so on
And on your xaml you'll bind your visibility to dtcb1
You can make the property boolean, and use a boolean to visibility converter as well (as per this answer for example, or just google yourself)

WPF databinding to display number in an appropriate currency

I need to display a value in a currency format (EUR / USD / YEN etc.) depending on the currency value stored in the database.
In the database the data is stored like:
Id Value Currency
1 1000 EUR
2 1500 USD
3 9650 USD
In XAML, I'd like to know how I can show the value in a correct currency format.
For example, if I read the first line from the database (Id=1), I like to show it on UI as €1,000 but if I read the second line (Id=2) it should be shown as $1,500.
Right now my XAML MVVM binding looks like this:
<TextBlock Text="{Binding SelectedItem, StringFormat=c0}" ...
...and for me this displays the value always as $1,500 which I do not want.
A converter class can do the trick for you to achieve the desired behavior
public class CurrencyConverter : MarkupExtension, IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return GetCurrency(values);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
private string GetCurrency(object[] values)
{
switch (values[1].ToString())
{
case "USD":
return string.Format(new System.Globalization.CultureInfo("en-US"), "{0:C}", values[0]);
case "EUR":
return string.Format(new System.Globalization.CultureInfo("en-GB"), "{0:C}", values[0]);
default:
return string.Format(new System.Globalization.CultureInfo("en-US"), "{0:C}", values[0]);
}
}
}
Simply use the converter in XAML with your TextBlock bindings.
<TextBlock DataContext="{Binding SelectedItem, ElementName=listBox}">
<TextBlock.Text>
<MultiBinding Converter="{local:CurrencyConverter}">
<Binding Path="Value"/>
<Binding Path="Currency"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The string format you're using is based on current system locale so it's not a way to go at all. In your situation you would be interested in something like such a converter: http://blogs.msdn.com/b/bencon/archive/2006/05/10/594886.aspx
Pass in two values (currency and amount), return back a string representation to be shown on UI.

Empty textbox bound with some decimal value

I have a textbox bound to some decimal value. Now, if I type something in it like 100 and clear it completely (empty). I save the data and it saves 1 in decimal value. Similarly if I tried 200 and clear textbox it saves 2. Remember decimal value is not null. Any ideas?
<TextBox
Height="23"
VerticalAlignment="Center"
Text="{Binding Discount,Mode=TwoWay}"
MaxLength="50"
TabIndex="28"
Grid.Row="2"
Grid.Column="1"
local:FocusExtension.IsFocused=
"{Binding Path=IsDiscountFocused,Mode=TwoWay}"
Margin="5,0,0,0"/>
Since String.Empty cannot be converted into a decimal per default. The last valid value is kept in the property.
You should use a converter as below.
Wpf
<Window.Resources>
<local:ValueConverter x:Key="valueConverter" />
</Window.Resources>
<TextBox Text="{Binding Path=Value, Mode=TwoWay, Converter={StaticResource valueConverter}}" />
Converter:
public class ValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && (string)value == "")
{
return 0;
}
return value;
}
}
Clr:
public decimal Value
{
get { return (decimal)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
i assume that your Discount property in your viewmodel looks like:
public decimal Discount {get;set;}
if you use backspace and clear your textbox you get a binding exception because "" can not convertet to decimal. so the last number remains in your property. actually this should happen when using UpdateSourceTrigger=Propertychanged. but nevertheless you can try using decimal?. if this not help you can also add a converter to convert the "" to a value your viewmodel can handle.
EDIT: i did not see you last comment. but in the case you want a 0 for an empty textbox, just use a converter to return 0 when "" is the input.

WPF user control to display years and months from one total months value

I have a value in a database that is the totals number of months. In my WPF UI I need to display and update this value as the number of years and the number of months. I am struggling to get the bindings to work in this control so that I can view and update this one value of total months using the two separate textboxes (years and months)
Can anyone help with this?
In the class that is the source of your bindings (e.g. a ViewModel) you can add two properties that calculate the two values whenever needed. For example:
private const int MonthsInAYear = 12; // pedagogic purposes only :)
// This field contains the updated database value
private int _timeInMonths;
public int TimeYears
{
get { return _timeInMonths / MonthsInAYear; }
}
public int TimeMonths
{
get { return _timeInMonths % MonthsInAYear; }
}
If you want these values to be automatically updated, make this class implement the INotifyPropertyChanged interface and raise the PropertyChanged event for both properties whenever the value of _timeInMonths changes.
I guess you should use a converter to convert your month value to the corresponding Year and month values.Or you can do it in your viewmodel itself
Sample
public class MonthConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(((string)parameter)=="Year")
{
return (int)value / 12;
}
if (((string)parameter) == "Month")
{
return (int)value % 12;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
and in your xaml
<StackPanel Orientation="Horizontal">
<TextBlock Height="23" Text="{Binding TotalMonths,Converter={StaticResource MonthConverter},ConverterParameter='Year',StringFormat={}{0}Years}"/>
<TextBlock Height="23" Text="{Binding TotalMonths,Converter={StaticResource MonthConverter},ConverterParameter='Month',StringFormat={}{0}Months}"/>
</StackPanel>

WPF Binding with invalid value for source

I have a TextBox that binds to an integer property.
What can I do so that when there is nothing no valid text in the TextBox that the property gets set to 0.
Really I think this can be extended so that if the binding fails then we set the source to default(T).
I need a nudge in the right direction.
TargetNullValue is the opposite of what I'm looking for(I think), that sets the TextBox text when the source is null. I want when the TextBox text is an invalid binding value to set the source as its default.
Applying a Converter such as the following to your binding should do the trick:
public class TextConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
int actual = (int)value;
return actual.ToString();
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
string actual = (string)value;
int theValue = 0;
int.TryParse(actual, out theValue);
return theValue;
}
}
Your TextBox binding would look something like this:
<TextBox Text="{Binding ... Converter={StaticResource convert}}"></TextBox>
With the convertor defined as a resource of your Window/Control/...

Resources