WPF textbox expression bindings - wpf

I have two textboxes bound to a slider. I want the second textbox to be 1.2 time the value of the slide.
<Slider Maximum="500" Minimum="25" TickFrequency="5" IsSnapToTickEnabled="True" Name="slCellHeight" />
<TextBox Text="{Binding ElementName=slCellHeight, Path=Value, UpdateSourceTrigger=PropertyChanged}" Width="40" Name="txtCellHeight" />
<TextBox Text="{Binding ElementName=slCellHeight, Path=Value, UpdateSourceTrigger=PropertyChanged}" Width="40" Name="txtCellWidth" />
That is, when the slider shows 100, the first textbox(txtCellHeight) should show 100. This is working fine. I want to the second one to be 120.
I tried the calBinding but no success. Please suggest some good ways to do that.

Use a converter.
XAML:
<Window.Resources>
<local:MultiplyConverter x:Key="MultiplyConverter" />
</Window.Resources>
...
<TextBox Text="{Binding ElementName=slCellHeight, Path=Value,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource
MultiplyConverter}, ConverterParameter=1.2 }" Width="40" Name="txtCellWidth" />
Class MultiplyConverter:
class MultiplyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double result;
double.TryParse(parameter.ToString(), out result);
double mult = (double)value * result;
return mult;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I've done it on the fly, so maybe it will need some fixes to compile.

Related

WPF MarkupExtension binding error

refers to implementing a multilanguage interface now I have a problem. I have a grid where its ItemSource it's a Dictionary<string, string>: I can't give the key value as parameter of the markup extension because I have the following exception
A 'Binding' cannot be set on the 'Value1' property of type 'TranslateMarkupExtension'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
This is the xaml where I use the markup extension:
<ItemsControl ItemsSource="{Binding MyDictionary}" Grid.Row="0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="{TranslateMarkup Value1 = {Binding Path = Key}}" Grid.Column="0" />
<TextBox Tag="{Binding Key, Mode=OneWay}" Text="{Binding Value, Mode=OneWay}" Width="200" Height="46" VerticalContentAlignment="Center" Grid.Column="1" LostFocus="TextBox_OnLostFocus" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I can't find any workaround..I need the dictionary as item source because the label will show the key and the textbox the corresponding value..I tried also replacing the dictionary with a list of object but the problem still remains.
Does anyone have a good hint? Thanks in advance.
As suggested by Ed Plunkett, the solution is the ValueConverter.
So the label is know this:
<Label Content="{Binding Key, Converter={StaticResource MultiLangConverter}}" Grid.Column="0" />
where my ValueConverter is the following:
public class StringToMultiLangConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var stringValue = (string) value;
if (string.IsNullOrEmpty(stringValue))
return string.Empty;
string multiLang = LangTranslator.GetString(stringValue);
return multiLang ?? value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
Thanks for the help!

WPF Binding TextBlock to ProgressBar with Percentage

I have a ProgressBar which has a maximum of 10,000 (not 100). I want the binded TextBox to show the percentage of the current Value, not the Value itself. Is it possible to do this in the .xaml code?
The following shows the current Value of my ProgressBar. I want it to show the Value / Maximum.
<ProgressBar x:Name="calculationProgressBar" />
<TextBlock x:Name="calculationProgressText" Text="{Binding ElementName=calculationProgressBar, Path=Value, StringFormat={}{0:0}%}" />
You could setup a simple IMultiValueConverter and pass in the ProgressBars Value and Maximum properties
Example:
Converter
public class ValueToPercentConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double value = System.Convert.ToDouble(values[0]);
double maximum = System.Convert.ToDouble(values[1]);
return (value / maximum) * 100;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="100" Width="100">
<Window.Resources>
<local:ValueToPercentConverter x:Key="ValueToPercentConverter" />
</Window.Resources>
<StackPanel>
<ProgressBar x:Name="calculationProgressBar" Maximum="10000" Value="2566" Height="40"/>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource ValueToPercentConverter}" StringFormat="{}{0}">
<Binding ElementName="calculationProgressBar" Path="Value"/>
<Binding ElementName="calculationProgressBar" Path="Maximum"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Window>
Result:
Since manipulations are not possible in XAML so converters is a approach for the same
I tried to write a simple code for you, using string format for percent notice StringFormat={}{0:P0}
XAML example
<StackPanel>
<StackPanel.Resources>
<l:ScaleConverter x:Key="ScaleConverter"/>
</StackPanel.Resources>
<Slider x:Name="calculationSource" Maximum="10000"/>
<TextBlock Text="{Binding ElementName=calculationSource,
Path=Value, StringFormat={}{0:P0},
Converter={StaticResource ScaleConverter},
ConverterParameter=10000}" />
</StackPanel>
I used slider instead of progressbar for easy demo, you can use any source
specify the max value in converter parameter
and P0 in string format means percentage format with 0 precision eg 0%, you can choose to make it P1 for 1 decimal and so on eg 0.0%
converter class
class ScaleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return System.Convert.ToDouble(value) / System.Convert.ToDouble(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
converter is pretty simple, divide the value by the defined scale.
I hope you'll find it useful for your issue
Extras
additionally if you prefer to define the max range at a single location you can use resources for the same
<StackPanel>
<StackPanel.Resources>
<l:ScaleConverter x:Key="ScaleConverter"/>
<sys:Double x:Key="maxRange">10000</sys:Double>
</StackPanel.Resources>
<Slider x:Name="calculationSource" Maximum="{StaticResource maxRange}"/>
<TextBlock Text="{Binding ElementName=calculationSource,
Path=Value, StringFormat={}{0:P0},
Converter={StaticResource ScaleConverter},
ConverterParameter={StaticResource maxRange}}" />
</StackPanel>

How to reference another control in a TreeViewItem through a binding converter?

I would like to bind the Visibility of a TextBox based on SelectedItem of a ComboBoxin same TreeViewItemContainer. I think I can use a Converter for the Binding but I don't know how to send the ComboBox item as a parameter of the TextBox Binding. Can this be done?
<TreeView>
<TreeView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Margin="2,0" Name="SkillSelectCB" ItemsSource="{Binding PotentialChildren}" />
<TextBox Margin="2,0" Width="50" Visibility="{Binding ??}" />
<Button Margin="2,0" Content="Add" />
</StackPanel>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
This is actually in a HierarchicalDataTemplate, the example above is very minimal. The "Add" Button will add new children to the ViewModel for the TreeView based on what's selected in the ComboBox. And the visibility is the TextBox will change depending on some property of the ComboBox's SelectedItem.
So the Xaml for the TextBox:
<TextBox Margin="2,0"Width="50" Visibility="{Binding SelectedItem, ElementName=SkillSelectCB, Converter={StaticResource SkillToVisibilityConverter}}" />
And the Converter:
public class SkillToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var s = (Skill)value;
return (s == null || !s.Specialized) ? "Hidden" : "Visible";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

WPF ComboBox a better way to format ItemsSource

Morning Guys,
I have a few ComboBoxes bound to List of TimeSpan. I am formatting the TimeSpans using IValueConverter and ItemTemplate. I was wondering if there were an easier way to format the TimeSpans. Here's what I'm currently doing.
public class TimeSpanConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
TimeSpan t = TimeSpan.MinValue;
TimeSpan.TryParse(value.ToString(), out t);
return "{0:00}:{1:00}".F(t.Hours,t.Minutes);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return TimeSpan.Parse(value.ToString());
}
#endregion
}
<Canvas>
<Canvas.Resources>
<bc:TimeSpanConverter x:Key="ts" />
<DataTemplate x:Key="TimeSpanTemplate">
<TextBlock Text="{Binding ., Converter={StaticResource ts}}" />
</DataTemplate>
</Canvas.Resources>
<TextBlock Canvas.Left="6"
Canvas.Top="6"
Height="21"
Name="textBlock4"
Text="Begin"
Width="40" />
<TextBlock Canvas.Left="81"
Canvas.Top="6"
Height="21"
Name="textBlock5"
Text="End"
Width="40" />
<ComboBox Canvas.Left="7"
Canvas.Top="25"
Height="23"
Name="TimeBeginCombo"
ItemTemplate="{StaticResource TimeSpanTemplate}"
SelectedItem="{Binding TimeBegin}"
Width="68" />
<ComboBox Canvas.Left="81"
Canvas.Top="25"
Height="23"
Name="TimeEndCombo"
ItemTemplate="{StaticResource TimeSpanTemplate}"
SelectedItem="{Binding TimeEnd}"
Width="68" />
</Canvas>
</GroupBox>
Is what you're binding to of type TimeSpan? If so, then the converter can be much simpler
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is TimeSpan))
return string.Empty;
TimeSpan t = (TimeSpan)value;
return "{0:00}:{1:00}".F(t.Hours,t.Minutes);
}
And also, a general remark - are you sure you need to layout your UI on a Canvas and using absolute coordinates? :)

Show the validation error template on a different control in WPF

I have a UserControl that contains other controls and a TextBox. It has a Value property that is bound to the TextBox text and has ValidatesOnDataErrors set to True.
When a validation error occurs in the Value property binding, the error template (standard red border) is shown around the entire UserControl.
Is there a way to show it around the TextBox only?
I'd like to be able to use any error template so simply putting border around textbox and binding its color or something to Validation.HasError is not an option.
Here's my code:
<DataTemplate x:Key="TextFieldDataTemplate">
<c:TextField DisplayName="{Binding Name}" Value="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
</DataTemplate>
<controls:FieldBase x:Name="root">
<DockPanel DataContext="{Binding ElementName=root}">
<TextBlock Text="{Binding DisplayName}"/>
<TextBox x:Name="txtBox"
Text="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True}"
IsReadOnly="{Binding IsReadOnly}"/>
</DockPanel>
UserControl (FieldBase) is than bound to ModelView which performs validation.
to accomplish this task I've used this solution. It uses converter, that "hides" border by converting (Validation.Errors).CurrentItem to Thickness.
<Grid>
<Grid.Resources>
<data:ValidationBorderConverter
x:Key="ValidationBorderConverter" />
</Grid.Resources>
<Border
BorderBrush="#ff0000"
BorderThickness="{Binding
ElementName=myControl,
Path=(Validation.Errors).CurrentItem,
onverter={StaticResource ValidationBorderConverter}}">
<TextBox
ToolTip="{Binding
ElementName=myControl,
Path=(Validation.Errors).CurrentItem.ErrorContent}" />
</Border>
</Grid>
ValidationBorderConverter class is pretty simple:
[ValueConversion(typeof(object), typeof(ValidationError))]
public sealed class ValidationBorderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return (value == null) ? new Thickness(0) : new Thickness(1);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Resources