wpf specify multiple DataBindings in Groupbox IsEnabled Property - wpf

I have a GroupBox whose IsEnabled Property is set via a property on the ViewModel as under:-
<GroupBox>
<Canvas IsEnabled="{Binding CurrentRec.Current_Selected_Category.NoBonus,Converter={StaticResource TFC}}">
<Label Content="Amount:" Width="55" Canvas.Left="9" Canvas.Top="-2"/>
<TextBox x:Name="txtBonusAmount" Width="76" Canvas.Left="12" Canvas.Top="20" Text="Some text"/>
<Label Content="Bonus:" Canvas.Top="38" Width="54" Canvas.Left="10"/>
<TextBox x:Name="txtBonus" Width="76" Canvas.Left="13" Canvas.Top="58" Text="Some Text"/>
</Canvas>
<Groupbox>
There are more than one properties in my viewmodel affecting the IsEnabled property of Canvas.How do i specify those additional properties against the IsEnabled property of Canvas?

Use a MultiBinding with a converter:
<GroupBox>
<GroupBox.Resources>
<local:MultiConverter x:Key="conv" />
</GroupBox.Resources>
<Canvas>
<Canvas.IsEnabled>
<MultiBinding Converter="{StaticResource conv}">
<Binding Path="CurrentRec.Current_Selected_Category.NoBonus" />
<Binding Path="TheOtherProperty" />
</MultiBinding>
</Canvas.IsEnabled>
<Label Content="Amount:" Width="55" Canvas.Left="9" Canvas.Top="-2"/>
<TextBox x:Name="txtBonusAmount" Width="76" Canvas.Left="12" Canvas.Top="20" Text="Some text"/>
<Label Content="Bonus:" Canvas.Top="38" Width="54" Canvas.Left="10"/>
<TextBox x:Name="txtBonus" Width="76" Canvas.Left="13" Canvas.Top="58" Text="Some Text"/>
</Canvas>
</GroupBox>
The converter class should implement the IMultiValueConverter interface and return a bool from the Convert method:
public class MultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool noBonus = System.Convert.ToBoolean(values[0]);
bool theOtherSourceProperty = System.Convert.ToBoolean(values[1]);
//..
return noBonus && theOtherSourceProperty;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}

Related

WPFLocalizationExtension with ItemTemplate

I'm using WPFLocalizationExtension for my WPF app.
I have one ComboBox for languages selection. Item source is an ObservableCollection<KeyValuePair<string, string>> as below:
TITLE_LANGUAGE_ENGLISH : en
TITLE_LANGUAGE_VIETNAMESE: vi-VN
This is my xaml code:
<TextBlock Text="{lex:Loc TITLE_LANGUAGE}"></TextBlock>
<ComboBox Grid.Column="1"
ItemsSource="{Binding AvailableLanguages}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{lex:Loc Key={Binding Key}}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
When I run the application, it throws me an exeption as below:
A 'Binding' cannot be set on the 'Key' property of type 'LocExtension'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject
How can I translate the ItemTemplate ?
Thank you,
You could use an IMultiValueConverter together with a MultiBinding, so that you don't loose the ability to update the localization on-the-fly.
<ComboBox ItemsSource="{Binding AvailableLanguages}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding>
<MultiBinding.Bindings>
<Binding Path="Key" Mode="OneTime"/>
<Binding Path="Culture" Source="{x:Static lex:LocalizeDictionary.Instance}"/>
</MultiBinding.Bindings>
<MultiBinding.Converter>
<l:TranslateMultiConverter/>
</MultiBinding.Converter>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
And here is the converter:
class TranslateMultiConverter : DependencyObject, IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2)
{
var key = values[0] as string;
if (key == null)
{
return DependencyProperty.UnsetValue;
}
var cultureInfo = (values[1] as CultureInfo) ?? culture;
return LocalizeDictionary.Instance.GetLocalizedObject(key, this, cultureInfo);
}
return values.FirstOrDefault();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The LocalizeDictionary will raise a PropertyChanged event when the app's language will change causing the MultiBinding to refresh the values.
Note that the converter is a DependencyObject too. This is to provide the context to the LocalizeDictionary when calling the GetLocalizedObject method.
you have to bind to the Path Key directly. The TextBlock at DataTemplate points directly to a single KeyValuePair object, that you can access the property Key directly.
<TextBlock Text="{lex:Loc TITLE_LANGUAGE}"></TextBlock>
<ComboBox Grid.Column="1"
ItemsSource="{Binding AvailableLanguages}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Key}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Update:
Maybe you have to add a Converter. Try WPFLocalizeExtension.TypeConverters.DefaultConverter or implement a class deriving from IValueConverter by yourself.
<ComboBox.Resources>
<cv:DefaultConverter x:Key="DConv" />
</ComboBox.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Key, Converter={StaticResource DConv}}" />
</DataTemplate>
</ComboBox.ItemTemplate>

Add value ticks into my Circular Slider

This is my Circular slider:
<Slider Name="knobSlider" Minimum="0" Maximum="50" Value="1" Height="99" Width="75"
HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1">
<Slider.Template>
<ControlTemplate>
<Viewbox>
<Canvas Width="300" Height="300" Margin="5">
<Ellipse Fill="Transparent" Width="300" Height="300" Canvas.Left="0" Canvas.Top="0"
Stroke="#FF878889" StrokeThickness="10"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp"
MouseMove="Ellipse_MouseMove"/>
<Ellipse Fill="Transparent" Width="60" Height="60" Canvas.Left="120" Canvas.Top="120"/>
<Canvas>
<Line Stroke="Transparent" StrokeThickness="5" X1="150" Y1="150" X2="150" Y2="10"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp"/>
<Ellipse Fill="White" Width="30" Height="30" Canvas.Left="140" Canvas.Top="0"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
<Ellipse.ToolTip>
<ToolTip>
<Binding RelativeSource="{RelativeSource TemplatedParent}"
Path="Value" Converter="{StaticResource valueTextConverter}"/>
</ToolTip>
</Ellipse.ToolTip>
</Ellipse>
<Canvas.RenderTransform>
<RotateTransform CenterX="150" CenterY="150">
<RotateTransform.Angle>
<MultiBinding Converter="{StaticResource valueAngleConverter}">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
</MultiBinding>
</RotateTransform.Angle>
</RotateTransform>
</Canvas.RenderTransform>
</Canvas>
</Canvas>
</Viewbox>
</ControlTemplate>
</Slider.Template>
</Slider>
public class ValueAngleConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
double value = (double)values[0];
double minimum = (double)values[1];
double maximum = (double)values[2];
return MyHelper.GetAngle(value, maximum, minimum);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
public class ValueTextConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
double v = (double)value;
return String.Format("{0:F2}", v);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
And the results:
Is it possible to change the look of this Circular Slider to something similar to this one:
And add value tick and show the current value of this controller ad the button of this control like in the example instead of put a textBlock inside the Circle ?

Bind a formula to a TextBox

I'm doing a little program that needs to calculate the thickness of a book using its page count.
Please note that I'm almost completely new to programing. And this is my first time on ths website.
Here's the XAML.
<StackPanel VerticalAlignment="Center" Margin="25 5 0 10">
<Slider Maximum="800" TickPlacement="BottomRight" TickFrequency="1"
IsSnapToTickEnabled="True" DockPanel.Dock="Right" x:Name="slNumPages"
Margin="0" LargeChange="16" SmallChange="2" Value="200" Minimum="16"
BorderThickness="0" />
<WrapPanel>
<TextBox Text="{Binding ElementName=slNumPages, Path=Value,
UpdateSourceTrigger=PropertyChanged}" Width="40" />
<TextBlock Text="Approx. thickness: " />
<TextBlock x:Name="tbApproxThickness" Text="..."/>
</WrapPanel>
How can I bind the TextBlock tbApproxThickness to a formula where the value of slider slNumPages gets multiplied by constant 0.0252?
here you go
<StackPanel VerticalAlignment="Center"
Margin="25 5 0 10"
xmlns:l="clr-namespace:CSharpWPF">
<StackPanel.Resources>
<l:ApproxThicknessConverter x:Key="ApproxThicknessConverter" />
</StackPanel.Resources>
<Slider Maximum="800"
TickPlacement="BottomRight"
TickFrequency="1"
IsSnapToTickEnabled="True"
DockPanel.Dock="Right"
x:Name="slNumPages"
Margin="0"
LargeChange="16"
SmallChange="2"
Value="200"
Minimum="16"
BorderThickness="0" />
<WrapPanel>
<TextBox Text="{Binding ElementName=slNumPages, Path=Value,
UpdateSourceTrigger=PropertyChanged}"
Width="40" />
<TextBlock Text="Approx. thickness: " />
<TextBlock x:Name="tbApproxThickness"
Text="{Binding Value,ElementName=slNumPages,Converter={StaticResource ApproxThicknessConverter}}" />
</WrapPanel>
</StackPanel>
following are the changed for the same
<l:ApproxThicknessConverter x:Key="ApproxThicknessConverter" />
Text="{Binding Value,ElementName=slNumPages,Converter={StaticResource ApproxThicknessConverter}}"
converter class
namespace CSharpWPF
{
class ApproxThicknessConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value * 0.0252;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
You may need to refer to the Data Binding Overview page on MSDN to understand this answer. One simple solution would be to data bind a double property to the Slider.Value property and then reference this property in a formula property that does the calculation. Try something like this:
public double SliderValue
{
get { return sliderValue; }
set
{
sliderValue = value;
NotifyPropertyChanged("SliderValue"); // Implement INotifyPropertyChanged
FormulaValue = sliderValue * 0.0252;
}
}
public double FormulaValue { get; set; } // Implement INotifyPropertyChanged
...
<Slider Maximum="800" TickPlacement="BottomRight" TickFrequency="1"
IsSnapToTickEnabled="True" DockPanel.Dock="Right" x:Name="slNumPages"
Margin="0" LargeChange="16" SmallChange="2" Value="{Binding SliderValue}"
Minimum="16" BorderThickness="0" />
<WrapPanel>
<TextBox Text="{Binding ElementName=slNumPages, Path=Value,
UpdateSourceTrigger=PropertyChanged}" Width="40" />
<TextBlock Text="Approx. thickness: " />
<TextBlock x:Name="tbApproxThickness" Text="{Binding FormulaValue}" />
</WrapPanel>
Please bear in mind that you will need to implement the INotifyPropertyChanged Interface on these properties to make this work. You will also need to set the DataContext of the Window properly. Having done that, each time the Slider is moved, the property will automatically update the FormulaValue.

Always getting DependencyProperty.unsetvalue

So am testing multibinding in wpf and i have three text boxes which should get the year,month,day and my converter class should return a date with those inputs..pretty simple.
But in my convert method the values[0] is always unset that is i am always getting Dependencyproperty.UnsetValue even if get give it an initial value.
XAML
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:src="clr-namespace:WpfApplication2"
Title="MultiBinding Demo" Width="200" Height="200">
<Window.Resources>
<src:DateConverter x:Key="myConverter" />
</Window.Resources>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
</StackPanel.Resources>
<TextBox Name="tb1" Margin="10" Width="Auto" Height="20"></TextBox>
<TextBox Name="tb2" Margin="10" Width="20" Height="20" ></TextBox>
<TextBox Name="tb3" Width="20" Height="20" ></TextBox>
<Label Name="Date" Width="50" Height="25" Margin="5" >
<Label.Content>
<MultiBinding Converter="{StaticResource myConverter}" Mode="OneWay">
<Binding ElementName="tbl" Path="Text" />
<Binding ElementName="tb2" Path="Text" />
<Binding ElementName="tb3" Path="Text" />
</MultiBinding>
</Label.Content>
</Label>
</StackPanel>
DATECONVERTER CLASS
class DateConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue || values[2] == DependencyProperty.UnsetValue)
{
return "";
}
else
{
int year = (int)values[0];
int month = (int)values[1];
int day = (int)values[2];
DateTime date = new DateTime(year, month, day);
return date.ToShortDateString();
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I'm looking at your XAML, and it looks like your first TextBox is named tb1 (number 1) but in the binding you're referencing element name tbl (letter L).

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? :)

Resources